text: /**************************************************************
   * 
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   * 
   *************************************************************/
  
  
  
  
  // MARKER(update_precomp.py): autogen include statement, do not remove
  #include "precompiled_sw.hxx"
  
  #include <com/sun/star/chart2/XChartDocument.hpp>
  #include <hintids.hxx>
  #include <editeng/lrspitem.hxx>
  #include <editeng/brkitem.hxx>
  #include <editeng/protitem.hxx>
  #include <editeng/boxitem.hxx>
  #include <editeng/shaditem.hxx>
  #include <fmtfsize.hxx>
  #include <fmtornt.hxx>
  #include <fmtfordr.hxx>
  #include <fmtpdsc.hxx>
  #include <fmtanchr.hxx>
  #include <fmtlsplt.hxx>
  #include <frmatr.hxx>
  #include <charatr.hxx>
  #include <cellfrm.hxx>
  #include <pagefrm.hxx>
  #include <tabcol.hxx>
  #include <doc.hxx>
  #include <IDocumentUndoRedo.hxx>
  #include <UndoManager.hxx>
  #include <cntfrm.hxx>
  #include <pam.hxx>
  #include <swcrsr.hxx>
  #include <viscrs.hxx>
  #include <swtable.hxx>
  #include <ndtxt.hxx>
  #include <swundo.hxx>
  #include <tblsel.hxx>
  #include <fldbas.hxx>
  #include <poolfmt.hxx>
  #include <tabfrm.hxx>
  #include <UndoCore.hxx>
  #include <UndoRedline.hxx>
  #include <UndoDelete.hxx>
  #include <UndoTable.hxx>
  #include <hints.hxx>
  #include <tblafmt.hxx>
  #include <swcache.hxx>
  #include <ddefld.hxx>
  #include <frminf.hxx>
  #include <cellatr.hxx>
  #include <swtblfmt.hxx>
  #include <swddetbl.hxx>
  #include <mvsave.hxx>
  #include <docary.hxx>
  #include <redline.hxx>
  #include <rolbck.hxx>
  #include <tblrwcl.hxx>
  #include <editsh.hxx>
  #include <txtfrm.hxx>
  #include <ftnfrm.hxx>
  #include <section.hxx>
  #include <frmtool.hxx>
  #include <node2lay.hxx>
  #include <comcore.hrc>
  #include "docsh.hxx"
  #include <tabcol.hxx>
  #include <unochart.hxx>
  #include <node.hxx>
  #include <ndtxt.hxx>
  #include <map>
  #include <algorithm>
  #include <rootfrm.hxx>
  #include <fldupde.hxx>
  #include <switerator.hxx>
  
  #ifndef DBG_UTIL
  #define CHECK_TABLE(t)
  #else
  #ifdef DEBUG
  #define CHECK_TABLE(t) (t).CheckConsistency();
  #else
  #define CHECK_TABLE(t)
  #endif
  #endif
  
  
  using namespace ::com::sun::star;
  
  // #i17764# delete table redlines when modifying the table structure?
  // #define DEL_TABLE_REDLINES 1
  
  const sal_Unicode T2T_PARA = 0x0a;
  
  extern void ClearFEShellTabCols();
  
  // steht im gctable.cxx
  extern sal_Bool lcl_GC_Line_Border( const SwTableLine*& , void* pPara );
  
  #ifdef DEL_TABLE_REDLINES
  class lcl_DelRedlines
  {
  	SwDoc* pDoc;
  public:
  	lcl_DelRedlines( const SwTableNode& rNd, sal_Bool bCheckForOwnRedline );
  	lcl_DelRedlines( SwPaM& rPam );
  
      ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); }
  };
  
  lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() )
  {
      pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
  	if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
  		pDoc->AcceptRedline( rPam, true );
  }
  #endif
  
  void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, sal_uInt8 nId )
  {
  	sal_Bool bTop = sal_False, bBottom = sal_False, bLeft = sal_False, bRight = sal_False;
  	switch ( nId )
  	{
  	case 0:	bTop = bBottom = bLeft = sal_True; 			break;
  	case 1:	bTop = bBottom = bLeft = bRight = sal_True;	break;
  	case 2:	bBottom = bLeft = sal_True; 				break;
  	case 3: bBottom = bLeft = bRight = sal_True; 		break;
  	}
  
      const sal_Bool bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE);
  	Color aCol( bHTML ? COL_GRAY : COL_BLACK );
  	SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
  	if ( bHTML )
  	{
  		aLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
  		aLine.SetInWidth ( DEF_DOUBLE_LINE7_IN  );
  		aLine.SetDistance( DEF_DOUBLE_LINE7_DIST);
  	}
      SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 );
  	if ( bTop )
  		aBox.SetLine( &aLine, BOX_LINE_TOP );
  	if ( bBottom )
  		aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
  	if ( bLeft )
  		aBox.SetLine( &aLine, BOX_LINE_LEFT );
  	if ( bRight )
  		aBox.SetLine( &aLine, BOX_LINE_RIGHT );
      rFmt.SetFmtAttr( aBox );
  }
  
  void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, sal_uInt8 nId,
  							const SwTableAutoFmt* pAutoFmt = 0 )
  {
  	SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ];
  	if( !pArr )
  	{
  		pArr = new SvPtrarr;
  		rBoxFmtArr.Replace( pArr, nId );
  	}
  
  	SwTableBoxFmt* pNewBoxFmt = 0;
  	SwFrmFmt* pBoxFmt = rBox.GetFrmFmt();
  	for( sal_uInt16 n = 0; n < pArr->Count(); n += 2 )
  		if( pArr->GetObject( n ) == pBoxFmt )
  		{
  			pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 );
  			break;
  		}
  
  	if( !pNewBoxFmt )
  	{
  		SwDoc* pDoc = pBoxFmt->GetDoc();
  		// das Format ist also nicht vorhanden, also neu erzeugen
  		pNewBoxFmt = pDoc->MakeTableBoxFmt();
          pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) );
  
  		if( pAutoFmt )
  			pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(),
  									SwTableAutoFmt::UPDATE_BOX,
  									pDoc->GetNumberFormatter( sal_True ) );
  		else
  			::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId );
  
  		void* p = pBoxFmt;
  		pArr->Insert( p, pArr->Count() );
  		p = pNewBoxFmt;
  		pArr->Insert( p, pArr->Count() );
  	}
  	rBox.ChgFrmFmt( pNewBoxFmt );
  }
  
  SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
  									sal_uInt16 nCols, sal_uInt8 nId )
  {
  	if ( !rBoxFmtArr[nId] )
  	{
  		SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
  		if( USHRT_MAX != nCols )
              pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
  											USHRT_MAX / nCols, 0 ));
  		::lcl_SetDfltBoxAttr( *pBoxFmt, nId );
  		rBoxFmtArr.Replace( pBoxFmt, nId );
  	}
  	return (SwTableBoxFmt*)rBoxFmtArr[nId];
  }
  
  SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
  									const SwTableAutoFmt& rAutoFmt,
  									sal_uInt16 nCols, sal_uInt8 nId )
  {
  	if( !rBoxFmtArr[nId] )
  	{
  		SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
  		rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(),
  								SwTableAutoFmt::UPDATE_BOX,
  								rDoc.GetNumberFormatter( sal_True ) );
  		if( USHRT_MAX != nCols )
              pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
  											USHRT_MAX / nCols, 0 ));
  		rBoxFmtArr.Replace( pBoxFmt, nId );
  	}
  	return (SwTableBoxFmt*)rBoxFmtArr[nId];
  }
  
  SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx)
  {
  	SwTableNode* pTableNd = 0;
  	sal_uLong nIndex = rIdx.GetIndex();
  	do {
  		SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode();
  		if( 0 != ( pTableNd = pNd->GetTableNode() ) )
  			break;
  
  		nIndex = pNd->GetIndex();
  	} while ( nIndex );
  	return pTableNd;
  }
  
  
  // --------------- einfuegen einer neuen Box --------------
  
  	// fuege in der Line, vor der InsPos eine neue Box ein.
  
  sal_Bool SwNodes::InsBoxen( SwTableNode* pTblNd,
  						SwTableLine* pLine,
  						SwTableBoxFmt* pBoxFmt,
  						SwTxtFmtColl* pTxtColl,
                          const SfxItemSet* pAutoAttr,
  						sal_uInt16 nInsPos,
  						sal_uInt16 nCnt )
  {
      if( !nCnt )
  		return sal_False;
  	ASSERT( pLine, "keine gueltige Zeile" );
  
  	// Index hinter die letzte Box der Line
  	sal_uLong nIdxPos = 0;
  	SwTableBox *pPrvBox = 0, *pNxtBox = 0;
  	if( pLine->GetTabBoxes().Count() )
  	{
  		if( nInsPos < pLine->GetTabBoxes().Count() )
  		{
  			if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(),
  							pLine->GetTabBoxes()[ nInsPos ] )))
  				pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
  		}
  		else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable(),
  							pLine->GetTabBoxes()[ nInsPos-1 ] )))
  				pNxtBox = pLine->FindNextBox( pTblNd->GetTable() );
  	}
  	else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() )))
  		pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
  
  	if( !pPrvBox && !pNxtBox )
  	{
  		sal_Bool bSetIdxPos = sal_True;
  		if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos )
  		{
  			const SwTableLine* pTblLn = pLine;
  			while( pTblLn->GetUpper() )
  				pTblLn = pTblLn->GetUpper()->GetUpper();
  
  			if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn )
  			{
  				// also vor die erste Box der Tabelle
  				while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() )
  					pLine = pNxtBox->GetTabLines()[0];
  				nIdxPos = pNxtBox->GetSttIdx();
  				bSetIdxPos = sal_False;
  			}
  		}
  		if( bSetIdxPos )
  			// Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende
  			nIdxPos = pTblNd->EndOfSectionIndex();
  	}
  	else if( pNxtBox )			// es gibt einen Nachfolger
  		nIdxPos = pNxtBox->GetSttIdx();
  	else						// es gibt einen Vorgaenger
  		nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
  
  	SwNodeIndex aEndIdx( *this, nIdxPos );
  	for( sal_uInt16 n = 0; n < nCnt; ++n )
  	{
  		SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE,
  												SwTableBoxStartNode );
  		pSttNd->pStartOfSection = pTblNd;
  		new SwEndNode( aEndIdx, *pSttNd );
  
  		pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
  
          SwTableBoxes & rTabBoxes = pLine->GetTabBoxes();
          sal_uInt16 nRealInsPos = nInsPos + n;        
          if (nRealInsPos > rTabBoxes.Count())
              nRealInsPos = rTabBoxes.Count();
  
          rTabBoxes.C40_INSERT( SwTableBox, pPrvBox, nRealInsPos );
  
  		//if( NO_NUMBERING == pTxtColl->GetOutlineLevel()//#outline level,zhaojianwei
  		if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei
  //FEATURE::CONDCOLL
  			&& RES_CONDTXTFMTCOLL != pTxtColl->Which()
  //FEATURE::CONDCOLL
  		)
  			new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
  								pTxtColl, pAutoAttr );
  		else
  		{
  			// Outline-Numerierung richtig behandeln !!!
  			SwTxtNode* pTNd = new SwTxtNode(
  							SwNodeIndex( *pSttNd->EndOfSectionNode() ),
  							(SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(),
  							pAutoAttr );
  			pTNd->ChgFmtColl( pTxtColl );
  		}
  	}
  	return sal_True;
  }
  
  // --------------- einfuegen einer neuen Tabelle --------------
  
  const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts,
                                     const SwPosition& rPos, sal_uInt16 nRows,
                                     sal_uInt16 nCols, sal_Int16 eAdjust,
                                     const SwTableAutoFmt* pTAFmt,
                                     const SvUShorts* pColArr,
                                     sal_Bool bCalledFromShell,
                                     sal_Bool bNewModel )
  {
      ASSERT( nRows, "Tabelle ohne Zeile?" );
      ASSERT( nCols, "Tabelle ohne Spalten?" );
  
      {
          // nicht in Fussnoten kopieren !!
          if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
              rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
              return 0;
  
          // sollte das ColumnArray die falsche Anzahl haben wird es ignoriert!
          if( pColArr &&
              (nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() )
              pColArr = 0;
      }
  
      String aTblName = GetUniqueTblName();
  
      if( GetIDocumentUndoRedo().DoesUndo() )
      {
          GetIDocumentUndoRedo().AppendUndo(
              new SwUndoInsTbl( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust),
                                        rInsTblOpts, pTAFmt, pColArr,
                                        aTblName));
      }
  
      // fuege erstmal die Nodes ein
      // hole das Auto-Format fuer die Tabelle
      SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ),
                   *pHeadColl = pBodyColl;
  
      sal_Bool bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER );
  
      if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) )
          pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN );
  
      const sal_uInt16 nRowsToRepeat =
              tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
              rInsTblOpts.mnRowsToRepeat :
              0;
  
      /* #106283# Save content node to extract FRAMEDIR from. */
      const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode();
  
      /* #109161# If we are called from a shell pass the attrset from
          pCntntNd (aka the node the table is inserted at) thus causing
          SwNodes::InsertTable to propagate an adjust item if
          necessary. */
      SwTableNode *pTblNd = GetNodes().InsertTable(
          rPos.nNode,
          nCols,
          pBodyColl,
          nRows,
          nRowsToRepeat,
          pHeadColl,
          bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 );
  
      // dann erstelle die Box/Line/Table-Struktur
      SwTableLineFmt* pLineFmt = MakeTableLineFmt();
      SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() );
  
      /* #106283# If the node to insert the table at is a context node and has a
         non-default FRAMEDIR propagate it to the table. */
      if (pCntntNd)
      {
          const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet();
          const SfxPoolItem *pItem = NULL;
  
          if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
              && pItem != NULL)
          {
              pTableFmt->SetFmtAttr( *pItem );
          }
      }
  
      //Orientation am Fmt der Table setzen
      pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
      // alle Zeilen haben die Fill-Order von links nach rechts !
      pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
  
      // die Tabelle bekommt USHRT_MAX als default SSize
      SwTwips nWidth = USHRT_MAX;
      if( pColArr )
      {
          sal_uInt16 nSttPos = (*pColArr)[ 0 ];
          sal_uInt16 nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-1)];
          if( text::HoriOrientation::NONE == eAdjust )
          {
              sal_uInt16 nFrmWidth = nLastPos;
              nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-2)];
              pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
          }
          nWidth = nLastPos - nSttPos;
      }
      else if( nCols )
      {
          nWidth /= nCols;
          nWidth *= nCols; // to avoid rounding problems
      }
      pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
      if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
          pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
  
      // verschiebe ggfs. die harten PageDesc/PageBreak Attribute:
      SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]
                              ->GetCntntNode();
      if( pNextNd && pNextNd->HasSwAttrSet() )
      {
          const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
          const SfxPoolItem *pItem;
          if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, sal_False,
              &pItem ) )
          {
              pTableFmt->SetFmtAttr( *pItem );
              pNextNd->ResetAttr( RES_PAGEDESC );
              pNdSet = pNextNd->GetpSwAttrSet();
          }
          if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_False,
               &pItem ) )
          {
              pTableFmt->SetFmtAttr( *pItem );
              pNextNd->ResetAttr( RES_BREAK );
          }
      }
  
      SwTable * pNdTbl = &pTblNd->GetTable();
      pNdTbl->RegisterToFormat( *pTableFmt );
  
      pNdTbl->SetRowsToRepeat( nRowsToRepeat );
      pNdTbl->SetTableModel( bNewModel );
  
      SvPtrarr aBoxFmtArr( 0, 16 );
      SwTableBoxFmt* pBoxFmt = 0;
      if( !bDfltBorders && !pTAFmt )
      {
          pBoxFmt = MakeTableBoxFmt();
          pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 ));
      }
      else
      {
          const sal_uInt16 nBoxArrLen = pTAFmt ? 16 : 4;
          for( sal_uInt16 i = 0; i < nBoxArrLen; ++i )
              aBoxFmtArr.Insert( (void*)0, i );
      }
      // --> OD 2008-02-25 #refactorlists#
  //    SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
      SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
      // <--
  
      SwNodeIndex aNdIdx( *pTblNd, 1 );   // auf den ersten Box-StartNode
      SwTableLines& rLines = pNdTbl->GetTabLines();
      for( sal_uInt16 n = 0; n < nRows; ++n )
      {
          SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 );
          rLines.C40_INSERT( SwTableLine, pLine, n );
          SwTableBoxes& rBoxes = pLine->GetTabBoxes();
          for( sal_uInt16 i = 0; i < nCols; ++i )
          {
              SwTableBoxFmt *pBoxF;
              if( pTAFmt )
              {
                  sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
                                          ? 12 : (4 * (1 + ((n-1) & 1 )))));
                  nId = nId + static_cast<sal_uInt8>( !i ? 0 :
                              ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
                  pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt,
                                                  nCols, nId );
  
                  // ggfs. noch die Absatz/ZeichenAttribute setzen
                  if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
                  {
                      aCharSet.ClearItem();
                      pTAFmt->UpdateToSet( nId, aCharSet,
                                          SwTableAutoFmt::UPDATE_CHAR, 0 );
                      if( aCharSet.Count() )
                          GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()->
                              SetAttr( aCharSet );
                  }
              }
              else if( bDfltBorders )
              {
                  sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
                  pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId);
              }
              else
                  pBoxF = pBoxFmt;
  
              // fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle
              // werden gleich die Spalten gesetzt. Im Array stehen die
              // Positionen der Spalten!! (nicht deren Breite!)
              if( pColArr )
              {
                  nWidth = (*pColArr)[ sal_uInt16(i + 1) ] - (*pColArr)[ i ];
                  if( pBoxF->GetFrmSize().GetWidth() != nWidth )
                  {
                      if( pBoxF->GetDepends() )       // neues Format erzeugen!
                      {
                          SwTableBoxFmt *pNewFmt = MakeTableBoxFmt();
                          *pNewFmt = *pBoxF;
                          pBoxF = pNewFmt;
                      }
                      pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
                  }
              }
  
              SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
              rBoxes.C40_INSERT( SwTableBox, pBox, i );
              aNdIdx += 3;        // StartNode, TextNode, EndNode  == 3 Nodes
          }
      }
      // und Frms einfuegen.
      GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
      pTblNd->MakeFrms( &aNdIdx );
  
      if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
      {
          SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 );
          if( IsRedlineOn() )
              AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
          else
              SplitRedline( aPam );
      }
  
      SetModified();
      CHECK_TABLE( *pNdTbl );
      return pNdTbl;
  }
  
  SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx,
                                     sal_uInt16 nBoxes,
                                     SwTxtFmtColl* pCntntTxtColl,
                                     sal_uInt16 nLines,
                                     sal_uInt16 nRepeat,
  								   SwTxtFmtColl* pHeadlineTxtColl,
                                     const SwAttrSet * pAttrSet)
  {
  	if( !nBoxes )
  		return 0;
  
  	// wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
  	if( !pHeadlineTxtColl || !nLines )
  		pHeadlineTxtColl = pCntntTxtColl;
  
  	SwTableNode * pTblNd = new SwTableNode( rNdIdx );
  	SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd );
  
  	if( !nLines )		// fuer die FOR-Schleife
  		++nLines;
  
  	SwNodeIndex aIdx( *pEndNd );
  	SwTxtFmtColl* pTxtColl = pHeadlineTxtColl;
  	for( sal_uInt16 nL = 0; nL < nLines; ++nL )
  	{
  		for( sal_uInt16 nB = 0; nB < nBoxes; ++nB )
  		{
  			SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE,
  													SwTableBoxStartNode );
  			pSttNd->pStartOfSection = pTblNd;
  
  			SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl );
  
              // --> FME 2006-04-13 #i60422# Propagate some more attributes.
              // Adjustment was done for #109161#
              const SfxPoolItem* pItem = NULL;
              if ( NULL != pAttrSet )
              {
                  static const sal_uInt16 aPropagateItems[] = {
                      RES_PARATR_ADJUST,
                      RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
                      RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
                      RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 };
  
                  const sal_uInt16* pIdx = aPropagateItems;
                  while ( *pIdx != 0 )
                  {
                      if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
                           SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, sal_True, &pItem ) )
                          static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem);
                      ++pIdx;
                  }
              }
              // <--
  
  			new SwEndNode( aIdx, *pSttNd );
  		}
  		if ( nL + 1 >= nRepeat )
              pTxtColl = pCntntTxtColl;
  	}
  	return pTblNd;
  }
  
  
  //---------------- Text -> Tabelle -----------------------
  
  const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts,
                                     const SwPaM& rRange, sal_Unicode cCh,
                                     sal_Int16 eAdjust,
                                     const SwTableAutoFmt* pTAFmt )
  {
  	// pruefe ob in der Selection eine Tabelle liegt
  	const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
  	{
  		sal_uLong nCnt = pStt->nNode.GetIndex();
  		for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
  			if( !GetNodes()[ nCnt ]->IsTxtNode() )
  				return 0;
  	}
  
  	/* #106283# Save first node in the selection if it is a context node. */
  	SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode();
  
  	SwPaM aOriginal( *pStt, *pEnd );
  	pStt = aOriginal.GetMark();
  	pEnd = aOriginal.GetPoint();
  
  #ifdef DEL_TABLE_REDLINES
  	lcl_DelRedlines aDelRedl( aOriginal );
  #endif
  
  	SwUndoTxtToTbl* pUndo = 0;
      if( GetIDocumentUndoRedo().DoesUndo() )
      {
          GetIDocumentUndoRedo().StartUndo( UNDO_TEXTTOTABLE, NULL );
          pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh,
                      static_cast<sal_uInt16>(eAdjust), pTAFmt );
          GetIDocumentUndoRedo().AppendUndo( pUndo );
  
  		// das Splitten vom TextNode nicht in die Undohistory aufnehmen
          GetIDocumentUndoRedo().DoUndo( false );
      }
  
  	::PaMCorrAbs( aOriginal, *pEnd );
  
  	// sorge dafuer, das der Bereich auf Node-Grenzen liegt
  	SwNodeRange aRg( pStt->nNode, pEnd->nNode );
  	if( pStt->nContent.GetIndex() )
  		SplitNode( *pStt, false );
  
  	sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
  	// nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
  	if( bEndCntnt )
  	{
  		if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
  			|| pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
  		{
  			SplitNode( *pEnd, false );
  			((SwNodeIndex&)pEnd->nNode)--;
  			((SwIndex&)pEnd->nContent).Assign(
  								pEnd->nNode.GetNode().GetCntntNode(), 0 );
  			// ein Node und am Ende ??
  			if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
  				aRg.aStart--;
  		}
  		else
  			aRg.aEnd++;
  	}
  
  
  	if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
  	{
  		ASSERT( sal_False, "Kein Bereich" );
  		aRg.aEnd++;
  	}
  
  	// Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
  	SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
  
      GetIDocumentUndoRedo().DoUndo( 0 != pUndo );
  
  	// dann erstelle die Box/Line/Table-Struktur
  	SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
  	SwTableLineFmt* pLineFmt = MakeTableLineFmt();
  	SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
  
  	// alle Zeilen haben die Fill-Order von links nach rechts !
      pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
  	// die Tabelle bekommt USHRT_MAX als default SSize
      pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
      if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
          pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
  
  	/* #106283# If the first node in the selection is a context node and if it
         has an item FRAMEDIR set (no default) propagate the item to the
         replacing table. */
  	if (pSttCntntNd)
  	{
  		const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
  		const SfxPoolItem *pItem = NULL;
  
  		if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
  			&& pItem != NULL)
  		{
              pTableFmt->SetFmtAttr( *pItem );
  		}
  	}
  
      SwTableNode* pTblNd = GetNodes().TextToTable(
              aRg, cCh, pTableFmt, pLineFmt, pBoxFmt,
              GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
  
  	SwTable * pNdTbl = &pTblNd->GetTable();
  	ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
  
      const sal_uInt16 nRowsToRepeat =
              tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
              rInsTblOpts.mnRowsToRepeat :
              0;
      pNdTbl->SetRowsToRepeat( nRowsToRepeat );
  
  	sal_Bool bUseBoxFmt = sal_False;
  	if( !pBoxFmt->GetDepends() )
  	{
  		// die Formate an den Boxen haben schon die richtige Size, es darf
  		// also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
  		bUseBoxFmt = sal_True;
          pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
  		delete pBoxFmt;
          eAdjust = text::HoriOrientation::NONE;
  	}
  
  	//Orientation am Fmt der Table setzen
      pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
      pNdTbl->RegisterToFormat( *pTableFmt );
  
      if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) )
  	{
  		sal_uInt8 nBoxArrLen = pTAFmt ? 16 : 4;
  		SvPtrarr aBoxFmtArr( nBoxArrLen, 0 );
  		{
  			for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
  				aBoxFmtArr.Insert( (void*)0, i );
  		}
  
          // --> OD 2008-02-25 #refactorlists#
  //        SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
          SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
          // <--
  		SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
  
          SwTableBoxFmt *pBoxF = 0;
  		SwTableLines& rLines = pNdTbl->GetTabLines();
  		sal_uInt16 nRows = rLines.Count();
  		for( sal_uInt16 n = 0; n < nRows; ++n )
  		{
  			SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
  			sal_uInt16 nCols = rBoxes.Count();
  			for( sal_uInt16 i = 0; i < nCols; ++i )
  			{
  				SwTableBox* pBox = rBoxes[ i ];
  				sal_Bool bChgSz = sal_False;
  
  				if( pTAFmt )
  				{
  					sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
  											? 12 : (4 * (1 + ((n-1) & 1 )))));
  					nId = nId + static_cast<sal_uInt8>(!i ? 0 :
                                  ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
  					if( bUseBoxFmt )
  						::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt );
  					else
  					{
  						bChgSz = 0 == aBoxFmtArr[ nId ];
  						pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr,
  												*pTAFmt, USHRT_MAX, nId );
  					}
  
  					// ggfs. noch die Absatz/ZeichenAttribute setzen
  					if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
  					{
  						aCharSet.ClearItem();
  						pTAFmt->UpdateToSet( nId, aCharSet,
  											SwTableAutoFmt::UPDATE_CHAR, 0 );
  						if( aCharSet.Count() )
  						{
  							sal_uLong nSttNd = pBox->GetSttIdx()+1;
  							sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
  							for( ; nSttNd < nEndNd; ++nSttNd )
  							{
  								SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode();
  								if( pNd )
  								{
  									if( pHistory )
  									{
  										SwRegHistory aReg( pNd, *pNd, pHistory );
  										pNd->SetAttr( aCharSet );
  									}
  									else
  										pNd->SetAttr( aCharSet );
  								}
  							}
  						}
  					}
  				}
  				else
  				{
  					sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
  					if( bUseBoxFmt )
  						::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId );
  					else
  					{
  						bChgSz = 0 == aBoxFmtArr[ nId ];
  						pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr,
  														USHRT_MAX, nId );
  					}
  				}
  
  				if( !bUseBoxFmt )
  				{
  					if( bChgSz )
                          pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() );
  					pBox->ChgFrmFmt( pBoxF );
  				}
  			}
  		}
  
  		if( bUseBoxFmt )
  		{
  			for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
  			{
  				SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ];
  				delete pArr;
  			}
  		}
  	}
  
  	// JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen
  	if( IsInsTblFormatNum() )
  	{
  		for( sal_uInt16 nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; )
  			ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], sal_False );
  	}
  
  	sal_uLong nIdx = pTblNd->GetIndex();
  	aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
  
  	{
  		SwPaM& rTmp = (SwPaM&)rRange;	// Point immer an den Anfang
  		rTmp.DeleteMark();
  		rTmp.GetPoint()->nNode = *pTblNd;
  		SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
  		rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
  	}
  
  	if( pUndo )
      {
          GetIDocumentUndoRedo().EndUndo( UNDO_TEXTTOTABLE, NULL );
      }
  
  	SetModified();
  	SetFieldsDirty(true, NULL, 0);
  	return pNdTbl;
  }
  
  SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
  									SwTableFmt* pTblFmt,
  									SwTableLineFmt* pLineFmt,
  									SwTableBoxFmt* pBoxFmt,
  									SwTxtFmtColl* pTxtColl,
  									SwUndoTxtToTbl* pUndo )
  {
  	if( rRange.aStart >= rRange.aEnd )
  		return 0;
  
  	SwTableNode * pTblNd = new SwTableNode( rRange.aStart );
  	new SwEndNode( rRange.aEnd, *pTblNd );
  
  	SwDoc* pDoc = GetDoc();
  	SvUShorts aPosArr( 0, 16 );
  	SwTable * pTable = &pTblNd->GetTable();
  	SwTableLine* pLine;
  	SwTableBox* pBox;
  	sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
  
  	SwNodeIndex aSttIdx( *pTblNd, 1 );
  	SwNodeIndex aEndIdx( rRange.aEnd, -1 );
  	for( nLines = 0, nBoxes = 0;
  		aSttIdx.GetIndex() < aEndIdx.GetIndex();
  		aSttIdx += 2, nLines++, nBoxes = 0 )
  	{
  		SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
  		ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
  
  		if( !nLines && 0x0b == cCh )
  		{
  			cCh = 0x09;
  
  			// JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen,
  			//				damit die Boxen entsprechend eingestellt werden
  			SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->getLayoutFrm( pTxtNd->GetDoc()->GetCurrentLayout() ) );
  			if( aFInfo.IsOneLine() )		// nur dann sinnvoll!
  			{
  				const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
  				for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
                  {
  					if( *pTxt == cCh )
  					{
  						aPosArr.Insert( static_cast<sal_uInt16>(
                                          aFInfo.GetCharPos( nChPos+1, sal_False )),
  										aPosArr.Count() );
  					}
                  }
  
  				aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/
                                  static_cast<sal_uInt16>(aFInfo.GetFrm()->IsVertical() ?
                                  aFInfo.GetFrm()->Prt().Bottom() :
                                  aFInfo.GetFrm()->Prt().Right()),
  								aPosArr.Count() );
  			}
  		}
  
  		// die alten Frames loeschen, es werden neue erzeugt
  		pTxtNd->DelFrms();
  
  		// PageBreaks/PageDesc/ColBreak rausschmeissen.
          const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet();
  		if( pSet )
  		{
  // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
  // erfolgen, denn sonst stehen sie falsch in der History !!!
  //			SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
  			const SfxPoolItem* pItem;
  			if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
  			{
  				if( !nLines )
                      pTblFmt->SetFmtAttr( *pItem );
                  pTxtNd->ResetAttr( RES_BREAK );
                  pSet = pTxtNd->GetpSwAttrSet();
  			}
  
  			if( pSet && SFX_ITEM_SET == pSet->GetItemState(
  				RES_PAGEDESC, sal_False, &pItem ) &&
  				((SwFmtPageDesc*)pItem)->GetPageDesc() )
  			{
  				if( !nLines )
                      pTblFmt->SetFmtAttr( *pItem );
                  pTxtNd->ResetAttr( RES_PAGEDESC );
  			}
  		}
  
  		// setze den bei allen TextNode in der Tabelle den TableNode
  		// als StartNode
  		pTxtNd->pStartOfSection = pTblNd;
  
  		pLine = new SwTableLine( pLineFmt, 1, 0 );
  		pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
  
  		SwStartNode* pSttNd;
  		SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
  
  		SvULongs aBkmkArr( 15, 15 );
  		_SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
  
  		const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
  
  		if( T2T_PARA != cCh )
  			for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
  				if( *pTxt == cCh )
  				{
  					aCntPos.nContent = nChPos;
                      SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos );
  
  					if( aBkmkArr.Count() )
  						_RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
  											nChPos + 1 );
  
  					// Trennzeichen loeschen und SuchString korrigieren
                      pTxtNd->EraseText( aCntPos.nContent, 1 );
  					pTxt = pTxtNd->GetTxt().GetBuffer();
  					nChPos = 0;
  					--nChPos, --pTxt;           // for the ++ in the for loop !!!
  
  					// setze bei allen TextNodes in der Tabelle den TableNode
  					// als StartNode
  					const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
  					pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
  												SwTableBoxStartNode );
  					new SwEndNode( aCntPos.nNode, *pSttNd );
  					pNewNd->pStartOfSection = pSttNd;
  
  					// Section der Box zuweisen
  					pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
  					pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
  				}
  
  		// und jetzt den letzten Teil-String
  		if( aBkmkArr.Count() )
  			_RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(),
  								pTxtNd->GetTxt().Len()+1 );
  
  		pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode );
  		const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
  		new SwEndNode( aTmpIdx, *pSttNd  );
  		pTxtNd->pStartOfSection = pSttNd;
  
  		pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
  		pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
  		if( nMaxBoxes < nBoxes )
  			nMaxBoxes = nBoxes;
  	}
  
  	// die Tabelle ausgleichen, leere Sections einfuegen
  	sal_uInt16 n;
  
  	for( n = 0; n < pTable->GetTabLines().Count(); ++n )
  	{
  		SwTableLine* pCurrLine = pTable->GetTabLines()[ n ];
  		if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() ))
  		{
  			InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0,
  						nBoxes, nMaxBoxes - nBoxes );
  
  			if( pUndo )
  				for( sal_uInt16 i = nBoxes; i < nMaxBoxes; ++i )
  					pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] );
  
  			// fehlen der 1. Line Boxen, dann kann man das Breiten Array
  			// vergessen!
  			if( !n )
  				aPosArr.Remove( 0, aPosArr.Count() );
  		}
  	}
  
  	if( aPosArr.Count() )
  	{
  		SwTableLines& rLns = pTable->GetTabLines();
  		sal_uInt16 nLastPos = 0;
  		for( n = 0; n < aPosArr.Count(); ++n )
  		{
  			SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
              pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
  												aPosArr[ n ] - nLastPos ));
  			for( sal_uInt16 nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine )
  				//JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
  				//				von der rufenden Methode noch gebraucht wird!
  				pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
  
  			nLastPos = aPosArr[ n ];
  		}
  
  		// damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
  		// Groesse nach "oben" transportieren.
  		ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
          pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
  	}
  	else
          pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
  
  	// das wars doch wohl ??
  	return pTblNd;
  }
  /*-- 18.05.2006 10:30:29---------------------------------------------------
  
    -----------------------------------------------------------------------*/
  const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
  {
      /* #106283# Save first node in the selection if it is a content node. */
      SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode();
  
      /**debug**/
  #if OSL_DEBUG_LEVEL > 1
      const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
      const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
      (void) rStartRange;
      (void) rEndRange;
  #endif
      /**debug**/
  
      //!!! not necessarily TextNodes !!!
      SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd );
      const SwPosition *pStt = aOriginal.GetMark();
      const SwPosition *pEnd = aOriginal.GetPoint();
  
  #ifdef DEL_TABLE_REDLINES
      lcl_DelRedlines aDelRedl( aOriginal );
  #endif
  
  //    SwUndoTxtToTbl* pUndo = 0;
      bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
      if (bUndo)
      {
          // das Splitten vom TextNode nicht in die Undohistory aufnehmen
          GetIDocumentUndoRedo().DoUndo(false);
      }
  
      ::PaMCorrAbs( aOriginal, *pEnd );
  
      // sorge dafuer, das der Bereich auf Node-Grenzen liegt
      SwNodeRange aRg( pStt->nNode, pEnd->nNode );
      if( pStt->nContent.GetIndex() )
          SplitNode( *pStt, false );
  
      sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
      // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
      if( bEndCntnt )
      {
          if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
              || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
          {
              SplitNode( *pEnd, false );
              ((SwNodeIndex&)pEnd->nNode)--;
              ((SwIndex&)pEnd->nContent).Assign(
                                  pEnd->nNode.GetNode().GetCntntNode(), 0 );
              // ein Node und am Ende ??
              if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
                  aRg.aStart--;
          }
          else
              aRg.aEnd++;
      }
  
  
      if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
      {
          ASSERT( sal_False, "Kein Bereich" );
          aRg.aEnd++;
      }
  
      // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
      SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
  
      GetIDocumentUndoRedo().DoUndo(bUndo);
  
      // dann erstelle die Box/Line/Table-Struktur
      SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
      SwTableLineFmt* pLineFmt = MakeTableLineFmt();
      SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
  
      // alle Zeilen haben die Fill-Order von links nach rechts !
      pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
      // die Tabelle bekommt USHRT_MAX als default SSize
      pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
  
      /* #106283# If the first node in the selection is a context node and if it
         has an item FRAMEDIR set (no default) propagate the item to the
         replacing table. */
      if (pSttCntntNd)
      {
          const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
          const SfxPoolItem *pItem = NULL;
  
          if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
              && pItem != NULL)
          {
              pTableFmt->SetFmtAttr( *pItem );
          }
      }
  
      SwTableNode* pTblNd = GetNodes().TextToTable(
              rTableNodes, pTableFmt, pLineFmt, pBoxFmt,
              GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ );
  
      SwTable * pNdTbl = &pTblNd->GetTable();
      ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
      pNdTbl->RegisterToFormat( *pTableFmt );
  
      sal_Bool bUseBoxFmt = sal_False;
      if( !pBoxFmt->GetDepends() )
      {
          // die Formate an den Boxen haben schon die richtige Size, es darf
          // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
          bUseBoxFmt = sal_True;
          pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
          delete pBoxFmt;
      }
  
      sal_uLong nIdx = pTblNd->GetIndex();
      aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
  
      SetModified();
      SetFieldsDirty( true, NULL, 0 );
      return pNdTbl;
  }
  
  SwNodeRange * SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange)
  {
      SwNodeRange * pResult = NULL;
      bool bChanged = false;
      
  	SwNodeIndex aNewStart = rRange.aStart;
  	SwNodeIndex aNewEnd = rRange.aEnd;
  	
  	SwNodeIndex aEndIndex = rRange.aEnd;
  	SwNodeIndex aIndex = rRange.aStart;
  	
  	while (aIndex < aEndIndex)
  	{
  		SwNode& rNode = aIndex.GetNode();
  		
  		if (rNode.IsStartNode())
  		{
              // advance aIndex to the end node of this start node
              SwNode * pEndNode = rNode.EndOfSectionNode();
              aIndex = *pEndNode;
  			
              if (aIndex > aNewEnd)
              {
                  aNewEnd = aIndex;
                  bChanged = true;
              }
  		}
  		else if (rNode.IsEndNode())
  		{
              SwNode * pStartNode = rNode.StartOfSectionNode();
  			SwNodeIndex aStartIndex = *pStartNode;
  			
  			if (aStartIndex < aNewStart)
              {
  				aNewStart = aStartIndex;
                  bChanged = true;
              }
  		}
  		
  		if (aIndex < aEndIndex)
  			++aIndex;	
  	}
      
      SwNode * pNode = &aIndex.GetNode();
      while (pNode->IsEndNode())
      {
          SwNode * pStartNode = pNode->StartOfSectionNode();
          SwNodeIndex aStartIndex(*pStartNode);
          aNewStart = aStartIndex;        
          aNewEnd = aIndex;
          bChanged = true;
          
          ++aIndex;
          pNode = &aIndex.GetNode();
      }
      
      if (bChanged)
          pResult = new SwNodeRange(aNewStart, aNewEnd);
      
      return pResult;
  }
  
  /*-- 18.05.2006 08:23:28---------------------------------------------------
  
    -----------------------------------------------------------------------*/
  SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes,
                                      SwTableFmt* pTblFmt,
                                      SwTableLineFmt* pLineFmt,
                                      SwTableBoxFmt* pBoxFmt,
                                      SwTxtFmtColl* /*pTxtColl*/  /*, SwUndo... pUndo*/  )
  {
      if( !rTableNodes.size() )
          return 0;
  
      SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
      //insert the end node after the last text node
     SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
     ++aInsertIndex;
  
     //!! owner ship will be transferred in c-tor to SwNodes array.
     //!! Thus no real problem here...
     new SwEndNode( aInsertIndex, *pTblNd );
  
  #if OSL_DEBUG_LEVEL > 1
      /**debug**/
      const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
      const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
      (void) rStartRange;
      (void) rEndRange;
      /**debug**/
  #endif
  
      SwDoc* pDoc = GetDoc();
      SvUShorts aPosArr( 0, 16 );
      SwTable * pTable = &pTblNd->GetTable();
      SwTableLine* pLine;
      SwTableBox* pBox;
      sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
  
  //    SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
  
  
      SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
      // delete frames of all contained content nodes
      for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
      {
          SwNode& rNode = aNodeIndex.GetNode();
          if( rNode.IsCntntNode() )
          {
              static_cast<SwCntntNode&>(rNode).DelFrms();
              if(rNode.IsTxtNode())
              {
                  SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode);
                  // setze den bei allen TextNode in der Tabelle den TableNode
                  // als StartNode
  // FIXME: this is setting wrong node StartOfSections in nested tables.
  //                rTxtNode.pStartOfSection = pTblNd;
                  // remove PageBreaks/PageDesc/ColBreak
                  const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet();
                  if( pSet )
                  {
          // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
          // erfolgen, denn sonst stehen sie falsch in der History !!!
          //          SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
                      const SfxPoolItem* pItem;
                      if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
                      {
                          if( !nLines )
                              pTblFmt->SetFmtAttr( *pItem );
                          rTxtNode.ResetAttr( RES_BREAK );
                          pSet = rTxtNode.GetpSwAttrSet();
                      }
  
                      if( pSet && SFX_ITEM_SET == pSet->GetItemState(
                          RES_PAGEDESC, sal_False, &pItem ) &&
                          ((SwFmtPageDesc*)pItem)->GetPageDesc() )
                      {
                          if( !nLines )
                              pTblFmt->SetFmtAttr( *pItem );
                          rTxtNode.ResetAttr( RES_PAGEDESC );
                      }
                  }
              }
          }
      }
  
  //    SwNodeIndex aSttIdx( *pTblNd, 1 );
  //    SwNodeIndex aEndIdx( rlNodes.rbegin()->aEnd, -1 );
      std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin();
      for( nLines = 0, nBoxes = 0;
          aRowIter != rTableNodes.end();
          ++aRowIter, /*aSttIdx += 2, */nLines++, nBoxes = 0 )
      {
  //        SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
  //        ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
  
          pLine = new SwTableLine( pLineFmt, 1, 0 );
          pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
  
  //        SwStartNode* pSttNd;
  //        SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
  
          std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin();
  //        SvULongs aBkmkArr( 15, 15 );
  //        _SaveCntntIdx( pDoc, aCellIter->aStart.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
  //        const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
  
          for( ; aCellIter != aRowIter->end(); ++aCellIter )
          {
  //            aCellIter->aStart aCellIter->aEnd
  //                aCntPos.nContent = nChPos;
  //                SwCntntNode* pNewNd = pTxtNd->SplitNode( aCntPos );
  
  //        auch f?rs undo?
  //                if( aBkmkArr.Count() )
  //                    _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
  //                                        nChPos + 1 );
  
                  const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 );
  
                 SwNodeIndex aCellEndIdx(aCellIter->aEnd);
                 ++aCellEndIdx;
                 SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
                                              SwTableBoxStartNode );
                  new SwEndNode( aCellEndIdx, *pSttNd );
                  //set the start node on all node of the current cell
                  SwNodeIndex aCellNodeIdx = aCellIter->aStart;
                  for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx )
                  {
                      aCellNodeIdx.GetNode().pStartOfSection = pSttNd;
                      //skip start/end node pairs
                      if( aCellNodeIdx.GetNode().IsStartNode() )
                          aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() );
                  }
  
                  // Section der Box zuweisen
                  pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
                  pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
          }
          if( nMaxBoxes < nBoxes )
              nMaxBoxes = nBoxes;
      }
  
      // die Tabelle ausgleichen, leere Sections einfuegen
      sal_uInt16 n;
  
      if( aPosArr.Count() )
      {
          SwTableLines& rLns = pTable->GetTabLines();
          sal_uInt16 nLastPos = 0;
          for( n = 0; n < aPosArr.Count(); ++n )
          {
              SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
              pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
                                                  aPosArr[ n ] - nLastPos ));
              for( sal_uInt16 nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 )
                  //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
                  //              von der rufenden Methode noch gebraucht wird!
                  pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] );
  
              nLastPos = aPosArr[ n ];
          }
  
          // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
          // Groesse nach "oben" transportieren.
          ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
          pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
      }
      else
          pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
  
      // das wars doch wohl ??
      return pTblNd;
  }
  
  
  //---------------- Tabelle -> Text -----------------------
  
  
  sal_Bool SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh )
  {
  	if( !pTblNd )
  		return sal_False;
  
      // --> FME 2004-09-28 #i34471#
      // If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted
      // the table cursor.
      SwEditShell* pESh = GetEditShell();
      if( pESh && pESh->IsTableMode() )
          pESh->ClearMark();
      // <--
  
  #ifdef DEL_TABLE_REDLINES
      lcl_DelRedlines aDelRedl( *pTblNd, sal_False );
  #endif
  
  	SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() );
  	SwUndoTblToTxt* pUndo = 0;
  	SwNodeRange* pUndoRg = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          GetIDocumentUndoRedo().ClearRedo();
  		pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
  		pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh );
  	}
  
  	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
  	aMsgHnt.eFlags = TBL_BOXNAME;
  	UpdateTblFlds( &aMsgHnt );
  
  	sal_Bool bRet = GetNodes().TableToText( aRg, cCh, pUndo );
  	if( pUndoRg )
  	{
  		pUndoRg->aStart++;
  		pUndoRg->aEnd--;
  		pUndo->SetRange( *pUndoRg );
          GetIDocumentUndoRedo().AppendUndo(pUndo);
  		delete pUndoRg;
  	}
  
  	if( bRet )
  		SetModified();
  
  	return bRet;
  }
  
  // -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder
  //		Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!)
  struct _DelTabPara
  {
  	SwTxtNode* pLastNd;
  	SwNodes& rNds;
  	SwUndoTblToTxt* pUndo;
  	sal_Unicode cCh;
  
  	_DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) :
  		pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
  	_DelTabPara( const _DelTabPara& rPara ) :
  		pLastNd(rPara.pLastNd), rNds( rPara.rNds ),
  		pUndo( rPara.pUndo ), cCh( rPara.cCh ) {}
  };
  
  // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
  // koennen.
  sal_Bool lcl_DelBox( const SwTableBox*&, void *pPara );
  
  sal_Bool lcl_DelLine( const SwTableLine*& rpLine, void* pPara )
  {
  	ASSERT( pPara, "die Parameter fehlen" );
  	_DelTabPara aPara( *(_DelTabPara*)pPara );
  	((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara );
  	if( rpLine->GetUpper() )		// gibt es noch eine uebergeordnete Box ??
  		// dann gebe den letzten TextNode zurueck
  		((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd;
  	return sal_True;
  }
  
  
  sal_Bool lcl_DelBox( const SwTableBox*& rpBox, void* pPara )
  {
  	ASSERT( pPara, "die Parameter fehlen" );
  
  	// loesche erstmal die Lines der Box
  	_DelTabPara* pDelPara = (_DelTabPara*)pPara;
  	if( rpBox->GetTabLines().Count() )
  		((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara );
  	else
  	{
  		SwDoc* pDoc = pDelPara->rNds.GetDoc();
  		SwNodeRange aDelRg( *rpBox->GetSttNd(), 0,
  							*rpBox->GetSttNd()->EndOfSectionNode() );
  		// loesche die Section
  		pDelPara->rNds.SectionUp( &aDelRg );
  		const SwTxtNode* pCurTxtNd;
  		if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd &&
  			0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() ))
  		{
  			// Join the current text node with the last from the previous box if possible
  			sal_uLong nNdIdx = aDelRg.aStart.GetIndex();
  			aDelRg.aStart--;
  			if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
  			{
                  // Inserting the seperator
                  SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len());
                  pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx,
                      IDocumentContentOperations::INS_EMPTYEXPAND );
  				if( pDelPara->pUndo )
  					pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
  												aCntIdx.GetIndex() );
  
  				SvULongs aBkmkArr( 4, 4 );
  				xub_StrLen nOldTxtLen = aCntIdx.GetIndex();
  				_SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(),
  								aBkmkArr );
  
  				pDelPara->pLastNd->JoinNext();
  
  				if( aBkmkArr.Count() )
  					_RestoreCntntIdx( pDoc, aBkmkArr,
  										pDelPara->pLastNd->GetIndex(),
  										nOldTxtLen );
  			}
  			else if( pDelPara->pUndo )
              {
                  aDelRg.aStart++;
  				pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
              }
  		}
  		else if( pDelPara->pUndo )
  			pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
  		aDelRg.aEnd--;
  		pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode();
  
  		//JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf
  		//				keinen Fall uebernehmen
          if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
  			pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
  	}
  	return sal_True;
  }
  
  
  sal_Bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
  							SwUndoTblToTxt* pUndo )
  {
  	// ist eine Tabelle selektiert ?
  	SwTableNode* pTblNd;
  	if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() ||
          0 == ( pTblNd = rRange.aStart.GetNode().GetTableNode()) ||
  		&rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() )
  		return sal_False;
  
  	// stand die Tabelle ganz alleine in einer Section ?
  	// dann ueber den Upper der Tabelle die Frames anlegen
  	SwNode2Layout* pNode2Layout = 0;
  	SwNodeIndex aFrmIdx( rRange.aStart );
  	SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() );
  	if( !pFrmNd )
  		// dann sammel mal alle Uppers ein
  		pNode2Layout = new SwNode2Layout( *pTblNd );
  
  	// loesche schon mal die Frames
  	pTblNd->DelFrms();
  
  	// dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen
  	_DelTabPara aDelPara( *this, cCh, pUndo );
  	pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara );
  
  	// jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden
  	// Trenner erzeugt worden. Es braucht nur noch die Table-Section
  	// geloescht und fuer die neuen TextNode die Frames erzeugt werden.
  	SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
  
  	// JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den
  	//				ersten TextNode uebernehmen
  	{
  // was ist mit UNDO???
  		const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet();
  		const SfxPoolItem *pBreak, *pDesc;
  		if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, sal_False, &pDesc ))
  			pDesc = 0;
  		if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, sal_False, &pBreak ))
  			pBreak = 0;
  
  		if( pBreak || pDesc )
  		{
  			SwNodeIndex aIdx( *pTblNd  );
  			SwCntntNode* pCNd = GoNext( &aIdx );
  			if( pBreak )
  				pCNd->SetAttr( *pBreak );
  			if( pDesc )
  				pCNd->SetAttr( *pDesc );
  		}
  	}
  
  	SectionUp( &aDelRg );		// loesche die Section und damit die Tabelle
      // #i28006#
      sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
  	if( !pFrmNd )
  	{
  		pNode2Layout->RestoreUpperFrms( *this,
  						aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
  		delete pNode2Layout;
  	}
  	else
  	{
  		SwCntntNode *pCNd;
  		SwSectionNode *pSNd;
  		while( aDelRg.aStart.GetIndex() < nEnd )
  		{
  			if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode()))
  			{
  				if( pFrmNd->IsCntntNode() )
  					((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
  				else if( pFrmNd->IsTableNode() )
  					((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
  				else if( pFrmNd->IsSectionNode() )
  					((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
  				pFrmNd = pCNd;
  			}
  			else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode()))
  			{
  				if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() )
  				{
  					pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd );
  					pFrmNd = pSNd;
  					break;
  				}
  				aDelRg.aStart = *pSNd->EndOfSectionNode();
  			}
  			aDelRg.aStart++;
  		}
      }
  
      // #i28006# Fly frames have to be restored even if the table was
      // #alone in the section
      const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts();
      for( sal_uInt16 n = 0; n < rFlyArr.Count(); ++n )
      {
          SwFrmFmt *const pFmt = (SwFrmFmt*)rFlyArr[n];
          const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
          SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
          if (pAPos &&
              ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
               (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
              nStt <= pAPos->nNode.GetIndex() &&
              pAPos->nNode.GetIndex() < nEnd )
          {
              pFmt->MakeFrms();
          }
  	}
  
  	return sal_True;
  }
  
  
  // ----- einfuegen von Spalten/Zeilen ------------------------
  
  sal_Bool SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
  {
  	if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
  		return sal_False;
  
  	// lasse ueber das Layout die Boxen suchen
  	SwSelBoxes aBoxes;
  	::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
  
  	sal_Bool bRet = sal_False;
  	if( aBoxes.Count() )
  		bRet = InsertCol( aBoxes, nCnt, bBehind );
  	return bRet;
  }
  
  sal_Bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
  {
  	// uebers SwDoc fuer Undo !!
  	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	SwTable& rTbl = pTblNd->GetTable();
  	if( rTbl.ISA( SwDDETable ))
  		return sal_False;
  
  #ifdef DEL_TABLE_REDLINES
  	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
  #endif
  
  	SwTableSortBoxes aTmpLst( 0, 5 );
  	SwUndoTblNdsChg* pUndo = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
  		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd,
                                       0, 0, nCnt, bBehind, sal_False );
  		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
  	}
  
      bool bRet(false);
      {
          ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
  
          SwTableFmlUpdate aMsgHnt( &rTbl );
          aMsgHnt.eFlags = TBL_BOXPTR;
          UpdateTblFlds( &aMsgHnt );
  
          bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind );
          if (bRet)
          {
              SetModified();
              ::ClearFEShellTabCols();
              SetFieldsDirty( true, NULL, 0 );
          }
      }
  
  	if( pUndo )
      {
  		if( bRet )
          {
  			pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
  			delete pUndo;
  	}
  	return bRet;
  }
  
  sal_Bool SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
  {
  	// lasse ueber das Layout die Boxen suchen
  	SwSelBoxes aBoxes;
  	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
  
  	sal_Bool bRet = sal_False;
  	if( aBoxes.Count() )
  		bRet = InsertRow( aBoxes, nCnt, bBehind );
  	return bRet;
  }
  
  sal_Bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
  {
  	// uebers SwDoc fuer Undo !!
  	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	SwTable& rTbl = pTblNd->GetTable();
  	if( rTbl.ISA( SwDDETable ))
  		return sal_False;
  
  #ifdef DEL_TABLE_REDLINES
  	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
  #endif
  
  	SwTableSortBoxes aTmpLst( 0, 5 );
  	SwUndoTblNdsChg* pUndo = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
  		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd,
  									 0, 0, nCnt, bBehind, sal_False );
  		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
  	}
  
      bool bRet(false);
      {
          ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
  
          SwTableFmlUpdate aMsgHnt( &rTbl );
          aMsgHnt.eFlags = TBL_BOXPTR;
          UpdateTblFlds( &aMsgHnt );
  
          bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind );
          if (bRet)
          {
              SetModified();
              ::ClearFEShellTabCols();
              SetFieldsDirty( true, NULL, 0 );
          }
      }
  
  	if( pUndo )
      {
  		if( bRet )
          {
  			pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
  			delete pUndo;
  	}
  	return bRet;
  
  }
  
  // ----- loeschen von Spalten/Zeilen ------------------------
  
  sal_Bool SwDoc::DeleteRow( const SwCursor& rCursor )
  {
  	// lasse ueber das Layout die Boxen suchen
  	SwSelBoxes aBoxes;
  	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
  	if( ::HasProtectedCells( aBoxes ))
  		return sal_False;
  
  	// die Crsr aus dem Loeschbereich entfernen.
  	// Der Cursor steht danach:
  	//	- es folgt noch eine Zeile, in dieser
  	//	- vorher steht noch eine Zeile, in dieser
  	//	- sonst immer dahinter
  	{
  		SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode();
  
  		if( pTblNd->GetTable().ISA( SwDDETable ))
  			return sal_False;
  
  		// suche alle Boxen / Lines
  		_FndBox aFndBox( 0, 0 );
  		{
  			_FndPara aPara( aBoxes, &aFndBox );
  			pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
  		}
  
  		if( !aFndBox.GetLines().Count() )
  			return sal_False;
  
  		SwEditShell* pESh = GetEditShell();
  		if( pESh )
  		{
  			pESh->KillPams();
  			// JP: eigentlich sollte man ueber alle Shells iterieren!!
  		}
  
  		_FndBox* pFndBox = &aFndBox;
  		while( 1 == pFndBox->GetLines().Count() &&
  				1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
  		{
  			_FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
  			if( pTmp->GetBox()->GetSttNd() )
  				break;		// das ist sonst zu weit
  			pFndBox = pTmp;
  		}
  
  		SwTableLine* pDelLine = pFndBox->GetLines()[
  						pFndBox->GetLines().Count()-1 ]->GetLine();
  		SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
  							pDelLine->GetTabBoxes().Count() - 1 ];
  		while( !pDelBox->GetSttNd() )
  		{
  			SwTableLine* pLn = pDelBox->GetTabLines()[
  						pDelBox->GetTabLines().Count()-1 ];
  			pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
  		}
  		SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
  														pDelBox, sal_True );
  		while( pNextBox &&
  				pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
  			pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
  
  		if( !pNextBox )			// keine nachfolgende? dann die vorhergehende
  		{
  			pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
  			pDelBox = pDelLine->GetTabBoxes()[ 0 ];
  			while( !pDelBox->GetSttNd() )
  				pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
  			pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
  														pDelBox, sal_True );
  			while( pNextBox &&
  					pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
  				pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
  		}
  
  		sal_uLong nIdx;
  		if( pNextBox )		// dann den Cursor hier hinein
  			nIdx = pNextBox->GetSttIdx() + 1;
  		else				// ansonsten hinter die Tabelle
  			nIdx = pTblNd->EndOfSectionIndex() + 1;
  
  		SwNodeIndex aIdx( GetNodes(), nIdx );
  		SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
  		if( !pCNd )
  			pCNd = GetNodes().GoNext( &aIdx );
  
  		if( pCNd )
  		{
  			// die Cursor von der Shell oder den uebergebenen Cursor aendern?
  			SwPaM* pPam = (SwPaM*)&rCursor;
  			pPam->GetPoint()->nNode = aIdx;
  			pPam->GetPoint()->nContent.Assign( pCNd, 0 );
  			pPam->SetMark();			// beide wollen etwas davon haben
  			pPam->DeleteMark();
  		}
  	}
  
  	// dann loesche doch die Zeilen
  
      GetIDocumentUndoRedo().StartUndo(UNDO_ROW_DELETE, NULL);
      sal_Bool bResult = DeleteRowCol( aBoxes );
      GetIDocumentUndoRedo().EndUndo(UNDO_ROW_DELETE, NULL);
  
  	return bResult;
  }
  
  sal_Bool SwDoc::DeleteCol( const SwCursor& rCursor )
  {
  	// lasse ueber das Layout die Boxen suchen
  	SwSelBoxes aBoxes;
  	GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
  	if( ::HasProtectedCells( aBoxes ))
  		return sal_False;
  
  	// die Crsr muessen noch aus dem Loesch Bereich entfernt
  	// werden. Setze sie immer hinter/auf die Tabelle; ueber die
  	// Dokument-Position werden sie dann immer an die alte Position gesetzt.
  	SwEditShell* pESh = GetEditShell();
  	if( pESh )
  	{
  		const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode();
  		pESh->ParkCrsr( SwNodeIndex( *pNd ) );
  	}
  
  	// dann loesche doch die Spalten
      GetIDocumentUndoRedo().StartUndo(UNDO_COL_DELETE, NULL);
      sal_Bool bResult = DeleteRowCol( aBoxes, true );
      GetIDocumentUndoRedo().EndUndo(UNDO_COL_DELETE, NULL);
  
  	return bResult;
  }
  
  sal_Bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
  {
  	if( ::HasProtectedCells( rBoxes ))
  		return sal_False;
  
  	// uebers SwDoc fuer Undo !!
  	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	if( pTblNd->GetTable().ISA( SwDDETable ))
  		return sal_False;
  
  	::ClearFEShellTabCols();
      SwSelBoxes aSelBoxes;
      aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
      SwTable &rTable = pTblNd->GetTable();
      long nMin = 0;
      long nMax = 0;
      if( rTable.IsNewModel() )
  	{
  		if( bColumn )
  			rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
  		else
  			rTable.FindSuperfluousRows( aSelBoxes );
  	}
  
  #ifdef DEL_TABLE_REDLINES
  	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
  #endif
  
  	// soll die gesamte Tabelle geloescht werden ??
  	const sal_uLong nTmpIdx1 = pTblNd->GetIndex();
  	const sal_uLong nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()->
  								EndOfSectionIndex()+1;
  	if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() &&
  		aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
  		nTmpIdx2 == pTblNd->EndOfSectionIndex() )
  	{
  		sal_Bool bNewTxtNd = sal_False;
  		// steht diese auch noch alleine in einem FlyFrame ?
  		SwNodeIndex aIdx( *pTblNd, -1 );
  		const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
  		if( pSttNd )
  		{
  			const sal_uLong nTblEnd = pTblNd->EndOfSectionIndex() + 1;
  			const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex();
  			if( nTblEnd == nSectEnd )
  			{
  				if( SwFlyStartNode == pSttNd->GetStartNodeType() )
  				{
  					SwFrmFmt* pFmt = pSttNd->GetFlyFmt();
  					if( pFmt )
  					{
  						// Ok, das ist das gesuchte FlyFormat
  						DelLayoutFmt( pFmt );
  						return sal_True;
  					}
  				}
  				// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
  				// TextNode ueberig lassen.
  				// Undo koennen wir dann vergessen !!
  				bNewTxtNd = sal_True;
  			}
  		}
  
  		// kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
  		// TextNode ueberig lassen.
  		aIdx++;
          if (GetIDocumentUndoRedo().DoesUndo())
          {
              GetIDocumentUndoRedo().ClearRedo();
  			SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() );
  
  			if( bNewTxtNd )
  			{
  				const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
  				GetNodes().MakeTxtNode( aTmpIdx,
  							GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
  			}
  
              // save the cursors (UNO and otherwise)
              SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
              if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
              {
                  *aSavePaM.GetMark() = SwPosition( *pTblNd );
                  aSavePaM.Move( fnMoveBackward, fnGoNode );
              }
              {
                  SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
                  ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
              }
  
  			// harte SeitenUmbrueche am nachfolgenden Node verschieben
  			sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
  			sal_uLong nNextNd = pTblNd->EndOfSectionIndex()+1;
  			SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode();
  			if( pNextNd )
  			{
  //JP 24.08.98: will man wirklich den PageDesc/Break vom
  //				nachfolgen Absatz ueberbuegeln?
  //				const SwAttrSet& rAttrSet = pNextNd->GetSwAttrSet();
  //				if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
  //					SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
  				{
  					SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
  					const SfxPoolItem *pItem;
  					if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
  						sal_False, &pItem ) )
  					{
  						pNextNd->SetAttr( *pItem );
  						bSavePageDesc = sal_True;
  					}
  
  					if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
  						sal_False, &pItem ) )
  					{
  						pNextNd->SetAttr( *pItem );
  						bSavePageBreak = sal_True;
  					}
  				}
  			}
  			SwUndoDelete* pUndo = new SwUndoDelete( aPaM );
  			if( bNewTxtNd )
  				pUndo->SetTblDelLastNd();
  			pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
              pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName());
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
          {
  			if( bNewTxtNd )
  			{
  				const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
  				GetNodes().MakeTxtNode( aTmpIdx,
  							GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
  			}
  
              // save the cursors (UNO and otherwise)
              SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
              if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
              {
                  *aSavePaM.GetMark() = SwPosition( *pTblNd );
                  aSavePaM.Move( fnMoveBackward, fnGoNode );
              }
              {
                  SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
                  ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
              }
  
  			// harte SeitenUmbrueche am nachfolgenden Node verschieben
  			SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
  			if( pNextNd )
  			{
  				SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
  				const SfxPoolItem *pItem;
  				if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
  					sal_False, &pItem ) )
  					pNextNd->SetAttr( *pItem );
  
  				if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
  					sal_False, &pItem ) )
  					pNextNd->SetAttr( *pItem );
  			}
  
  			pTblNd->DelFrms();
  			DeleteSection( pTblNd );
  		}
  		SetModified();
  		SetFieldsDirty( true, NULL, 0 );
  		return sal_True;
  	}
  
  	SwUndoTblNdsChg* pUndo = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
  		pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd,
                                       nMin, nMax, 0, sal_False, sal_False );
  	}
  
      bool bRet(false);
      {
          ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
  
          SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
          aMsgHnt.eFlags = TBL_BOXPTR;
          UpdateTblFlds( &aMsgHnt );
  
          if (rTable.IsNewModel())
          {
              if (bColumn)
                  rTable.PrepareDeleteCol( nMin, nMax );
              rTable.FindSuperfluousRows( aSelBoxes );
              if (pUndo)
                  pUndo->ReNewBoxes( aSelBoxes );
          }
          bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, sal_True, sal_True );
          if (bRet)
          {
              SetModified();
              SetFieldsDirty( true, NULL, 0 );
          }
      }
  
  	if( pUndo )
      {
  		if( bRet )
          {
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
  			delete pUndo;
  	}
  
  	return bRet;
  }
  
  
  // ---------- teilen / zusammenfassen von Boxen in der Tabelle --------
  
  sal_Bool SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, sal_uInt16 nCnt,
                        sal_Bool bSameHeight )
  {
  	// uebers SwDoc fuer Undo !!
  	ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	SwTable& rTbl = pTblNd->GetTable();
  	if( rTbl.ISA( SwDDETable ))
  		return sal_False;
  
  #ifdef DEL_TABLE_REDLINES
  	lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
  #endif
  
  	SvULongs aNdsCnts;
  	SwTableSortBoxes aTmpLst( 0, 5 );
  	SwUndoTblNdsChg* pUndo = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0,
                                       nCnt, bVert, bSameHeight );
  
  		aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
  		if( !bVert )
  		{
  			for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
  			{
  				const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
  				aNdsCnts.Insert( pSttNd->EndOfSectionIndex() -
  								 pSttNd->GetIndex(), n );
  			}
  		}
  	}
  
      bool bRet(false);
      {
          ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
  
          SwTableFmlUpdate aMsgHnt( &rTbl );
          aMsgHnt.eFlags = TBL_BOXPTR;
          UpdateTblFlds( &aMsgHnt );
  
          if (bVert)
              bRet = rTbl.SplitCol( this, rBoxes, nCnt );
          else
              bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight );
  
          if (bRet)
          {
              SetModified();
              SetFieldsDirty( true, NULL, 0 );
          }
      }
  
  	if( pUndo )
  	{
  		if( bRet )
  		{
  			if( bVert )
  				pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
  			else
  				pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts );
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
  			delete pUndo;
  	}
  
  	return bRet;
  }
  
  
  sal_uInt16 SwDoc::MergeTbl( SwPaM& rPam )
  {
  	// pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
  	SwTableNode* pTblNd = rPam.GetNode()->FindTableNode();
  	if( !pTblNd )
  		return TBLMERGE_NOSELECTION;
      SwTable& rTable = pTblNd->GetTable();
      if( rTable.ISA(SwDDETable) )
  		return TBLMERGE_NOSELECTION;
  	sal_uInt16 nRet = TBLMERGE_NOSELECTION;
      if( !rTable.IsNewModel() )
      {
          nRet =::CheckMergeSel( rPam );
          if( TBLMERGE_OK != nRet )
              return nRet;
          nRet = TBLMERGE_NOSELECTION;
      }
  
      // --> FME 2004-10-08 #i33394#
      GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_MERGE, NULL );
      // <--
  
  #ifdef DEL_TABLE_REDLINES
  	if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
  		DeleteRedline( *pTblNd, true, USHRT_MAX );
  #endif
  	RedlineMode_t eOld = GetRedlineMode();
  	SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
  
      SwUndoTblMerge *const pUndo( (GetIDocumentUndoRedo().DoesUndo())
          ?   new SwUndoTblMerge( rPam )
          :   0 );
  
  	// lasse ueber das Layout die Boxen suchen
  	SwSelBoxes aBoxes;
      SwSelBoxes aMerged;
  	SwTableBox* pMergeBox;
  
  	if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) )
  	{   // no cells found to merge
  		SetRedlineMode_intern( eOld );
  		if( pUndo )
  		{
  			delete pUndo;
              SwUndoId nLastUndoId(UNDO_EMPTY);
              if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId)
                  && (UNDO_REDLINE == nLastUndoId))
              {
                  // FIXME: why is this horrible cleanup necessary?
                  SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
                          GetUndoManager().RemoveLastUndo());
  				if( pU->GetRedlSaveCount() )
                  {
                      SwEditShell *const pEditShell(GetEditShell(0));
                      OSL_ASSERT(pEditShell);
                      ::sw::UndoRedoContext context(*this, *pEditShell);
                      static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
                  }
  				delete pU;
  			}
  		}
  	}
  	else
  	{
  		// die PaMs muessen noch aus dem Loesch Bereich entfernt
  		// werden. Setze sie immer hinter/auf die Tabelle; ueber die
  		// Dokument-Position werden sie dann immer an die alte Position gesetzt.
  		// Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel
  		// komme ich nicht mehr dran.
  		{
  			rPam.DeleteMark();
  			rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
  			rPam.GetPoint()->nContent.Assign( 0, 0 );
  			rPam.SetMark();
  			rPam.DeleteMark();
  
  			SwPaM* pTmp = &rPam;
  			while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ))
  				for( int i = 0; i < 2; ++i )
  					pTmp->GetBound( (sal_Bool)i ) = *rPam.GetPoint();
  		}
  
  		// dann fuege sie zusammen
  		SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
  		aMsgHnt.eFlags = TBL_BOXPTR;
  		UpdateTblFlds( &aMsgHnt );
  
  		if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo ))
  		{
  			nRet = TBLMERGE_OK;
  			SetModified();
  			SetFieldsDirty( true, NULL, 0 );
  			if( pUndo )
              {
                  GetIDocumentUndoRedo().AppendUndo( pUndo );
              }
          }
  		else if( pUndo )
  			delete pUndo;
  
  		rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
  		rPam.Move();
  
  		::ClearFEShellTabCols();
  		SetRedlineMode_intern( eOld );
  	}
      GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_MERGE, NULL );
  	return nRet;
  }
  
  
  
  // -------------------------------------------------------
  
  //---------
  // SwTableNode
  //---------
  
  SwTableNode::SwTableNode( const SwNodeIndex& rIdx )
  	: SwStartNode( rIdx, ND_TABLENODE )
  {
  	pTable = new SwTable( 0 );
  }
  
  SwTableNode::~SwTableNode()
  {
  	//don't forget to notify uno wrappers
  	SwFrmFmt* pTblFmt = GetTable().GetFrmFmt();
  	SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
  								pTblFmt );
  	pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
  	DelFrms();
  	delete pTable;
  }
  
  SwTabFrm *SwTableNode::MakeFrm( SwFrm* pSib )
  {
  	return new SwTabFrm( *pTable, pSib );
  }
  
  //Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
  //Dokument. Die erzeugten Contentframes werden in das entsprechende
  //Layout gehaengt.
  void SwTableNode::MakeFrms(const SwNodeIndex & rIdx )
  {
  	if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ??
  		return;
  
  	SwFrm *pFrm, *pNew;
  	SwCntntNode * pNode = rIdx.GetNode().GetCntntNode();
  
  	ASSERT( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch.");
  
  	sal_Bool bBefore = rIdx < GetIndex();
  
  	SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
  
  	while( 0 != (pFrm = aNode2Layout.NextFrm()) )
  	{
  		pNew = pNode->MakeFrm( pFrm );
  		// wird ein Node vorher oder nachher mit Frames versehen
  		if ( bBefore )
  			// der neue liegt vor mir
  			pNew->Paste( pFrm->GetUpper(), pFrm );
  		else
  			// der neue liegt hinter mir
  			pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
  	}
  }
  
  //Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden
  //CntntFrm pasten.
  
  void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind )
  {
  	ASSERT( pIdxBehind, "kein Index" );
  	*pIdxBehind = *this;
  	SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() );
  	if( !pNd )
  		return ;
  
      SwFrm *pFrm( 0L );
  	SwLayoutFrm *pUpper( 0L );
  	SwNode2Layout aNode2Layout( *pNd, GetIndex() );
  	while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) )
  	{
          SwTabFrm* pNew = MakeFrm( pUpper );
  		pNew->Paste( pUpper, pFrm );
          // --> OD 2005-12-01 #i27138#
          // notify accessibility paragraphs objects about changed
          // CONTENT_FLOWS_FROM/_TO relation.
          // Relation CONTENT_FLOWS_FROM for next paragraph will change
          // and relation CONTENT_FLOWS_TO for previous paragraph will change.
          {
              ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
              if ( pViewShell && pViewShell->GetLayout() &&
                   pViewShell->GetLayout()->IsAnyShellAccessible() )
              {
                  pViewShell->InvalidateAccessibleParaFlowRelation(
                              dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
                              dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) );
              }
          }
          // <--
          ((SwTabFrm*)pNew)->RegistFlys();
  	}
  }
  
  void SwTableNode::DelFrms()
  {
  	//Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows
  	//nehmen sie mit in's Grab.
  	//Die TabFrms haengen am FrmFmt des SwTable.
  	//Sie muessen etwas umstaendlich zerstort werden, damit die Master
  	//die Follows mit in's Grab nehmen.
  
  	SwIterator<SwTabFrm,SwFmt> aIter( *(pTable->GetFrmFmt()) );
  	SwTabFrm *pFrm = aIter.First();
  	while ( pFrm )
  	{
  		sal_Bool bAgain = sal_False;
  		{
  			if ( !pFrm->IsFollow() )
  			{
  				while ( pFrm->HasFollow() )
  					pFrm->JoinAndDelFollows();
                  // --> OD 2005-12-01 #i27138#
                  // notify accessibility paragraphs objects about changed
                  // CONTENT_FLOWS_FROM/_TO relation.
                  // Relation CONTENT_FLOWS_FROM for current next paragraph will change
                  // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
                  {
                      ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
                      if ( pViewShell && pViewShell->GetLayout() &&
                           pViewShell->GetLayout()->IsAnyShellAccessible() )
                      {
                          pViewShell->InvalidateAccessibleParaFlowRelation(
                              dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
                              dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
                      }
                  }
                  // <--
                  pFrm->Cut();
  				delete pFrm;
  				bAgain = sal_True;
  			}
  		}
  		pFrm = bAgain ? aIter.First() : aIter.Next();
  	}
  }
  
  
  void SwTableNode::SetNewTable( SwTable* pNewTable, sal_Bool bNewFrames )
  {
  	DelFrms();
  	delete pTable;
  	pTable = pNewTable;
  	if( bNewFrames )
  	{
  		SwNodeIndex aIdx( *EndOfSectionNode());
  		GetNodes().GoNext( &aIdx );
  		MakeFrms( &aIdx );
  	}
  }
  
  void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr,
  						const SwCellFrm* pBoxFrm ) const
  {
  	const SwTableBox* pBox = 0;
  	SwTabFrm *pTab = 0;
  
  	if( pBoxFrm )
  	{
  		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
  		pBox = pBoxFrm->GetTabBox();
  	}
  	else if( pCrsr )
  	{
  		const SwCntntNode* pCNd = pCrsr->GetCntntNode();
  		if( !pCNd )
  			return ;
  
  		Point aPt;
          const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
  		if( pShCrsr )
  			aPt = pShCrsr->GetPtPos();
  
  		const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
  		do {
  			pTmpFrm = pTmpFrm->GetUpper();
  		} while ( !pTmpFrm->IsCellFrm() );
  
  		pBoxFrm = (SwCellFrm*)pTmpFrm;
  		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
  		pBox = pBoxFrm->GetTabBox();
  	}
  	else if( !pCrsr && !pBoxFrm )
  	{
  		ASSERT( sal_False, "one of them must be indicated!" );
  		return ;
  	}
  
  	//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
      SWRECTFN( pTab )
      const SwPageFrm* pPage = pTab->FindPageFrm();
      const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
                             (pPage->Frm().*fnRect->fnGetLeft)();
      const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
                              (pPage->Frm().*fnRect->fnGetLeft)();
  
      rFill.SetLeftMin ( nLeftMin );
      rFill.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
      rFill.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
      rFill.SetRightMax( nRightMax - nLeftMin );
  
  	pTab->GetTable()->GetTabCols( rFill, pBox );
  }
  
  //
  // Here are some little helpers used in SwDoc::GetTabRows
  //
  
  #define ROWFUZZY 25
  
  struct FuzzyCompare
  {
      bool operator() ( long s1, long s2 ) const;
  };
  
  bool FuzzyCompare::operator() ( long s1, long s2 ) const
  {
      return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY );
  }
  
  bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes )
  {
      for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
      {
          if ( rFrm.GetTabBox() == rBoxes[ i ] )
              return true;
      }
  
      return false;
  }
  
  //
  // SwDoc::GetTabRows()
  //
  
  void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* ,
  						const SwCellFrm* pBoxFrm ) const
  {
      ASSERT( pBoxFrm, "GetTabRows called without pBoxFrm" )
  
      // --> FME 2005-09-12 #121591# Make code robust:
      if ( !pBoxFrm )
          return;
      // <--
  
      // --> FME 2005-01-06 #i39552# Collection of the boxes of the current
      // column has to be done at the beginning of this function, because
      // the table may be formatted in ::GetTblSel.
      SwDeletionChecker aDelCheck( pBoxFrm );
  
      SwSelBoxes aBoxes;
      const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm );
      if ( pCntnt && pCntnt->IsTxtFrm() )
      {
          const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
          const SwCursor aTmpCrsr( aPos, 0, false );
          ::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
      }
      // <--
  
      // --> FME 2005-09-12 #121591# Make code robust:
      if ( aDelCheck.HasBeenDeleted() )
      {
          ASSERT( false, "Current box has been deleted during GetTabRows()" )
          return;
      }
      // <--
  
      // --> FME 2005-09-12 #121591# Make code robust:
      const SwTabFrm* pTab = pBoxFrm->FindTabFrm();
      ASSERT( pTab, "GetTabRows called without a table" )
      if ( !pTab )
          return;
      // <--
  
      const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
  
  	//Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
      SWRECTFN( pTab )
      const SwPageFrm* pPage = pTab->FindPageFrm();
      const long nLeftMin  = ( bVert ?
                               pTab->GetPrtLeft() - pPage->Frm().Left() :
                               pTab->GetPrtTop() - pPage->Frm().Top() );
      const long nLeft     = bVert ? LONG_MAX : 0;
      const long nRight    = (pTab->Prt().*fnRect->fnGetHeight)();
      const long nRightMax = bVert ? nRight : LONG_MAX;
  
      rFill.SetLeftMin( nLeftMin );
      rFill.SetLeft( nLeft );
      rFill.SetRight( nRight );
      rFill.SetRightMax( nRightMax );
  
      typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap;
      BoundaryMap aBoundaries;
      BoundaryMap::iterator aIter;
      std::pair< long, long > aPair;
  
      typedef std::map< long, bool > HiddenMap;
      HiddenMap aHidden;
      HiddenMap::iterator aHiddenIter;
  
      while ( pFrm && pTab->IsAnLower( pFrm ) )
      {
          if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
          {
              // upper and lower borders of current cell frame:
              long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)();
              long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
  
              // get boundaries for nUpperBorder:
              aIter = aBoundaries.find( nUpperBorder );
              if ( aIter == aBoundaries.end() )
              {
                  aPair.first = nUpperBorder; aPair.second = LONG_MAX;
                  aBoundaries[ nUpperBorder ] = aPair;
              }
  
              // get boundaries for nLowerBorder:
              aIter = aBoundaries.find( nLowerBorder );
              if ( aIter == aBoundaries.end() )
              {
                  aPair.first = nUpperBorder; aPair.second = LONG_MAX;
              }
              else
              {
                  nLowerBorder = (*aIter).first;
                  long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder );
                  aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
              }
              aBoundaries[ nLowerBorder ] = aPair;
  
              // calculate hidden flags for entry nUpperBorder/nLowerBorder:
              long nTmpVal = nUpperBorder;
              for ( sal_uInt8 i = 0; i < 2; ++i )
              {
                  aHiddenIter = aHidden.find( nTmpVal );
                  if ( aHiddenIter == aHidden.end() )
                      aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes );
                  else
                  {
                      if ( aHidden[ nTmpVal ] &&
                           lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) )
                          aHidden[ nTmpVal ] = false;
                  }
                  nTmpVal = nLowerBorder;
              }
          }
  
          pFrm = pFrm->GetNextLayoutLeaf();
      }
  
      // transfer calculated values from BoundaryMap and HiddenMap into rFill:
      sal_uInt16 nIdx = 0;
      for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter )
      {
          const long nTabTop = (pTab->*fnRect->fnGetPrtTop)();
          const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop );
          const std::pair< long, long > aTmpPair = (*aIter).second;
          const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop );
          const long nSecond = aTmpPair.second;
  
          aHiddenIter = aHidden.find( (*aIter).first );
          const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
          rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
      }
  
      // delete first and last entry
      ASSERT( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" )
      // --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make
      // code robust by checking count of rFill.
      if ( rFill.Count() ) rFill.Remove( 0, 1 );
      if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 );
      // <--
      rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
  }
  
  void SwDoc::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly,
  						const SwCursor* pCrsr, const SwCellFrm* pBoxFrm )
  {
  	const SwTableBox* pBox = 0;
  	SwTabFrm *pTab = 0;
  
  	if( pBoxFrm )
  	{
  		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
  		pBox = pBoxFrm->GetTabBox();
  	}
  	else if( pCrsr )
  	{
  		const SwCntntNode* pCNd = pCrsr->GetCntntNode();
  		if( !pCNd )
  			return ;
  
  		Point aPt;
          const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
  		if( pShCrsr )
  			aPt = pShCrsr->GetPtPos();
  
  		const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
  		do {
  			pTmpFrm = pTmpFrm->GetUpper();
  		} while ( !pTmpFrm->IsCellFrm() );
  
  		pBoxFrm = (SwCellFrm*)pTmpFrm;
  		pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
  		pBox = pBoxFrm->GetTabBox();
  	}
  	else if( !pCrsr && !pBoxFrm )
  	{
  		ASSERT( sal_False, "one of them must be indicated!" );
  		return ;
  	}
  
  	// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
  	// dann muss es jetzt auf absolute umgerechnet werden.
  	SwTable& rTab = *pTab->GetTable();
  	const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize();
      SWRECTFN( pTab )
      // OD 06.08.2003 #i17174# - With fix for #i9040# the shadow size is taken
      // from the table width. Thus, add its left and right size to current table
      // printing area width in order to get the correct table size attribute.
      SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
      {
          SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() );
          nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) +
                       aShadow.CalcShadowSpace( SHADOW_RIGHT );
      }
      if( nPrtWidth != rTblFrmSz.GetWidth() )
  	{
  		SwFmtFrmSize aSz( rTblFrmSz );
          aSz.SetWidth( nPrtWidth );
          rTab.GetFrmFmt()->SetFmtAttr( aSz );
  	}
  
      SwTabCols aOld( rNew.Count() );
  
      const SwPageFrm* pPage = pTab->FindPageFrm();
      const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
                             (pPage->Frm().*fnRect->fnGetLeft)();
      const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
                              (pPage->Frm().*fnRect->fnGetLeft)();
  
      //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
      aOld.SetLeftMin ( nLeftMin );
      aOld.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
      aOld.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
      aOld.SetRightMax( nRightMax - nLeftMin );
  
      rTab.GetTabCols( aOld, pBox );
      SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
  }
  
  void SwDoc::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const SwCursor*,
                          const SwCellFrm* pBoxFrm )
  {
  	const SwTableBox* pBox;
  	SwTabFrm *pTab;
  
      ASSERT( pBoxFrm, "SetTabRows called without pBoxFrm" )
  
  	pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
  	pBox = pBoxFrm->GetTabBox();
  
  	// sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
  	// dann muss es jetzt auf absolute umgerechnet werden.
      SWRECTFN( pTab )
  	SwTabCols aOld( rNew.Count() );
  
      //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
      const SwPageFrm* pPage = pTab->FindPageFrm();
  
      aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() );
      long nLeftMin;
      if ( bVert )
      {
          nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left();
          aOld.SetLeft    ( LONG_MAX );
          aOld.SetRightMax( aOld.GetRight() );
  
      }
      else
      {
          nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top();
          aOld.SetLeft    ( 0 );
          aOld.SetRightMax( LONG_MAX );
      }
      aOld.SetLeftMin ( nLeftMin );
  
      GetTabRows( aOld, 0, pBoxFrm );
  
      GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_ATTR, NULL );
  
      // check for differences between aOld and rNew:
      const sal_uInt16 nCount = rNew.Count();
      const SwTable* pTable = pTab->GetTable();
      ASSERT( pTable, "My colleague told me, this couldn't happen" );
  
      for ( sal_uInt16 i = 0; i <= nCount; ++i )
      {
          const sal_uInt16 nIdxStt = bVert ? nCount - i : i - 1;
          const sal_uInt16 nIdxEnd = bVert ? nCount - i - 1 : i;
  
          const long nOldRowStart = i == 0  ? 0 : aOld[ nIdxStt ];
          const long nOldRowEnd =   i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
          const long nOldRowHeight = nOldRowEnd - nOldRowStart;
  
          const long nNewRowStart = i == 0  ? 0 : rNew[ nIdxStt ];
          const long nNewRowEnd =   i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
          const long nNewRowHeight = nNewRowEnd - nNewRowStart;
  
          const long nDiff = nNewRowHeight - nOldRowHeight;
          if ( abs( nDiff ) >= ROWFUZZY )
          {
              // For the old table model pTxtFrm and pLine will be set for every box.
              // For the new table model pTxtFrm will be set if the box is not covered,
              // but the pLine will be set if the box is not an overlapping box
              // In the new table model the row height can be adjusted,
              // when both variables are set.
              SwTxtFrm* pTxtFrm = 0;
              const SwTableLine* pLine = 0;
  
              // Iterate over all SwCellFrms with Bottom = nOldPos
              const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
              while ( pFrm && pTab->IsAnLower( pFrm ) )
              {
                  if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
                  {
                      const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
                      const sal_uLong nTabTop = (pTab->*fnRect->fnGetPrtTop)();
                      if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
                      {
                          if ( !bCurColOnly || pFrm == pBoxFrm )
                          {
                              const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) );
  
                              if ( pCntnt && pCntnt->IsTxtFrm() )
                              {
                                  pBox = ((SwCellFrm*)pFrm)->GetTabBox();
                                  const long nRowSpan = pBox->getRowSpan();
                                  if( nRowSpan > 0 ) // Not overlapped
                                      pTxtFrm = (SwTxtFrm*)pCntnt;
                                  if( nRowSpan < 2 ) // Not overlapping for row height
                                      pLine = pBox->GetUpper();
                                  if( pLine && pTxtFrm ) // always for old table model
                                  {
                                      // The new row height must not to be calculated from a overlapping box
                                      SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() );
                                      const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff;
                                      if( nNewSize != aNew.GetHeight() )
                                      {
                                          aNew.SetHeight( nNewSize );
                                          if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() )
                                              aNew.SetHeightSizeType( ATT_MIN_SIZE );
                                          // This position must not be in an overlapped box
                                          const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
                                          const SwCursor aTmpCrsr( aPos, 0, false );
                                          SetRowHeight( aTmpCrsr, aNew );
                                          // For the new table model we're done, for the old one
                                          // there might be another (sub)row to adjust...
                                          if( pTable->IsNewModel() )
                                              break;
                                      }
                                      pLine = 0;
                                  }
                              }
                          }
                      }
                  }
                  pFrm = pFrm->GetNextLayoutLeaf();
              }
          }
      }
  
      GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_ATTR, NULL );
  
  	::ClearFEShellTabCols();
  }
  
  /* -----------------18.07.98 11:45-------------------
   *  Direktzugriff fuer UNO
   * --------------------------------------------------*/
  void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
  								const SwTableBox *pStart, sal_Bool bCurRowOnly )
  {
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          GetIDocumentUndoRedo().AppendUndo(
              new SwUndoAttrTbl( *rTab.GetTableNode(), sal_True ));
  	}
  	rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
    	::ClearFEShellTabCols();
  	SetModified();
  }
  
  void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet )
  {
      if( nSet == rTable.GetRowsToRepeat() )
          return;
  
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          GetIDocumentUndoRedo().AppendUndo(
              new SwUndoTblHeadline(rTable, rTable.GetRowsToRepeat(), nSet) );
      }
  
      SwMsgPoolItem aChg( RES_TBLHEADLINECHG );
      rTable.SetRowsToRepeat( nSet );
      rTable.GetFrmFmt()->ModifyNotification( &aChg, &aChg );
      SetModified();
  }
  
  
  
  
  // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
  // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
  // Ist das Flag bCalcNewSize auf sal_True, wird fuer beide neuen Tabellen
  // die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt,
  // die Size ist "absolut" gesetzt (USHRT_MAX)
  
  void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd )
  {
  	if( pHst )
  		pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE );
  }
  
  void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox )
  {
  	aPosArr.Insert( nWidth, aPosArr.Count() );
  	SwTableBox* p = (SwTableBox*)&rBox;
  	aBoxes.Insert( p, aBoxes.Count() );
  	nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
  }
  
  const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox )
  {
  	const SwTableBox* pRet = 0;
  	sal_uInt16 n;
  
  	if( aPosArr.Count() )
  	{
  		for( n = 0; n < aPosArr.Count(); ++n )
  			if( aPosArr[ n ] == nWidth )
  				break;
  			else if( aPosArr[ n ] > nWidth )
  			{
  				if( n )
  					--n;
  				break;
  			}
  
  		if( n >= aPosArr.Count() )
  			--n;
  
  		nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
  		pRet = aBoxes[ n ];
  	}
  	return pRet;
  }
  
  sal_Bool SwCollectTblLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth )
  {
  	sal_uInt16 n;
  
  	if( aPosArr.Count() )
  	{
  		for( n = 0; n < aPosArr.Count(); ++n )
  			if( aPosArr[ n ] == nOffset )
  				break;
  			else if( aPosArr[ n ] > nOffset )
  			{
  				if( n )
  					--n;
  				break;
  			}
  
  		aPosArr.Remove( 0, n );
  		aBoxes.Remove( 0, n );
  
  		// dann die Positionen der neuen Size anpassen
  		for( n = 0; n < aPosArr.Count(); ++n )
  		{
  			sal_uLong nSize = nWidth;
  			nSize *= ( aPosArr[ n ] - nOffset );
  			nSize /= nOldWidth;
  			aPosArr[ n ] = sal_uInt16( nSize );
  		}
  	}
  	return 0 != aPosArr.Count();
  }
  
  sal_Bool lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
  {
  	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
  	if( pSplPara->IsGetValues() )
  		((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara );
  	else
  		((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara );
  	return sal_True;
  }
  
  sal_Bool lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara )
  {
  	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
  	sal_uInt16 nLen = rpBox->GetTabLines().Count();
  	if( nLen )
  	{
  		// dann mit der richtigen Line weitermachen
  		if( pSplPara->IsGetFromTop() )
  			nLen = 0;
  		else
  			--nLen;
  
  		const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
  		lcl_Line_CollectBox( pLn, pPara );
  	}
  	else
  		pSplPara->AddBox( *rpBox );
  	return sal_True;
  }
  
  sal_Bool lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara )
  {
  	SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
  	sal_uInt16 nLen = rpBox->GetTabLines().Count();
  	if( nLen )
  	{
  		// dann mit der richtigen Line weitermachen
  		if( pSplPara->IsGetFromTop() )
  			nLen = 0;
  		else
  			--nLen;
  
  		const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
  		lcl_Line_CollectBox( pLn, pPara );
  	}
  	else
  	{
  		const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox );
  		SwFrmFmt* pFmt = pSrcBox->GetFrmFmt();
  		SwTableBox* pBox = (SwTableBox*)rpBox;
  
  		if( HEADLINE_BORDERCOPY == pSplPara->GetMode() )
  		{
  			const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
  			if( !rBoxItem.GetTop() )
  			{
  				SvxBoxItem aNew( rBoxItem );
  				aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP );
  				if( aNew != rBoxItem )
                      pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
  			}
  		}
  		else
  		{
  sal_uInt16 __FAR_DATA aTableSplitBoxSetRange[] = {
  	RES_LR_SPACE, 		RES_UL_SPACE,
  	RES_BACKGROUND, 	RES_SHADOW,
  	RES_PROTECT, 		RES_PROTECT,
  	RES_VERT_ORIENT,	RES_VERT_ORIENT,
  	0 };
  			SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(),
  								aTableSplitBoxSetRange );
  			aTmpSet.Put( pFmt->GetAttrSet() );
  			if( aTmpSet.Count() )
                  pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet );
  
  			if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() )
  			{
  				SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
  				SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
  				if( !pCNd )
  					pCNd = aIdx.GetNodes().GoNext( &aIdx );
  				aIdx = *pBox->GetSttNd();
  				SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
  
  				// nur wenn der Node alleine in der Section steht
  				if( 2 == pDNd->EndOfSectionIndex() -
  						pDNd->StartOfSectionIndex() )
  				{
  					pSplPara->AddToUndoHistory( *pDNd );
  					pDNd->ChgFmtColl( pCNd->GetFmtColl() );
  				}
  			}
  
  			// bedingte Vorlage beachten
  			pBox->GetSttNd()->CheckSectionCondColl();
  		}
  	}
  	return sal_True;
  }
  
  
  sal_Bool SwDoc::SplitTable( const SwPosition& rPos, sal_uInt16 eHdlnMode,
  						sal_Bool bCalcNewSize )
  {
  	SwNode* pNd = &rPos.nNode.GetNode();
  	SwTableNode* pTNd = pNd->FindTableNode();
  	if( !pTNd || pNd->IsTableNode() )
  		return 0;
  
  	if( pTNd->GetTable().ISA( SwDDETable ))
  		return sal_False;
  
  	SwTable& rTbl = pTNd->GetTable();
  	rTbl.SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
  
  	SwTableFmlUpdate aMsgHnt( &rTbl );
  
  	SwHistory aHistory;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
  		aMsgHnt.pHistory = &aHistory;
      }
  
  	{
  		sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
  
  		// Suche die Grund-Line dieser Box:
  		SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
  		if( pBox )
  		{
  			SwTableLine* pLine = pBox->GetUpper();
  			while( pLine->GetUpper() )
  				pLine = pLine->GetUpper()->GetUpper();
  
  			// in pLine steht jetzt die GrundLine.
  			aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
  		}
  
  		String sNewTblNm( GetUniqueTblName() );
  		aMsgHnt.DATA.pNewTblNm = &sNewTblNm;
  		aMsgHnt.eFlags = TBL_SPLITTBL;
  		UpdateTblFlds( &aMsgHnt );
  	}
  
  	//Lines fuer das Layout-Update heraussuchen.
  	_FndBox aFndBox( 0, 0 );
      aFndBox.SetTableLines( rTbl );
      aFndBox.DelFrms( rTbl );
  
      // TL_CHART2: need to inform chart of probably changed cell names
      //pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
  
  	SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, sal_False, bCalcNewSize );
  
  	if( pNew )
  	{
          SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() );
  		SwUndoSplitTbl* pUndo = 0;
          if (GetIDocumentUndoRedo().DoesUndo())
          {
              pUndo = new SwUndoSplitTbl(
                          *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize);
              GetIDocumentUndoRedo().AppendUndo(pUndo);
  			if( aHistory.Count() )
  				pUndo->SaveFormula( aHistory );
  		}
  
  		switch( eHdlnMode )
  		{
  			// setze die untere Border der vorherige Line,
  			// an der aktuellen als obere
  		case HEADLINE_BORDERCOPY:
  			{
  				SwCollectTblLineBoxes aPara( sal_False, eHdlnMode );
  				SwTableLine* pLn = rTbl.GetTabLines()[
  							rTbl.GetTabLines().Count() - 1 ];
  				pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
  
  				aPara.SetValues( sal_True );
  				pLn = pNew->GetTable().GetTabLines()[ 0 ];
  				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
  
  				// Kopfzeile wiederholen abschalten
                  pNew->GetTable().SetRowsToRepeat( 0 );
  			}
  			break;
  
  			// setze die Attributierung der ersten Line an der neuen ersten
  		case HEADLINE_BOXATTRCOPY:
  		case HEADLINE_BOXATRCOLLCOPY:
  			{
  				SwHistory* pHst = 0;
  				if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo )
  					pHst = pUndo->GetHistory();
  
  				SwCollectTblLineBoxes aPara( sal_True, eHdlnMode, pHst );
  				SwTableLine* pLn = rTbl.GetTabLines()[ 0 ];
  				pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
  
  				aPara.SetValues( sal_True );
  				pLn = pNew->GetTable().GetTabLines()[ 0 ];
  				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
  			}
  			break;
  
  		case HEADLINE_CNTNTCOPY:
  			rTbl.CopyHeadlineIntoTable( *pNew );
  			if( pUndo )
  				pUndo->SetTblNodeOffset( pNew->GetIndex() );
  			break;
  
  		case HEADLINE_NONE:
  			// Kopfzeile wiederholen abschalten
              pNew->GetTable().SetRowsToRepeat( 0 );
  			break;
  		}
  
  		// und Frms einfuegen.
  		SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
  		GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
  		pNew->MakeFrms( &aNdIdx );
  
  		//Zwischen die Tabellen wird ein Absatz geschoben
  		GetNodes().MakeTxtNode( SwNodeIndex( *pNew ),
  								GetTxtCollFromPool( RES_POOLCOLL_TEXT ) );
  	}
  
  	//Layout updaten
      aFndBox.MakeFrms( rTbl );
  
      // TL_CHART2: need to inform chart of probably changed cell names
      UpdateCharts( rTbl.GetFrmFmt()->GetName() );
  
      SetFieldsDirty( true, NULL, 0 );
  
  	return 0 != pNew;
  }
  
  sal_Bool lcl_ChgTblSize( SwTable& rTbl )
  {
  	// das Attribut darf nicht ueber das Modify an der
  	// Tabelle gesetzt werden, denn sonst werden alle
  	// Boxen wieder auf 0 zurueck gesetzt. Also locke das Format
  	SwFrmFmt* pFmt = rTbl.GetFrmFmt();
  	SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() );
  
  	if( USHRT_MAX == aTblMaxSz.GetWidth() )
  		return sal_False;
  
  	sal_Bool bLocked = pFmt->IsModifyLocked();
  	pFmt->LockModify();
  
  	aTblMaxSz.SetWidth( 0 );
  
  	SwTableLines& rLns = rTbl.GetTabLines();
  	for( sal_uInt16 nLns = 0; nLns < rLns.Count(); ++nLns )
  	{
  		SwTwips nMaxLnWidth = 0;
  		SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes();
  		for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox )
  			nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth();
  
  		if( nMaxLnWidth > aTblMaxSz.GetWidth() )
  			aTblMaxSz.SetWidth( nMaxLnWidth );
  	}
      pFmt->SetFmtAttr( aTblMaxSz );
  	if( !bLocked )			// und gegebenenfalls Lock wieder freigeben
  		pFmt->UnlockModify();
  
  	return sal_True;
  }
  
  class _SplitTable_Para
  {
  	SvPtrarr aSrc, aDest;
  	SwTableNode* pNewTblNd;
  	SwTable& rOldTbl;
  
  public:
  	_SplitTable_Para( SwTableNode* pNew, SwTable& rOld )
  		: aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld )
  	{}
  	sal_uInt16 SrcFmt_GetPos( void* pFmt ) const
  			{ return aSrc.GetPos( pFmt ); }
  
  	void DestFmt_Insert( void* pFmt )
  			{ aDest.Insert( pFmt, aDest.Count() ); }
  
  	void SrcFmt_Insert( void* pFmt )
  			{ aSrc.Insert( pFmt, aSrc.Count() ); }
  
  	SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const
  			{ return (SwFrmFmt*)aDest[ nPos ]; }
  
  	void ChgBox( SwTableBox* pBox )
  	{
  		rOldTbl.GetTabSortBoxes().Remove( pBox );
  		pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox );
  	}
  };
  
  
  sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara );
  
  sal_Bool lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara )
  {
  	SwTableLine* pLn = (SwTableLine*)rpLine;
  	_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
  
  	SwFrmFmt *pSrcFmt = pLn->GetFrmFmt();
  	sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
  	if( USHRT_MAX == nPos )
  	{
  		rPara.DestFmt_Insert( pLn->ClaimFrmFmt() );
  		rPara.SrcFmt_Insert( pSrcFmt );
  	}
  	else
  		pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) );
  
  	pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara );
  	return sal_True;
  }
  
  sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara )
  {
  	SwTableBox* pBox = (SwTableBox*)rpBox;
  	_SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
  
  	SwFrmFmt *pSrcFmt = pBox->GetFrmFmt();
  	sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
  	if( USHRT_MAX == nPos )
  	{
  		rPara.DestFmt_Insert( pBox->ClaimFrmFmt() );
  		rPara.SrcFmt_Insert( pSrcFmt );
  	}
  	else
  		pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) );
  
  	if( pBox->GetSttNd() )
  		rPara.ChgBox( pBox );
  	else
  		pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara );
  	return sal_True;
  }
  
  SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, sal_Bool bAfter,
  									sal_Bool bCalcNewSize )
  {
  	SwNode* pNd = &rPos.GetNode();
  	SwTableNode* pTNd = pNd->FindTableNode();
  	if( !pTNd || pNd->IsTableNode() )
  		return 0;
  
  	sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
  
  	// Suche die Grund-Line dieser Box:
  	SwTable& rTbl = pTNd->GetTable();
  	SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
  	if( !pBox )
  		return 0;
  
  	SwTableLine* pLine = pBox->GetUpper();
  	while( pLine->GetUpper() )
  		pLine = pLine->GetUpper()->GetUpper();
  
  	// in pLine steht jetzt die GrundLine.
  	sal_uInt16 nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
  	if( USHRT_MAX == nLinePos ||
  		( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos ))
  		return 0;		// nicht gefunden oder letze Line !!
  
  	// Suche jetzt die 1. Box der nachfolgenden Line
  	SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ];
  	pBox = pNextLine->GetTabBoxes()[0];
  	while( !pBox->GetSttNd() )
  		pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
  
  	// dann fuege mal einen End- und TabelleNode ins Nodes-Array ein.
  	SwTableNode * pNewTblNd;
  	{
  		SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode();
  		ASSERT( pOldTblEndNd, "wo ist der EndNode?" )
  
  		SwNodeIndex aIdx( *pBox->GetSttNd() );
  		new SwEndNode( aIdx, *pTNd );
  		pNewTblNd = new SwTableNode( aIdx );
          pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() );
  
  		pOldTblEndNd->pStartOfSection = pNewTblNd;
  		pNewTblNd->pEndOfSection = pOldTblEndNd;
  
  		SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
  		do {
  			ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
  			pBoxNd->pStartOfSection = pNewTblNd;
  			pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
  		} while( pBoxNd != pOldTblEndNd );
  	}
  
  	{
          // die Lines ruebermoven...
  		SwTable& rNewTbl = pNewTblNd->GetTable();
  		rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos );
          //
          // von hinten (unten-rechts) nach vorn (oben-links) alle Boxen
          // beim chart data provider austragen (das modified event wird dann
          // in der aufrufenden Funktion getriggert.
          // TL_CHART2:
          SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider();
          if( pPCD )
          {
              for (sal_uInt16 k = nLinePos;  k < rTbl.GetTabLines().Count();  ++k)
              {
                  sal_uInt16 nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos;
                  sal_uInt16 nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count();
                  for (sal_uInt16 j = 0;  j < nBoxCnt;  ++j)
                  {
                      sal_uInt16 nIdx = nBoxCnt - 1 - j;
                      pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
                  }
              }
          }
          //
          // ...und loeschen
          sal_uInt16 nDeleted = rTbl.GetTabLines().Count() - nLinePos;
  		rTbl.GetTabLines().Remove( nLinePos, nDeleted );
  
  		// und die betr. Boxen verschieben. Dabei die Formate eindeutig
  		// machen und die StartNodes korrigieren
  		_SplitTable_Para aPara( pNewTblNd, rTbl );
  		rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara );
          rTbl.CleanUpBottomRowSpan( nDeleted );
  	}
  
  	{
  		// Das Tabellen-FrmFormat kopieren
  		SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt();
  		SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt(
  								pOldTblFmt->GetDoc()->GetUniqueTblName(),
  								pOldTblFmt->GetDoc()->GetDfltFrmFmt() );
  
  		*pNewTblFmt = *pOldTblFmt;
          pNewTblNd->GetTable().RegisterToFormat( *pNewTblFmt );
  
  		// neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es
  		// beim 1. schon geklappt hat; also absolute Groesse hat)
  		if( bCalcNewSize && lcl_ChgTblSize( rTbl ) )
  			lcl_ChgTblSize( pNewTblNd->GetTable() );
  	}
  
      // TL_CHART2: need to inform chart of probably changed cell names
      rTbl.UpdateCharts();
  
  	return pNewTblNd;		// das wars
  }
  
  // und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen
  // bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter
  // stehenden vereint wird.
  sal_Bool SwDoc::MergeTable( const SwPosition& rPos, sal_Bool bWithPrev, sal_uInt16 nMode )
  {
  	SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd;
  	if( !pTblNd )
  		return sal_False;
  
  	SwNodes& rNds = GetNodes();
  	if( bWithPrev )
  		pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
  	else
  		pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
  	if( !pDelTblNd )
  		return sal_False;
  
  	if( pTblNd->GetTable().ISA( SwDDETable ) ||
  		pDelTblNd->GetTable().ISA( SwDDETable ))
  		return sal_False;
  
  	// MIB 9.7.97: HTML-Layout loeschen
  	pTblNd->GetTable().SetHTMLTableLayout( 0 );
  	pDelTblNd->GetTable().SetHTMLTableLayout( 0 );
  
  	// beide Tabellen vorhanden, also kanns losgehen
  	SwUndoMergeTbl* pUndo = 0;
  	SwHistory* pHistory = 0;
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, bWithPrev, nMode );
          GetIDocumentUndoRedo().AppendUndo(pUndo);
  		pHistory = new SwHistory;
  	}
  
  	// alle "Tabellenformeln" anpassen
  	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
  	aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable();
  	aMsgHnt.eFlags = TBL_MERGETBL;
  	aMsgHnt.pHistory = pHistory;
  	UpdateTblFlds( &aMsgHnt );
  
  	// das eigentliche Mergen
  	SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd );
  	sal_Bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory );
  
  	if( pHistory )
  	{
  		if( pHistory->Count() )
  			pUndo->SaveFormula( *pHistory );
  		delete pHistory;
  	}
  	if( bRet )
  	{
  		SetModified();
  		SetFieldsDirty( true, NULL, 0 );
  	}
  	return bRet;
  }
  
  sal_Bool SwNodes::MergeTable( const SwNodeIndex& rPos, sal_Bool bWithPrev,
  							sal_uInt16 nMode, SwHistory* )
  {
  	SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode();
  	ASSERT( pDelTblNd, "wo ist der TableNode geblieben?" );
  
  	SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
  	ASSERT( pTblNd, "wo ist der TableNode geblieben?" );
  
  	if( !pDelTblNd || !pTblNd )
  		return sal_False;
  
  	pDelTblNd->DelFrms();
  
  	SwTable& rDelTbl = pDelTblNd->GetTable();
  	SwTable& rTbl = pTblNd->GetTable();
  
  	//Lines fuer das Layout-Update herausuchen.
  	_FndBox aFndBox( 0, 0 );
      aFndBox.SetTableLines( rTbl );
      aFndBox.DelFrms( rTbl );
  
      // TL_CHART2: since chart currently does not want to get informed about
      // additional rows/cols there is no need for a modified event in the
      // remaining first table. Also, if it is required it  should be done
      // after the merging and not here...
      // pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
  
  
      // TL_CHART2:
      // tell the charts about the table to be deleted and have them use their own data
      GetDoc()->CreateChartInternalDataProviders( &rDelTbl );
  
  	// die Breite der TabellenFormate abgleichen:
  	{
  		const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize();
  		const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize();
  		if( rTblSz != rDelTblSz )
  		{
  			// dann sollten die mal schleunigst korrigiert werden
  			if( bWithPrev )
                  rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz );
  			else
                  rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz );
  		}
  	}
  
  	if( !bWithPrev )
  	{
  		// dann mussen alle Attruibute der hinteren Tabelle auf die
  		// vordere uebertragen werden, weil die hintere ueber das loeschen
  		// des Node geloescht wird.
          rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() );
  		rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() );
  
  		rTbl.GetFrmFmt()->LockModify();
  		*rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt();
  		// auch den Namen umsetzen!
  		rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() );
  		rTbl.GetFrmFmt()->UnlockModify();
  	}
  
  	// die Lines und Boxen ruebermoven
  	sal_uInt16 nOldSize = rTbl.GetTabLines().Count();
  	rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize );
  	rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() );
  
  	rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() );
  	rDelTbl.GetTabSortBoxes().Remove( (sal_uInt16)0, rDelTbl.GetTabSortBoxes().Count() );
  
  	// die vordere Tabelle bleibt immer stehen, die hintere wird geloescht
  	SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode();
  	pTblNd->pEndOfSection = pTblEndNd;
  
  	SwNodeIndex aIdx( *pDelTblNd, 1 );
  
  	SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
  	do {
  		ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
  		pBoxNd->pStartOfSection = pTblNd;
  		pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
  	} while( pBoxNd != pTblEndNd );
  	pBoxNd->pStartOfSection = pTblNd;
  
  	aIdx -= 2;
  	DelNodes( aIdx, 2 );
  
  	// jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen
  	const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ];
  	if( 1 == nMode )		//
  	{
  		// Header-Vorlagen in der Zeile setzen
  		// und ggfs. in der History speichern fuers Undo!!!
  	}
  	lcl_LineSetHeadCondColl( pFirstLn, 0 );
  
  	// und die Borders "aufrauemen"
  	if( nOldSize )
  	{
  		_SwGCLineBorder aPara( rTbl );
  		aPara.nLinePos = --nOldSize;
  		pFirstLn = rTbl.GetTabLines()[ nOldSize ];
  		lcl_GC_Line_Border( pFirstLn, &aPara );
  	}
  
  	//Layout updaten
      aFndBox.MakeFrms( rTbl );
  
      return sal_True;
  }
  
  // -------------------------------------------------------------------
  
  
  // -- benutze die ForEach Methode vom PtrArray
  struct _SetAFmtTabPara
  {
  	SwTableAutoFmt& rTblFmt;
  	SwUndoTblAutoFmt* pUndo;
  	sal_uInt16 nEndBox, nCurBox;
  	sal_uInt8 nAFmtLine, nAFmtBox;
  
  	_SetAFmtTabPara( const SwTableAutoFmt& rNew )
  		: rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ),
  		nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 )
  	{}
  };
  
  // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
  // koennen.
  sal_Bool lcl_SetAFmtBox( const _FndBox*&, void *pPara );
  sal_Bool lcl_SetAFmtLine( const _FndLine*&, void *pPara );
  
  sal_Bool lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara )
  {
  	((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara );
  	return sal_True;
  }
  
  sal_Bool lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara )
  {
  	_SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara;
  
  	if( !rpBox->GetUpper()->GetUpper() )	// Box auf 1. Ebene ?
  	{
  		if( !pSetPara->nCurBox )
  			pSetPara->nAFmtBox = 0;
  		else if( pSetPara->nCurBox == pSetPara->nEndBox )
  			pSetPara->nAFmtBox = 3;
  		else
  			pSetPara->nAFmtBox = (sal_uInt8)(1 + ((pSetPara->nCurBox-1) & 1));
  	}
  
  	if( rpBox->GetBox()->GetSttNd() )
  	{
  		SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox();
  		SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc();
          // --> OD 2008-02-25 #refactorlists#
  //        SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
          SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
          // <--
  		SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange );
  		sal_uInt8 nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox;
  		pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet,
  										SwTableAutoFmt::UPDATE_CHAR, 0 );
  		pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet,
  										SwTableAutoFmt::UPDATE_BOX,
  										pDoc->GetNumberFormatter( sal_True ) );
  		if( aCharSet.Count() )
  		{
  			sal_uLong nSttNd = pSetBox->GetSttIdx()+1;
  			sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
  			for( ; nSttNd < nEndNd; ++nSttNd )
  			{
  				SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode();
  				if( pNd )
  					pNd->SetAttr( aCharSet );
  			}
  		}
  
  		if( aBoxSet.Count() )
  		{
  			if( pSetPara->pUndo &&
  				SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT ))
  				pSetPara->pUndo->SaveBoxCntnt( *pSetBox );
  
              pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet );
  		}
  	}
  	else
  		((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara );
  
  	if( !rpBox->GetUpper()->GetUpper() )		// eine BaseLine
  		++pSetPara->nCurBox;
  	return sal_True;
  }
  
  
  		// AutoFormat fuer die Tabelle/TabellenSelection
  sal_Bool SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew )
  {
  	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	// suche alle Boxen / Lines
  	_FndBox aFndBox( 0, 0 );
  	{
  		_FndPara aPara( rBoxes, &aFndBox );
  		pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
  	}
  	if( !aFndBox.GetLines().Count() )
  		return sal_False;
  
  	pTblNd->GetTable().SetHTMLTableLayout( 0 );
  
  	_FndBox* pFndBox = &aFndBox;
  	while( 1 == pFndBox->GetLines().Count() &&
  			1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
  		pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
  
  	if( !pFndBox->GetLines().Count() )		// eine zu weit? (nur 1 sel.Box)
  		pFndBox = pFndBox->GetUpper()->GetUpper();
  
  
  	// Undo abschalten, Attribute werden sich vorher gemerkt
  	SwUndoTblAutoFmt* pUndo = 0;
      bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
      if (bUndo)
      {
          pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew );
          GetIDocumentUndoRedo().AppendUndo(pUndo);
          GetIDocumentUndoRedo().DoUndo(false);
      }
  
  	_SetAFmtTabPara aPara( rNew );
  	_FndLines& rFLns = pFndBox->GetLines();
  	_FndLine* pLine;
  
  	for( sal_uInt16 n = 0; n < rFLns.Count(); ++n )
  	{
  		pLine = rFLns[n];
  
  		// Upper auf 0 setzen (Base-Line simulieren!)
  		_FndBox* pSaveBox = pLine->GetUpper();
  		pLine->SetUpper( 0 );
  
  		if( !n )
  			aPara.nAFmtLine = 0;
  		else if( n+1 == rFLns.Count() )
  			aPara.nAFmtLine = 3;
  		else
  			aPara.nAFmtLine = (sal_uInt8)(1 + ((n-1) & 1 ));
  
  		aPara.nAFmtBox = 0;
  		aPara.nCurBox = 0;
  		aPara.nEndBox = pLine->GetBoxes().Count()-1;
  		aPara.pUndo = pUndo;
  		pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara );
  
  		pLine->SetUpper( pSaveBox );
  	}
  
  	if( pUndo )
      {
          GetIDocumentUndoRedo().DoUndo(bUndo);
      }
  
  	SetModified();
  	SetFieldsDirty( true, NULL, 0 );
  
  	return sal_True;
  }
  
  
  		// Erfrage wie attributiert ist
  sal_Bool SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet )
  {
  	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
  	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
  	if( !pTblNd )
  		return sal_False;
  
  	// suche alle Boxen / Lines
  	_FndBox aFndBox( 0, 0 );
  	{
  		_FndPara aPara( rBoxes, &aFndBox );
  		pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
  	}
  	if( !aFndBox.GetLines().Count() )
  		return sal_False;
  
  	_FndBox* pFndBox = &aFndBox;
  	while( 1 == pFndBox->GetLines().Count() &&
  			1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
  		pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
  
  	if( !pFndBox->GetLines().Count() )		// eine zu weit? (nur 1 sel.Box)
  		pFndBox = pFndBox->GetUpper()->GetUpper();
  
  	_FndLines& rFLns = pFndBox->GetLines();
  
  	sal_uInt16 aLnArr[4];
  	aLnArr[0] = 0;
  	aLnArr[1] = 1 < rFLns.Count() ? 1 : 0;
  	aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1];
  	aLnArr[3] = rFLns.Count() - 1;
  
  	for( sal_uInt8 nLine = 0; nLine < 4; ++nLine )
  	{
  		_FndLine& rLine = *rFLns[ aLnArr[ nLine ] ];
  
  		sal_uInt16 aBoxArr[4];
  		aBoxArr[0] = 0;
  		aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0;
  		aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1];
  		aBoxArr[3] = rLine.GetBoxes().Count() - 1;
  
  		for( sal_uInt8 nBox = 0; nBox < 4; ++nBox )
  		{
  			SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
  			// immer auf die 1. runterfallen
  			while( !pFBox->GetSttNd() )
  				pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
  
  			sal_uInt8 nPos = nLine * 4 + nBox;
  			SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
  			SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
  			if( !pCNd )
  				pCNd = GetNodes().GoNext( &aIdx );
  
  			if( pCNd )
  				rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
  									SwTableAutoFmt::UPDATE_CHAR, 0 );
  			rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(),
  								SwTableAutoFmt::UPDATE_BOX,
  								GetNumberFormatter( sal_True ) );
  		}
  	}
  
  	return sal_True;
  }
  
  String SwDoc::GetUniqueTblName() const
  {
  	ResId aId( STR_TABLE_DEFNAME, *pSwResMgr );
  	String aName( aId );
  	xub_StrLen nNmLen = aName.Len();
  
  	sal_uInt16 nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2;
  	sal_uInt16 n;
  
  	sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
  	memset( pSetFlags, 0, nFlagSize );
  
  	for( n = 0; n < pTblFrmFmtTbl->Count(); ++n )
  	{
  		const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
  		if( !pFmt->IsDefault() && IsUsed( *pFmt )  &&
  			pFmt->GetName().Match( aName ) == nNmLen )
  		{
  			// Nummer bestimmen und das Flag setzen
  			nNum = static_cast<sal_uInt16>(pFmt->GetName().Copy( nNmLen ).ToInt32());
  			if( nNum-- && nNum < pTblFrmFmtTbl->Count() )
  				pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
  		}
  	}
  
  	// alle Nummern entsprechend geflag, also bestimme die richtige Nummer
  	nNum = pTblFrmFmtTbl->Count();
  	for( n = 0; n < nFlagSize; ++n )
  		if( 0xff != ( nTmp = pSetFlags[ n ] ))
  		{
  			// also die Nummer bestimmen
  			nNum = n * 8;
  			while( nTmp & 1 )
  				++nNum, nTmp >>= 1;
  			break;
  		}
  
  	delete [] pSetFlags;
  	return aName += String::CreateFromInt32( ++nNum );
  }
  
  SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, sal_Bool bAll ) const
  {
  	const SwFmt* pRet = 0;
  	if( bAll )
  		pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName );
  	else
  	{
  		// dann nur die, die im Doc gesetzt sind
  		for( sal_uInt16 n = 0; n < pTblFrmFmtTbl->Count(); ++n )
  		{
  			const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
  			if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
  				pFmt->GetName() == rName )
  			{
  				pRet = pFmt;
  				break;
  			}
  		}
  	}
  	return (SwTableFmt*)pRet;
  }
  
  sal_Bool SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, sal_uInt16 eType,
  									SwTwips nAbsDiff, SwTwips nRelDiff )
  {
  	SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode();
  	SwUndo* pUndo = 0;
  
  	if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable ))
  		return sal_False;
  
  	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
  	aMsgHnt.eFlags = TBL_BOXPTR;
  	UpdateTblFlds( &aMsgHnt );
  
      bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
  	sal_Bool bRet = sal_False;
  	switch( eType & 0xff )
  	{
  	case nsTblChgWidthHeightType::WH_COL_LEFT:
  	case nsTblChgWidthHeightType::WH_COL_RIGHT:
  	case nsTblChgWidthHeightType::WH_CELL_LEFT:
  	case nsTblChgWidthHeightType::WH_CELL_RIGHT:
  		{
  			 bRet = pTblNd->GetTable().SetColWidth( rAktBox,
  								eType, nAbsDiff, nRelDiff,
                                  (bUndo) ? &pUndo : 0 );
          }
  		break;
  	case nsTblChgWidthHeightType::WH_ROW_TOP:
  	case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
  	case nsTblChgWidthHeightType::WH_CELL_TOP:
  	case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
  		bRet = pTblNd->GetTable().SetRowHeight( rAktBox,
  							eType, nAbsDiff, nRelDiff,
                              (bUndo) ? &pUndo : 0 );
  		break;
  	}
  
      GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off
  	if( pUndo )
      {
          GetIDocumentUndoRedo().AppendUndo( pUndo );
      }
  
  	if( bRet )
  	{
  		SetModified();
  		if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType )
  			SetFieldsDirty( true, NULL, 0 );
  	}
  	return bRet;
  }
  
  
  void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, sal_Bool bCallUpdate )
  {
  	//JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text
  	//							sein soll, dann bleibt das auch Text!
  	const SfxPoolItem* pNumFmtItem = 0;
  	if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
  		sal_False, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat(
  			((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() ))
  		return ;
  
  	SwUndoTblNumFmt* pUndo = 0;
  
  	sal_Bool bIsEmptyTxtNd, bChgd = sal_True;
  	sal_uInt32 nFmtIdx;
  	double fNumber;
  	if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) )
  	{
  		if( !rBox.IsNumberChanged() )
  			bChgd = sal_False;
  		else
  		{
              if (GetIDocumentUndoRedo().DoesUndo())
              {
                  GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
  				pUndo = new SwUndoTblNumFmt( rBox );
  				pUndo->SetNumFmt( nFmtIdx, fNumber );
  			}
  
  			SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
  			SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
  
  			sal_Bool bSetNumFmt = IsInsTblFormatNum(), bLockModify = sal_True;
  			if( bSetNumFmt )
  			{
  				if( !IsInsTblChangeNumFormat() )
  				{
  					if( !pNumFmtItem )
  						bSetNumFmt = sal_False;
  					else
  					{
  						sal_uLong nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)->
  											GetValue();
  						SvNumberFormatter* pNumFmtr = GetNumberFormatter();
  
  						short nFmtType = pNumFmtr->GetType( nFmtIdx );
  						if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) ||
  							NUMBERFORMAT_NUMBER == nFmtType )
  							// eingstelltes und vorgegebenes NumFormat
  							// stimmen ueberein -> altes Format beibehalten
  							nFmtIdx = nOldNumFmt;
  						else
  							// eingstelltes und vorgegebenes NumFormat
  							// stimmen nicht ueberein -> als Text einfuegen
  							bLockModify = bSetNumFmt = sal_False;
  					}
  				}
  
  				if( bSetNumFmt )
  				{
  					pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
  
  					aBoxSet.Put( SwTblBoxValue( fNumber ));
  					aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
  				}
  			}
  
  			// JP 28.04.98: Nur Formel zuruecksetzen reicht nicht.
  			//				Sorge dafuer, das der Text auch entsprechend
  			//				formatiert wird!
  
  			if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem )
  			{
  				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
  				//				Sorge dafuer, das der Text auch entsprechend
  				//				formatiert wird!
                  pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
  			}
  
  			if( bLockModify ) pBoxFmt->LockModify();
              pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
  			if( bLockModify ) pBoxFmt->UnlockModify();
  
  			if( bSetNumFmt )
                  pBoxFmt->SetFmtAttr( aBoxSet );
  		}
  	}
  	else
  	{
  		// es ist keine Zahl
  		const SfxPoolItem* pValueItem = 0, *pFmtItem = 0;
  		SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
  		if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT,
  				sal_False, &pFmtItem ) ||
  			SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE,
  				sal_False, &pValueItem ))
  		{
              if (GetIDocumentUndoRedo().DoesUndo())
              {
                  GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
  				pUndo = new SwUndoTblNumFmt( rBox );
  			}
  
  			pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
  
  			// alle Zahlenformate entfernen
  			sal_uInt16 nWhich1 = RES_BOXATR_FORMULA;
  			if( !bIsEmptyTxtNd )
  				//JP 15.01.99: dieser Teil wurde doch schon oben abgeprueft!
  				/* && pFmtItem && !GetNumberFormatter()->
  				IsTextFormat( ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ) )*/
  			{
  				nWhich1 = RES_BOXATR_FORMAT;
  
  				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
  				//				Sorge dafuer, das der Text auch entsprechend
  				//				formatiert wird!
                  pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 ));
  			}
              pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
  		}
  		else
  			bChgd = sal_False;
  	}
  
  	if( bChgd )
  	{
  		if( pUndo )
  		{
  			pUndo->SetBox( rBox );
              GetIDocumentUndoRedo().AppendUndo(pUndo);
              GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
          }
  
  		const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode();
  		if( bCallUpdate )
  		{
  			SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() );
  			UpdateTblFlds( &aTblUpdate );
  
  			// TL_CHART2: update charts (when cursor leaves cell and
  			// automatic update is enabled)
  			if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true))
  				pTblNd->GetTable().UpdateCharts();
  		}
  		SetModified();
  	}
  }
  
  void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet )
  {
      if (GetIDocumentUndoRedo().DoesUndo())
      {
          GetIDocumentUndoRedo().AppendUndo( new SwUndoTblNumFmt(rBox, &rSet) );
      }
  
  	SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
  	if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
  	{
  		pBoxFmt->LockModify();
          pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
  		pBoxFmt->UnlockModify();
  	}
  	else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE ))
  	{
  		pBoxFmt->LockModify();
          pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
  		pBoxFmt->UnlockModify();
  	}
      pBoxFmt->SetFmtAttr( rSet );
  	SetModified();
  }
  
  void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode )
  {
  	SwStartNode* pSttNd;
      if( 0 != ( pSttNd = rNode.GetNode().
  								FindSttNodeByType( SwTableBoxStartNode )) &&
  		2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() )
  	{
  		SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
  							GetTblBox( pSttNd->GetIndex() );
  
  		const SfxPoolItem* pFmtItem = 0;
  		const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet();
  		if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pFmtItem ) ||
  			SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, sal_False ) ||
  			SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, sal_False ))
  		{
              if (GetIDocumentUndoRedo().DoesUndo())
              {
                  GetIDocumentUndoRedo().AppendUndo(new SwUndoTblNumFmt(*pBox));
              }
  
  			SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
  
  			//JP 01.09.97: TextFormate bleiben erhalten!
  			sal_uInt16 nWhich1 = RES_BOXATR_FORMAT;
  			if( pFmtItem && GetNumberFormatter()->IsTextFormat(
  					((SwTblBoxNumFormat*)pFmtItem)->GetValue() ))
  				nWhich1 = RES_BOXATR_FORMULA;
  			else
  				// JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
  				//				Sorge dafuer, das der Text auch entsprechend
  				//				formatiert wird!
                  pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
  
              pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
  			SetModified();
  		}
  	}
  }
  
  // kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich
  // selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende
  // mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder
  // in eine bestehende TblSelektion gefuellt wird.
  // Gerufen wird es von: edglss.cxx/fecopy.cxx
  
  sal_Bool SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
  						const SwTable* pCpyTbl, sal_Bool bCpyName, sal_Bool bCorrPos )
  {
  	sal_Bool bRet;
  
  	const SwTableNode* pSrcTblNd = pCpyTbl
  			? pCpyTbl->GetTableNode()
  			: rBoxes[ 0 ]->GetSttNd()->FindTableNode();
  
      SwTableNode * pInsTblNd = rInsPos.nNode.GetNode().FindTableNode();
  
      bool const bUndo( GetIDocumentUndoRedo().DoesUndo() );
  	if( !pCpyTbl && !pInsTblNd )
  	{
  		SwUndoCpyTbl* pUndo = 0;
          if (bUndo)
          {
              GetIDocumentUndoRedo().ClearRedo();
  			pUndo = new SwUndoCpyTbl;
          }
  
          {
              ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
              bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes,
  												sal_True, bCpyName );
          }
  
  		if( pUndo )
  		{
  			if( !bRet )
              {
  				delete pUndo;
                  pUndo = 0;
              }
  			else
  			{
  				pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
  
  				pUndo->SetTableSttIdx( pInsTblNd->GetIndex() );
                  GetIDocumentUndoRedo().AppendUndo( pUndo );
              }
  		}
  	}
  	else
  	{
          RedlineMode_t eOld = GetRedlineMode();
          if( IsRedlineOn() )
  	  SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
  								  nsRedlineMode_t::REDLINE_SHOW_INSERT |
  								  nsRedlineMode_t::REDLINE_SHOW_DELETE));
  
  		SwUndoTblCpyTbl* pUndo = 0;
          if (bUndo)
          {
              GetIDocumentUndoRedo().ClearRedo();
  			pUndo = new SwUndoTblCpyTbl;
              GetIDocumentUndoRedo().DoUndo(false);
          }
  
  		SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc();
  		sal_Bool bDelCpyDoc = pCpyDoc == this;
  
  		if( bDelCpyDoc )
  		{
  			// kopiere die Tabelle erstmal in ein temp. Doc
  			pCpyDoc = new SwDoc;
              pCpyDoc->acquire();
  
  			SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() ));
  			if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, sal_True, sal_True ))
  			{
                  if( pCpyDoc->release() == 0 )
                      delete pCpyDoc;
  
  				if( pUndo )
                  {
                      GetIDocumentUndoRedo().DoUndo(bUndo);
  					delete pUndo;
                      pUndo = 0;
  				}
  				return sal_False;
  			}
  			aPos.nNode -= 1;		// auf den EndNode der Tabelle
  			pSrcTblNd = aPos.nNode.GetNode().FindTableNode();
  		}
  
  		const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
  
  		rInsPos.nContent.Assign( 0, 0 );
  
  		// no complex into complex, but copy into or from new model is welcome
  		if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() )
              && ( bDelCpyDoc || rBoxes.Count() ) )
  		{
  			// dann die Tabelle "relativ" kopieren
  			const SwSelBoxes* pBoxes;
  			SwSelBoxes aBoxes;
  
  			if( bDelCpyDoc )
  			{
  				SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox(
  										pSttNd->GetIndex() );
  				ASSERT( pBox, "Box steht nicht in dieser Tabelle" );
  				aBoxes.Insert( pBox );
  				pBoxes = &aBoxes;
  			}
  			else
  				pBoxes = &rBoxes;
  
  			// kopiere die Tabelle in die selktierten Zellen.
  			bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
  														*pBoxes, pUndo );
  		}
  		else
  		{
  			SwNodeIndex aNdIdx( *pSttNd, 1 );
  			bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
  													aNdIdx, pUndo );
  		}
  
  		if( bDelCpyDoc )
          {
              if( pCpyDoc->release() == 0 )
                  delete pCpyDoc;
          }
  
  		if( pUndo )
  		{
  			// falls die Tabelle nicht kopiert werden konnte, das Undo-Object
  			// wieder loeschen
              GetIDocumentUndoRedo().DoUndo(bUndo);
  			if( !bRet && pUndo->IsEmpty() )
  				delete pUndo;
              else
              {
                  GetIDocumentUndoRedo().AppendUndo(pUndo);
              }
          }
  
  		if( bCorrPos )
  		{
  			rInsPos.nNode = *pSttNd;
  			rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
  		}
          SetRedlineMode( eOld );
  	}
  
  	if( bRet )
  	{
  		SetModified();
  		SetFieldsDirty( true, NULL, 0 );
  	}
  	return bRet;
  }
  
  
  
  sal_Bool SwDoc::_UnProtectTblCells( SwTable& rTbl )
  {
  	sal_Bool bChgd = sal_False;
      SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
          ?   new SwUndoAttrTbl( *rTbl.GetTableNode() )
          :   0;
  
  	SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes();
  	for( sal_uInt16 i = rSrtBox.Count(); i; )
  	{
  		SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
  		if( pBoxFmt->GetProtect().IsCntntProtected() )
  		{
              pBoxFmt->ResetFmtAttr( RES_PROTECT );
  			bChgd = sal_True;
  		}
  	}
  
  	if( pUndo )
  	{
  		if( bChgd )
          {
              GetIDocumentUndoRedo().AppendUndo( pUndo );
          }
          else
  			delete pUndo;
  	}
  	return bChgd;
  }
  
  
  sal_Bool SwDoc::UnProtectCells( const String& rName )
  {
  	sal_Bool bChgd = sal_False;
  	SwTableFmt* pFmt = FindTblFmtByName( rName );
  	if( pFmt )
  	{
  		bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) );
  		if( bChgd )
  			SetModified();
  	}
  
  	return bChgd;
  }
  
  sal_Bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
  {
  	sal_Bool bChgd = sal_False;
  	if( rBoxes.Count() )
      {
          SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
  				? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() )
  				: 0;
  
  		SvPtrarr aFmts( 16 ), aNewFmts( 16 );
  		for( sal_uInt16 i = rBoxes.Count(); i; )
  		{
  			SwTableBox* pBox = rBoxes[ --i ];
  			SwFrmFmt* pBoxFmt = pBox->GetFrmFmt();
  			if( pBoxFmt->GetProtect().IsCntntProtected() )
  			{
  				sal_uInt16 nFnd = aFmts.GetPos( pBoxFmt );
  				if( USHRT_MAX != nFnd )
  					pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] );
  				else
  				{
  					aFmts.Insert( pBoxFmt, aFmts.Count() );
  					pBoxFmt = pBox->ClaimFrmFmt();
                      pBoxFmt->ResetFmtAttr( RES_PROTECT );
  					aNewFmts.Insert( pBoxFmt, aNewFmts.Count() );
  				}
  				bChgd = sal_True;
  			}
  		}
  
  		if( pUndo )
  		{
  			if( bChgd )
              {
                  GetIDocumentUndoRedo().AppendUndo( pUndo );
              }
              else
  				delete pUndo;
  		}
  	}
  	return bChgd;
  }
  
  sal_Bool SwDoc::UnProtectTbls( const SwPaM& rPam )
  {
      GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
  
  	sal_Bool bChgd = sal_False, bHasSel = rPam.HasMark() ||
  									rPam.GetNext() != (SwPaM*)&rPam;
  	SwFrmFmts& rFmts = *GetTblFrmFmts();
  	SwTable* pTbl;
  	const SwTableNode* pTblNd;
  	for( sal_uInt16 n = rFmts.Count(); n ; )
  		if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) &&
  			0 != (pTblNd = pTbl->GetTableNode() ) &&
  			pTblNd->GetNodes().IsDocNodes() )
  		{
  			sal_uLong nTblIdx = pTblNd->GetIndex();
  
  			// dann ueberpruefe ob Tabelle in der Selection liegt
  			if( bHasSel )
  			{
  				int bFound = sal_False;
  				SwPaM* pTmp = (SwPaM*)&rPam;
  				do {
  					const SwPosition *pStt = pTmp->Start(),
  									*pEnd = pTmp->End();
  					bFound = pStt->nNode.GetIndex() < nTblIdx &&
  							nTblIdx < pEnd->nNode.GetIndex();
  
  				} while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) );
  				if( !bFound )
  					continue;		// weitersuchen
  			}
  
  			// dann mal den Schutz aufheben
  			bChgd |= _UnProtectTblCells( *pTbl );
  		}
  
      GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
  	if( bChgd )
  		SetModified();
  
  	return bChgd;
  }
  
  sal_Bool SwDoc::HasTblAnyProtection( const SwPosition* pPos,
  								 const String* pTblName,
  								 sal_Bool* pFullTblProtection )
  {
  	sal_Bool bHasProtection = sal_False;
  	SwTable* pTbl = 0;
  	if( pTblName )
  		pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) );
  	else if( pPos )
  	{
  		SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode();
  		if( pTblNd )
  			pTbl = &pTblNd->GetTable();
  	}
  
  	if( pTbl )
  	{
  		SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes();
  		for( sal_uInt16 i = rSrtBox.Count(); i; )
  		{
  			SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
  			if( pBoxFmt->GetProtect().IsCntntProtected() )
  			{
  				if( !bHasProtection )
  				{
  					bHasProtection = sal_True;
  					if( !pFullTblProtection )
  						break;
  					*pFullTblProtection = sal_True;
  				}
  			}
  			else if( bHasProtection && pFullTblProtection )
  			{
  				*pFullTblProtection = sal_False;
  				break;
  			}
  		}
  	}
  	return bHasProtection;
  }
  
  #ifdef DEL_TABLE_REDLINES
  lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd,
  									sal_Bool bCheckForOwnRedline )
  	: pDoc( (SwDoc*)rNd.GetNodes().GetDoc() )
  {
      pDoc->StartUndo(UNDO_EMPTY, NULL);
  	const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
  	if( !pDoc->IsIgnoreRedline() && rTbl.Count() )
  	{
  		sal_Bool bDelete = sal_True;
  		if( bCheckForOwnRedline )
  		{
  			sal_uInt16 nRedlPos = pDoc->GetRedlinePos( rNd, USHRT_MAX );
  			sal_uInt32 nSttNd = rNd.GetIndex(),
  					   nEndNd = rNd.EndOfSectionIndex();
  
  			for ( ; nRedlPos < rTbl.Count(); ++nRedlPos )
  			{
  				const SwRedline* pRedline = rTbl[ nRedlPos ];
  				const SwPosition* pStt = pRedline->Start(),
  						  		* pEnd = pStt == pRedline->GetPoint()
  						  							? pRedline->GetMark()
  													: pRedline->GetPoint();
  				if( pStt->nNode <= nSttNd )
  				{
  					if( pEnd->nNode >= nEndNd &&
  						pRedline->GetAuthor() == pDoc->GetRedlineAuthor() )
  					{
  						bDelete = sal_False;
  						break;
  					}
  				}
  				else
  					break;
  			}
  		}
  		if( bDelete )
  		{
  			SwPaM aPam(*rNd.EndOfSectionNode(), rNd);
  			pDoc->AcceptRedline( aPam, true );
  		}
  	}
  }
  #endif
  
  
  