/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#include "hintids.hxx"

#include <limits.h>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/table/XCellRange.hpp>
#include <svl/itemset.hxx>
#include <svl/zformat.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <xmloff/xmltkmap.hxx>
#include <xmloff/nmspmap.hxx>

#include <xmloff/families.hxx>
#include <xmloff/xmluconv.hxx>
#include <xmloff/i18nmap.hxx>
#include <editeng/protitem.hxx>
#include "poolfmt.hxx"
#include "fmtfsize.hxx"
#include "fmtornt.hxx"
#include "fmtfordr.hxx"
#include "doc.hxx"
#include "swtable.hxx"
#include "swtblfmt.hxx"
#include "pam.hxx"
#include "unotbl.hxx"
#include "unotextrange.hxx"
#include "unocrsr.hxx"
#include "cellatr.hxx"
#include "swddetbl.hxx"
#include "ddefld.hxx"
#include <sfx2/linkmgr.hxx>  // for cTokenSeparator
#include "xmlimp.hxx"
#include "xmltbli.hxx"

// for locking SolarMutex: svapp + mutex
#include <vcl/svapp.hxx>
#include <vos/mutex.hxx>
#include "ndtxt.hxx"

using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::table;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;
using ::std::hash_map;

enum SwXMLTableElemTokens
{
	XML_TOK_TABLE_HEADER_COLS,
	XML_TOK_TABLE_COLS,
	XML_TOK_TABLE_COL,
	XML_TOK_TABLE_HEADER_ROWS,
	XML_TOK_TABLE_ROWS,
	XML_TOK_TABLE_ROW,
	XML_TOK_OFFICE_DDE_SOURCE,
	XML_TOK_TABLE_ELEM_END=XML_TOK_UNKNOWN
};

enum SwXMLTableCellAttrTokens
{
    XML_TOK_TABLE_XMLID,
	XML_TOK_TABLE_STYLE_NAME,
	XML_TOK_TABLE_NUM_COLS_SPANNED,
	XML_TOK_TABLE_NUM_ROWS_SPANNED,
	XML_TOK_TABLE_NUM_COLS_REPEATED,
	XML_TOK_TABLE_FORMULA,
	XML_TOK_TABLE_VALUE,
	XML_TOK_TABLE_TIME_VALUE,
	XML_TOK_TABLE_DATE_VALUE,
	XML_TOK_TABLE_BOOLEAN_VALUE,
	XML_TOK_TABLE_PROTECTED,
	XML_TOK_TABLE_STRING_VALUE,
	XML_TOK_TABLE_CELL_ATTR_END=XML_TOK_UNKNOWN
};

static __FAR_DATA SvXMLTokenMapEntry aTableElemTokenMap[] =
{
	{ XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS,
			XML_TOK_TABLE_HEADER_COLS },
	{ XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS,			XML_TOK_TABLE_COLS },
	{ XML_NAMESPACE_TABLE, XML_TABLE_COLUMN,			XML_TOK_TABLE_COL },
	{ XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS,
			XML_TOK_TABLE_HEADER_ROWS },
	{ XML_NAMESPACE_TABLE, XML_TABLE_ROWS,				XML_TOK_TABLE_ROWS },
	{ XML_NAMESPACE_TABLE, XML_TABLE_ROW,				XML_TOK_TABLE_ROW },
	{ XML_NAMESPACE_OFFICE, XML_DDE_SOURCE,
			XML_TOK_OFFICE_DDE_SOURCE },

	// There are slight differences between <table:table-columns> and
	// <table:table-columns-groups>. However, none of these are
	// supported in Writer (they are Calc-only features), so we
	// support column groups by simply using the <table:table-columns>
	// token for column groups, too.
	{ XML_NAMESPACE_TABLE, XML_TABLE_COLUMN_GROUP,		XML_TOK_TABLE_COLS },

	XML_TOKEN_MAP_END
};

static __FAR_DATA SvXMLTokenMapEntry aTableCellAttrTokenMap[] =
{
	{ XML_NAMESPACE_XML, XML_ID, XML_TOK_TABLE_XMLID },
	{ XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_STYLE_NAME },
	{ XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_NUM_COLS_SPANNED },
	{ XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_NUM_ROWS_SPANNED },
	{ XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_NUM_COLS_REPEATED },
	{ XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_FORMULA },
	{ XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_TABLE_VALUE },
	{ XML_NAMESPACE_OFFICE, XML_TIME_VALUE, XML_TOK_TABLE_TIME_VALUE },
	{ XML_NAMESPACE_OFFICE, XML_DATE_VALUE, XML_TOK_TABLE_DATE_VALUE },
	{ XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_BOOLEAN_VALUE },
	{ XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED },
	{ XML_NAMESPACE_TABLE, XML_PROTECT, XML_TOK_TABLE_PROTECTED }, // for backwards compatibility with SRC629 (and before)
	{ XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_STRING_VALUE },
	XML_TOKEN_MAP_END
};

const SvXMLTokenMap& SwXMLImport::GetTableElemTokenMap()
{
	if( !pTableElemTokenMap )
		pTableElemTokenMap = new SvXMLTokenMap( aTableElemTokenMap );

	return *pTableElemTokenMap;
}

const SvXMLTokenMap& SwXMLImport::GetTableCellAttrTokenMap()
{
	if( !pTableCellAttrTokenMap )
		pTableCellAttrTokenMap = new SvXMLTokenMap( aTableCellAttrTokenMap );

	return *pTableCellAttrTokenMap;
}

// ---------------------------------------------------------------------

class SwXMLTableCell_Impl
{
	OUString aStyleName;

    OUString mXmlId;

	OUString sFormula;	// cell formula; valid if length > 0
	double dValue;		// formula value

	SvXMLImportContextRef	xSubTable;

	const SwStartNode *pStartNode;
	sal_uInt32 nRowSpan;
	sal_uInt32 nColSpan;

	sal_Bool bProtected : 1;
	sal_Bool bHasValue;	// determines whether dValue attribute is valid
    sal_Bool mbCovered;
    sal_Bool mbTextValue;

public:

	SwXMLTableCell_Impl( sal_uInt32 nRSpan=1UL, sal_uInt32 nCSpan=1UL ) :
		pStartNode( 0 ),
		nRowSpan( nRSpan ),
		nColSpan( nCSpan ),
        bProtected( sal_False ),
        mbCovered( sal_False )
		{}

    inline void Set( const OUString& rStyleName,
					  sal_uInt32 nRSpan, sal_uInt32 nCSpan,
					 const SwStartNode *pStNd, SwXMLTableContext *pTable,
					 sal_Bool bProtect = sal_False,
					 const OUString* pFormula = NULL,
					 sal_Bool bHasValue = sal_False,
                     sal_Bool mbCovered = sal_False,
					 double dVal = 0.0,
					 sal_Bool mbTextValue = sal_False,
                     OUString const& i_rXmlId = OUString());

	sal_Bool IsUsed() const { return pStartNode!=0 ||
									 xSubTable.Is() || bProtected;}

	sal_uInt32 GetRowSpan() const { return nRowSpan; }
	void SetRowSpan( sal_uInt32 nSet ) { nRowSpan = nSet; }
	sal_uInt32 GetColSpan() const { return nColSpan; }
	const OUString& GetStyleName() const { return aStyleName; }
	const OUString& GetFormula() const { return sFormula; }
	double GetValue() const { return dValue; }
	sal_Bool HasValue() const { return bHasValue; }
	sal_Bool IsProtected() const { return bProtected; }
    sal_Bool IsCovered() const { return mbCovered; }
    sal_Bool HasTextValue() const { return mbTextValue; }
	const OUString& GetXmlId() const { return mXmlId; }

	const SwStartNode *GetStartNode() const { return pStartNode; }
    inline void SetStartNode( const SwStartNode *pSttNd );

	inline SwXMLTableContext *GetSubTable() const;

	inline void Dispose();
};

inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
									  sal_uInt32 nRSpan, sal_uInt32 nCSpan,
									  const SwStartNode *pStNd,
									  SwXMLTableContext *pTable,
									  sal_Bool bProtect,
									  const OUString* pFormula,
									  sal_Bool bHasVal,
                                      sal_Bool bCov,
									  double dVal,
									  sal_Bool bTextVal,
                                      OUString const& i_rXmlId )
{
	aStyleName = rStyleName;
	nRowSpan = nRSpan;
	nColSpan = nCSpan;
	pStartNode = pStNd;
	xSubTable = pTable;
	dValue = dVal;
	bHasValue = bHasVal;
    mbCovered = bCov;
	mbTextValue = bTextVal;
	bProtected = bProtect;

    if (!mbCovered) // ensure uniqueness
    {
        mXmlId = i_rXmlId;
    }

	// set formula, if valid
	if (pFormula != NULL)
	{
		sFormula = *pFormula;
	}
}

inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
{
	pStartNode = pSttNd;
	xSubTable = 0;
}

inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
{
	return (SwXMLTableContext *)&xSubTable;
}

inline void SwXMLTableCell_Impl::Dispose()
{
	if( xSubTable.Is() )
		xSubTable = 0;
}

// ---------------------------------------------------------------------

typedef SwXMLTableCell_Impl* SwXMLTableCellPtr;
SV_DECL_PTRARR_DEL(SwXMLTableCells_Impl,SwXMLTableCellPtr,5,5)
SV_IMPL_PTRARR(SwXMLTableCells_Impl,SwXMLTableCellPtr)

class SwXMLTableRow_Impl
{
	OUString aStyleName;
	OUString aDfltCellStyleName;
    OUString mXmlId;

	SwXMLTableCells_Impl aCells;

    sal_Bool bSplitable;

public:

	SwXMLTableRow_Impl( const OUString& rStyleName, sal_uInt32 nCells,
					 	const OUString *pDfltCellStyleName = 0,
                        const OUString& i_rXmlId = OUString() );
	~SwXMLTableRow_Impl() {}

	inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol ) const;

	inline void Set( const OUString& rStyleName,
					 const OUString& rDfltCellStyleName,
                     const OUString& i_rXmlId );

	void Expand( sal_uInt32 nCells, sal_Bool bOneCell );

    void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
    sal_Bool IsSplitable() const { return bSplitable; }

    const OUString& GetStyleName() const { return aStyleName; }
	const OUString& GetDefaultCellStyleName() const { return aDfltCellStyleName; }
	const OUString& GetXmlId() const { return mXmlId; }

	void Dispose();
};

SwXMLTableRow_Impl::SwXMLTableRow_Impl( const OUString& rStyleName,
										sal_uInt32 nCells,
										const OUString *pDfltCellStyleName,
                                        const OUString& i_rXmlId ) :
    aStyleName( rStyleName ),
    mXmlId( i_rXmlId ),
    bSplitable( sal_False )
{
	if( pDfltCellStyleName  )
		aDfltCellStyleName = *pDfltCellStyleName;
	ASSERT( nCells <= USHRT_MAX,
			"SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
	if( nCells > USHRT_MAX )
		nCells = USHRT_MAX;

	for( sal_uInt16 i=0U; i<nCells; i++ )
	{
		aCells.Insert( new SwXMLTableCell_Impl, aCells.Count() );
	}
}

inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol ) const
{
	ASSERT( nCol < USHRT_MAX,
			"SwXMLTableRow_Impl::GetCell: column number is to big" );
    // --> OD 2009-03-19 #i95726# - some fault tolerance
//    return aCells[(sal_uInt16)nCol];
    ASSERT( nCol < aCells.Count(),
            "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
    return nCol < aCells.Count() ? aCells[(sal_uInt16)nCol] : 0;
    // <--
}

void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, sal_Bool bOneCell )
{
	ASSERT( nCells <= USHRT_MAX,
			"SwXMLTableRow_Impl::Expand: too many cells" );
	if( nCells > USHRT_MAX )
		nCells = USHRT_MAX;

	sal_uInt32 nColSpan = nCells - aCells.Count();
	for( sal_uInt16 i=aCells.Count(); i<nCells; i++ )
	{
		aCells.Insert( new SwXMLTableCell_Impl( 1UL,
												bOneCell ? nColSpan : 1UL ),
					   aCells.Count() );
		nColSpan--;
	}

	ASSERT( nCells<=aCells.Count(),
			"SwXMLTableRow_Impl::Expand: wrong number of cells" );
}

inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
                                     const OUString& rDfltCellStyleName,
                                     const OUString& i_rXmlId )
{
	aStyleName = rStyleName;
	aDfltCellStyleName = rDfltCellStyleName;
    mXmlId = i_rXmlId;
}

void SwXMLTableRow_Impl::Dispose()
{
	for( sal_uInt16 i=0; i < aCells.Count(); i++ )
		aCells[i]->Dispose();
}

// ---------------------------------------------------------------------

class SwXMLTableCellContext_Impl : public SvXMLImportContext
{
	OUString aStyleName;
	OUString sFormula;
    OUString sSaveParaDefault;
    OUString mXmlId;

	SvXMLImportContextRef	xMyTable;

	double fValue;
	sal_Bool bHasValue;
	sal_Bool bHasTextValue;
	sal_Bool bProtect;

	sal_uInt32 					nRowSpan;
	sal_uInt32 					nColSpan;
	sal_uInt32 					nColRepeat;

	sal_Bool					bHasTextContent : 1;
	sal_Bool					bHasTableContent : 1;

	SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }

	sal_Bool HasContent() const { return bHasTextContent || bHasTableContent; }
	inline void _InsertContent();
	inline void InsertContent();
	inline void InsertContentIfNotThere();
	inline void InsertContent( SwXMLTableContext *pTable );

public:

	SwXMLTableCellContext_Impl(
			SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
			const Reference< xml::sax::XAttributeList > & xAttrList,
			SwXMLTableContext *pTable );

	virtual ~SwXMLTableCellContext_Impl();

	virtual SvXMLImportContext *CreateChildContext(
			sal_uInt16 nPrefix, const OUString& rLocalName,
			const Reference< xml::sax::XAttributeList > & xAttrList );
	virtual void EndElement();

	SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
};

SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
		SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		SwXMLTableContext *pTable ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	sFormula(),
	xMyTable( pTable ),
	fValue( 0.0 ),
	bHasValue( sal_False ),
	bHasTextValue( sal_False ),
	bProtect( sal_False ),
	nRowSpan( 1UL ),
	nColSpan( 1UL ),
	nColRepeat( 1UL ),
	bHasTextContent( sal_False ),
	bHasTableContent( sal_False )
{
    sSaveParaDefault = GetImport().GetTextImport()->GetCellParaStyleDefault();
	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		const OUString& rValue = xAttrList->getValueByIndex( i );
		const SvXMLTokenMap& rTokenMap =
			GetSwImport().GetTableCellAttrTokenMap();
		switch( rTokenMap.Get( nPrefix, aLocalName ) )
		{
		case XML_TOK_TABLE_XMLID:
			mXmlId = rValue;
			break;
		case XML_TOK_TABLE_STYLE_NAME:
			aStyleName = rValue;
            GetImport().GetTextImport()->SetCellParaStyleDefault(rValue);
			break;
		case XML_TOK_TABLE_NUM_COLS_SPANNED:
			nColSpan = (sal_uInt32)rValue.toInt32();
			if( nColSpan < 1UL )
				nColSpan = 1UL;
			break;
		case XML_TOK_TABLE_NUM_ROWS_SPANNED:
			nRowSpan = (sal_uInt32)rValue.toInt32();
			if( nRowSpan < 1UL )
				nRowSpan = 1UL;
			break;
		case XML_TOK_TABLE_NUM_COLS_REPEATED:
			nColRepeat = (sal_uInt32)rValue.toInt32();
			if( nColRepeat < 1UL )
				nColRepeat = 1UL;
			break;
		case XML_TOK_TABLE_FORMULA:
			{
				OUString sTmp;
				sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
						_GetKeyByAttrName( rValue, &sTmp, sal_False );
				sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : rValue;
			}
			break;
		case XML_TOK_TABLE_VALUE:
			{
				double fTmp;
				if (SvXMLUnitConverter::convertDouble(fTmp, rValue))
				{
					fValue = fTmp;
					bHasValue = sal_True;
				}
			}
			break;
		case XML_TOK_TABLE_TIME_VALUE:
			{
				double fTmp;
				if (SvXMLUnitConverter::convertTime(fTmp, rValue))
				{
					fValue = fTmp;
					bHasValue = sal_True;
				}
			}
			break;
		case XML_TOK_TABLE_DATE_VALUE:
			{
				double fTmp;
				if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
																	  rValue))
				{
					fValue = fTmp;
					bHasValue = sal_True;
				}
			}
			break;
		case XML_TOK_TABLE_BOOLEAN_VALUE:
			{
				sal_Bool bTmp;
				if (SvXMLUnitConverter::convertBool(bTmp, rValue))
				{
					fValue = (bTmp ? 1.0 : 0.0);
					bHasValue = sal_True;
				}
			}
			break;
		case XML_TOK_TABLE_PROTECTED:
			{
				sal_Bool bTmp;
				if (SvXMLUnitConverter::convertBool(bTmp, rValue))
				{
					bProtect = bTmp;
				}
			}
			break;
		case XML_TOK_TABLE_STRING_VALUE:
			{
				bHasTextValue = sal_True;
			}
			break;
		}
	}
}

SwXMLTableCellContext_Impl::~SwXMLTableCellContext_Impl()
{
}

inline void SwXMLTableCellContext_Impl::_InsertContent()
{
	GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan,
							GetTable()->InsertTableSection(),
                            mXmlId,
							NULL, bProtect, &sFormula, bHasValue, fValue, bHasTextValue );
}

inline void SwXMLTableCellContext_Impl::InsertContent()
{
	ASSERT( !HasContent(), "content already there" );
	bHasTextContent = sal_True;
	_InsertContent();
}

inline void SwXMLTableCellContext_Impl::InsertContentIfNotThere()
{
	if( !HasContent() )
		InsertContent();
}

inline void SwXMLTableCellContext_Impl::InsertContent(
												SwXMLTableContext *pTable )
{
	GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan, 0, mXmlId, pTable, bProtect );
	bHasTableContent = sal_True;
}

SvXMLImportContext *SwXMLTableCellContext_Impl::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

    OUString sXmlId;
	sal_Bool bSubTable = sal_False;
	if( XML_NAMESPACE_TABLE == nPrefix &&
        IsXMLToken( rLocalName, XML_TABLE ) )
	{
        sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
		for( sal_Int16 i=0; i < nAttrCount; i++ )
		{
			const OUString& rAttrName = xAttrList->getNameByIndex( i );

			OUString aLocalName;
			sal_uInt16 nPrefix2 =
				GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
																&aLocalName );
			if( XML_NAMESPACE_TABLE == nPrefix2 &&
			 	IsXMLToken( aLocalName, XML_IS_SUB_TABLE ) &&
			 	IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) )
            {
				bSubTable = sal_True;
            }
            else if ( (XML_NAMESPACE_XML == nPrefix2) &&
                     IsXMLToken( aLocalName, XML_ID ) )
            {
                sXmlId = xAttrList->getValueByIndex( i );
            }
//FIXME: RDFa
		}
	}

	if( bSubTable )
	{
		if( !HasContent() )
		{
			SwXMLTableContext *pTblContext =
				new SwXMLTableContext( GetSwImport(), nPrefix, rLocalName,
									   xAttrList, GetTable(), sXmlId );
			pContext = pTblContext;
			if( GetTable()->IsValid() )
				InsertContent( pTblContext );

            GetTable()->SetHasSubTables( sal_True );
		}
	}
	else
	{
		if( GetTable()->IsValid() )
			InsertContentIfNotThere();
		pContext = GetImport().GetTextImport()->CreateTextChildContext(
						GetImport(), nPrefix, rLocalName, xAttrList,
						XML_TEXT_TYPE_CELL  );
	}

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

void SwXMLTableCellContext_Impl::EndElement()
{
	if( GetTable()->IsValid() )
	{
        if( bHasTextContent )
		{
			GetImport().GetTextImport()->DeleteParagraph();
			if( nColRepeat > 1 && nColSpan == 1 )
			{
				// The original text is invalid after deleting the last
				// paragraph
				Reference < XTextCursor > xSrcTxtCursor =
					GetImport().GetTextImport()->GetText()->createTextCursor();
				xSrcTxtCursor->gotoEnd( sal_True );

				// Until we have an API for copying we have to use the core.
				Reference<XUnoTunnel> xSrcCrsrTunnel( xSrcTxtCursor, UNO_QUERY);
				ASSERT( xSrcCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
				OTextCursorHelper *pSrcTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
						sal::static_int_cast< sal_IntPtr >( xSrcCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
				ASSERT( pSrcTxtCrsr, "SwXTextCursor missing" );
				SwDoc *pDoc = pSrcTxtCrsr->GetDoc();
				const SwPaM *pSrcPaM = pSrcTxtCrsr->GetPaM();

				while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
				{
					_InsertContent();

					Reference<XUnoTunnel> xDstCrsrTunnel(
						GetImport().GetTextImport()->GetCursor(), UNO_QUERY);
					ASSERT( xDstCrsrTunnel.is(),
							"missing XUnoTunnel for Cursor" );
					OTextCursorHelper *pDstTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
							sal::static_int_cast< sal_IntPtr >( xDstCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )) );
					ASSERT( pDstTxtCrsr, "SwXTextCursor missing" );
					SwPaM aSrcPaM( *pSrcPaM->GetPoint(),
								   *pSrcPaM->GetMark() );
					SwPosition aDstPos( *pDstTxtCrsr->GetPaM()->GetPoint() );
                    pDoc->CopyRange( aSrcPaM, aDstPos, false );

					nColRepeat--;
				}
			}
		}
		else if( !bHasTableContent )
		{
			InsertContent();
			if( nColRepeat > 1 && nColSpan == 1 )
			{
				while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
				{
					_InsertContent();
					nColRepeat--;
				}
			}
		}
	}
    GetImport().GetTextImport()->SetCellParaStyleDefault(sSaveParaDefault);
}

// ---------------------------------------------------------------------

class SwXMLTableColContext_Impl : public SvXMLImportContext
{
	SvXMLImportContextRef	xMyTable;

	SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }

public:

	SwXMLTableColContext_Impl(
			SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
			const Reference< xml::sax::XAttributeList > & xAttrList,
			SwXMLTableContext *pTable );

	virtual ~SwXMLTableColContext_Impl();

	SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
};

SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
		SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		SwXMLTableContext *pTable ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	xMyTable( pTable )
{
	sal_uInt32 nColRep = 1UL;
	OUString aStyleName, aDfltCellStyleName;

	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		const OUString& rValue = xAttrList->getValueByIndex( i );
		if( XML_NAMESPACE_TABLE == nPrefix )
		{
			if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
				aStyleName = rValue;
			else if( IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
				nColRep = (sal_uInt32)rValue.toInt32();
			else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
				aDfltCellStyleName = rValue;
		}
        else if ( (XML_NAMESPACE_XML == nPrefix) &&
                 IsXMLToken( aLocalName, XML_ID ) )
        {
            (void) rValue;
//FIXME where to put this??? columns do not actually exist in writer...
        }
	}

	sal_Int32 nWidth = MINLAY;
	sal_Bool bRelWidth = sal_True;
	if( aStyleName.getLength() )
	{
		const SfxPoolItem *pItem;
		const SfxItemSet *pAutoItemSet = 0;
		if( GetSwImport().FindAutomaticStyle(
					XML_STYLE_FAMILY_TABLE_COLUMN,
											  aStyleName, &pAutoItemSet ) &&
			pAutoItemSet &&
			SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
														&pItem ) )
		{
			const SwFmtFrmSize *pSize = ((const SwFmtFrmSize *)pItem);
			nWidth = pSize->GetWidth();
            bRelWidth = ATT_VAR_SIZE == pSize->GetHeightSizeType();
		}
	}

	if( nWidth )
	{
		while( nColRep-- && GetTable()->IsInsertColPossible() )
			GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
	}
}

SwXMLTableColContext_Impl::~SwXMLTableColContext_Impl()
{
}

// ---------------------------------------------------------------------

class SwXMLTableColsContext_Impl : public SvXMLImportContext
{
	SvXMLImportContextRef	xMyTable;
	sal_Bool bHeader;

	SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }

public:

	SwXMLTableColsContext_Impl(
			SwXMLImport& rImport, sal_uInt16 nPrfx,
			const OUString& rLName,
			const Reference< xml::sax::XAttributeList > & xAttrList,
			SwXMLTableContext *pTable,
			sal_Bool bHead );

	virtual ~SwXMLTableColsContext_Impl();

	virtual SvXMLImportContext *CreateChildContext(
			sal_uInt16 nPrefix, const OUString& rLocalName,
			const Reference< xml::sax::XAttributeList > & xAttrList );

	SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
};

SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
		SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
        const Reference< xml::sax::XAttributeList > &,
		SwXMLTableContext *pTable, sal_Bool bHead ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	xMyTable( pTable ),
	bHeader( bHead )
{
}

SwXMLTableColsContext_Impl::~SwXMLTableColsContext_Impl()
{
}

SvXMLImportContext *SwXMLTableColsContext_Impl::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	if( XML_NAMESPACE_TABLE == nPrefix &&
		IsXMLToken( rLocalName, XML_TABLE_COLUMN ) &&
		GetTable()->IsInsertColPossible() )
		pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
												  rLocalName, xAttrList,
												  GetTable() );

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

// ---------------------------------------------------------------------

class SwXMLTableRowContext_Impl : public SvXMLImportContext
{
	SvXMLImportContextRef	xMyTable;

	sal_uInt32 					nRowRepeat;

	SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }

public:

	SwXMLTableRowContext_Impl(
			SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
			const Reference< xml::sax::XAttributeList > & xAttrList,
			SwXMLTableContext *pTable, sal_Bool bInHead=sal_False );

	virtual ~SwXMLTableRowContext_Impl();

	virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
			const OUString& rLocalName,
			const Reference< xml::sax::XAttributeList > & xAttrList );

	virtual void EndElement();

	SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
};

SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
		sal_uInt16 nPrfx,
		const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList,
		SwXMLTableContext *pTable,
		sal_Bool bInHead ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	xMyTable( pTable ),
	nRowRepeat( 1 )
{
	OUString aStyleName, aDfltCellStyleName;
    OUString sXmlId;

	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		const OUString& rValue = xAttrList->getValueByIndex( i );
		if( XML_NAMESPACE_TABLE == nPrefix )
		{
			if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
			{
				aStyleName = rValue;
			}
			else if( IsXMLToken( aLocalName, XML_NUMBER_ROWS_REPEATED ) )
			{
				nRowRepeat = (sal_uInt32)rValue.toInt32();
				if( nRowRepeat < 1UL )
					nRowRepeat = 1UL;
			}
			else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
			{
				aDfltCellStyleName = rValue;
			}
		}
        else if ( (XML_NAMESPACE_XML == nPrefix) &&
                 IsXMLToken( aLocalName, XML_ID ) )
        {
            sXmlId = rValue;
        }
	}
	if( GetTable()->IsValid() )
		GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead,
                               sXmlId );
}

void SwXMLTableRowContext_Impl::EndElement()
{
	if( GetTable()->IsValid() )
	{
		GetTable()->FinishRow();

		if( nRowRepeat > 1UL )
			GetTable()->InsertRepRows( nRowRepeat );
	}
}

SwXMLTableRowContext_Impl::~SwXMLTableRowContext_Impl()
{
}

SvXMLImportContext *SwXMLTableRowContext_Impl::CreateChildContext(
		sal_uInt16 nPrefix, const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	if( XML_NAMESPACE_TABLE == nPrefix )
	{
		if( IsXMLToken( rLocalName, XML_TABLE_CELL ) )
		{
			if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
				pContext = new SwXMLTableCellContext_Impl( GetSwImport(),
														   nPrefix,
														   rLocalName,
														   xAttrList,
														   GetTable() );
		}
		else if( IsXMLToken( rLocalName, XML_COVERED_TABLE_CELL ) )
			pContext = new SvXMLImportContext( GetImport(), nPrefix,
											   rLocalName );
	}

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

// ---------------------------------------------------------------------

class SwXMLTableRowsContext_Impl : public SvXMLImportContext
{
	SvXMLImportContextRef	xMyTable;

	sal_Bool bHeader;

	SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }

public:

	SwXMLTableRowsContext_Impl( SwXMLImport& rImport, sal_uInt16 nPrfx,
		    const OUString& rLName,
		    const Reference< xml::sax::XAttributeList > & xAttrList,
			SwXMLTableContext *pTable,
		    sal_Bool bHead );

	virtual ~SwXMLTableRowsContext_Impl();

	virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
			const OUString& rLocalName,
			const Reference< xml::sax::XAttributeList > & xAttrList );

	SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
};

SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
		sal_uInt16 nPrfx,
		const OUString& rLName,
        const Reference< xml::sax::XAttributeList > &,
		SwXMLTableContext *pTable,
		sal_Bool bHead ) :
	SvXMLImportContext( rImport, nPrfx, rLName ),
	xMyTable( pTable ),
	bHeader( bHead )
{
}

SwXMLTableRowsContext_Impl::~SwXMLTableRowsContext_Impl()
{
}

SvXMLImportContext *SwXMLTableRowsContext_Impl::CreateChildContext(
		sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	if( XML_NAMESPACE_TABLE == nPrefix &&
		IsXMLToken( rLocalName, XML_TABLE_ROW ) &&
		GetTable()->IsInsertRowPossible() )
		pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
												  rLocalName, xAttrList,
												  GetTable(),
												  bHeader );

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

// ---------------------------------------------------------------------

class SwXMLDDETableContext_Impl : public SvXMLImportContext
{
	OUString sConnectionName;
	OUString sDDEApplication;
	OUString sDDEItem;
	OUString sDDETopic;
	sal_Bool bIsAutomaticUpdate;

public:

	TYPEINFO();

	SwXMLDDETableContext_Impl(
		SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName);

	~SwXMLDDETableContext_Impl();

	virtual void StartElement(
		const Reference<xml::sax::XAttributeList> & xAttrList);

	OUString& GetConnectionName()	{ return sConnectionName; }
	OUString& GetDDEApplication()	{ return sDDEApplication; }
	OUString& GetDDEItem() 			{ return sDDEItem; }
	OUString& GetDDETopic()			{ return sDDETopic; }
	sal_Bool GetIsAutomaticUpdate()	{ return bIsAutomaticUpdate; }
};

TYPEINIT1( SwXMLDDETableContext_Impl, SvXMLImportContext );

SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(
	SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName) :
		SvXMLImportContext(rImport, nPrfx, rLName),
		sConnectionName(),
		sDDEApplication(),
		sDDEItem(),
		sDDETopic(),
		bIsAutomaticUpdate(sal_False)
{
}

SwXMLDDETableContext_Impl::~SwXMLDDETableContext_Impl()
{
}

void SwXMLDDETableContext_Impl::StartElement(
	const Reference<xml::sax::XAttributeList> & xAttrList)
{
	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i = 0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		const OUString& rValue = xAttrList->getValueByIndex( i );

		if (XML_NAMESPACE_OFFICE == nPrefix)
		{
			if ( IsXMLToken( aLocalName, XML_DDE_APPLICATION ) )
			{
				sDDEApplication = rValue;
			}
			else if ( IsXMLToken( aLocalName, XML_DDE_TOPIC ) )
			{
				sDDETopic = rValue;
			}
			else if ( IsXMLToken( aLocalName, XML_DDE_ITEM ) )
			{
				sDDEItem = rValue;
			}
			else if ( IsXMLToken( aLocalName, XML_NAME ) )
			{
				sConnectionName = rValue;
			}
			else if ( IsXMLToken( aLocalName, XML_AUTOMATIC_UPDATE ) )
			{
				sal_Bool bTmp;
				if (SvXMLUnitConverter::convertBool(bTmp, rValue))
				{
					bIsAutomaticUpdate = bTmp;
				}
			}
			// else: unknown attribute
		}
		// else: unknown attribute namespace
	}
}

// generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
String lcl_GenerateFldTypeName(OUString sPrefix, SwTableNode* pTableNode)
{
	String sPrefixStr(sPrefix);

	if (sPrefixStr.Len() == 0)
	{
		sPrefixStr = String('_');
	}
// 	else if (sPrefixStr.Copy(0, 1).IsAlphaAscii())
// 	{
// 		sPrefixStr.Insert('_', 0);
// 	}
	// else: name is OK.

	// increase count until we find a name that is not yet taken
	String sName;
	sal_Int32 nCount = 0;
	do
	{
		// this is crazy, but just in case all names are taken: exit gracefully
		if (nCount < 0)
			return sName;

		nCount++;
		sName = sPrefixStr;
		sName += String::CreateFromInt32(nCount);

	}
	while (NULL != pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false));

	return sName;
}

// set table properties
SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
									SwTableNode* pTableNode)
{
	// make command string
	String sCommand(pContext->GetDDEApplication());
    sCommand += sfx2::cTokenSeperator;
	sCommand += String(pContext->GetDDEItem());
    sCommand += sfx2::cTokenSeperator;
	sCommand += String(pContext->GetDDETopic());

    sal_uInt16 nType = static_cast< sal_uInt16 >(pContext->GetIsAutomaticUpdate() ? sfx2::LINKUPDATE_ALWAYS
                                                        : sfx2::LINKUPDATE_ONCALL);

	String sName(pContext->GetConnectionName());

	// field type to be returned
	SwDDEFieldType* pType = NULL;

	// valid name?
	if (sName.Len() == 0)
	{
		sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
										pTableNode);
	}
	else
	{
		// check for existing DDE field type with the same name
		SwDDEFieldType* pOldType = (SwDDEFieldType*)pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false);
		if (NULL != pOldType)
		{
			// same values -> return old type
			if ( (pOldType->GetCmd() == sCommand) &&
				 (pOldType->GetType() == nType) )
			{
				// same name, same values -> return old type!
				pType = pOldType;
			}
			else
			{
				// same name, different values -> think of new name
				sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
												pTableNode);
			}
		}
		// no old type -> create new one
	}

	// create new field type (unless we already have one)
	if (NULL == pType)
	{
		// create new field type and return
		SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
		pType = (SwDDEFieldType*)pTableNode->
			GetDoc()->InsertFldType(aDDEFieldType);
	}

	DBG_ASSERT(NULL != pType, "We really want a SwDDEFieldType here!");
	return pType;
}


// ---------------------------------------------------------------------

class TableBoxIndex
{
public:
    OUString msName;
    sal_Int32 mnWidth;
    sal_Bool mbProtected;

    TableBoxIndex( const OUString& rName, sal_Int32 nWidth,
                   sal_Bool bProtected ) :
        msName( rName ),
        mnWidth( nWidth ),
        mbProtected( bProtected )
    { }

    bool operator== ( const TableBoxIndex& rArg ) const
    {
        return (rArg.mnWidth == mnWidth) &&
            (rArg.mbProtected == mbProtected) &&
            (rArg.msName == msName);
    }
};

class TableBoxIndexHasher
{
public:
    size_t operator() (const TableBoxIndex& rArg) const
    {
        return rArg.msName.hashCode() + rArg.mnWidth + rArg.mbProtected;
    }
};




typedef SwXMLTableRow_Impl* SwXMLTableRowPtr;
SV_DECL_PTRARR_DEL(SwXMLTableRows_Impl,SwXMLTableRowPtr,5,5)
SV_IMPL_PTRARR(SwXMLTableRows_Impl,SwXMLTableRowPtr)

SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
												 sal_uInt32 nCol ) const
{
	return (*pRows)[(sal_uInt16)nRow]->GetCell( (sal_uInt16)nCol );
}

TYPEINIT1( SwXMLTableContext, XMLTextTableContext );

SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
		sal_uInt16 nPrfx,
		const OUString& rLName,
		const Reference< xml::sax::XAttributeList > & xAttrList ) :
	XMLTextTableContext( rImport, nPrfx, rLName ),
	pColumnDefaultCellStyleNames( 0 ),
	pRows( new SwXMLTableRows_Impl ),
	pTableNode( 0 ),
	pBox1( 0 ),
	pSttNd1( 0 ),
	pBoxFmt( 0 ),
	pLineFmt( 0 ),
    pSharedBoxFormats(NULL),
	pDDESource(NULL),
	bFirstSection( sal_True ),
	bRelWidth( sal_True ),
    bHasSubTables( sal_False ),
	nHeaderRows( 0 ),
	nCurRow( 0UL ),
	nCurCol( 0UL ),
	nWidth( 0UL )
{
	OUString aName;
    OUString sXmlId;

    // this method will modify the document directly -> lock SolarMutex
    vos::OGuard aGuard(Application::GetSolarMutex());

	sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
	for( sal_Int16 i=0; i < nAttrCount; i++ )
	{
		const OUString& rAttrName = xAttrList->getNameByIndex( i );

		OUString aLocalName;
		sal_uInt16 nPrefix =
			GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
															&aLocalName );
		const OUString& rValue = xAttrList->getValueByIndex( i );
		if( XML_NAMESPACE_TABLE == nPrefix )
		{
			if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
				aStyleName = rValue;
			else if( IsXMLToken( aLocalName, XML_NAME ) )
				aName = rValue;
			else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
				aDfltCellStyleName = rValue;
		}
        else if ( (XML_NAMESPACE_XML == nPrefix) &&
                 IsXMLToken( aLocalName, XML_ID ) )
        {
            sXmlId = rValue;
        }
	}

	SwDoc *pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );

	String sTblName;
	if( aName.getLength() )
	{
		const SwTableFmt *pTblFmt = pDoc->FindTblFmtByName( aName );
		if( !pTblFmt )
			sTblName = aName;
	}
	if( !sTblName.Len() )
	{
		sTblName = pDoc->GetUniqueTblName();
		GetImport().GetTextImport()
			->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTblName );
	}

	Reference< XTextTable > xTable;
	const SwXTextTable *pXTable = 0;
	Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
											  UNO_QUERY );
	ASSERT( xFactory.is(), "factory missing" );
	if( xFactory.is() )
	{
		OUString sService(
				RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextTable" ) );
		Reference<XInterface> xIfc = xFactory->createInstance( sService );
		ASSERT( xIfc.is(), "Couldn't create a table" );

		if( xIfc.is() )
			xTable = Reference< XTextTable > ( xIfc, UNO_QUERY );
	}

	if( xTable.is() )
	{
		xTable->initialize( 1, 1 );

		try
		{
			xTextContent = Reference< XTextContent >( xTable, UNO_QUERY );
			GetImport().GetTextImport()->InsertTextContent( xTextContent );
		}
		catch( IllegalArgumentException& )
		{
			xTable = 0;
		}
	}

	if( xTable.is() )
	{
//FIXME
        // xml:id for RDF metadata
        GetImport().SetXmlId(xTable, sXmlId);

		Reference<XUnoTunnel> xTableTunnel( xTable, UNO_QUERY);
		if( xTableTunnel.is() )
		{
			pXTable = reinterpret_cast< SwXTextTable * >(
					sal::static_int_cast< sal_IntPtr >( xTableTunnel->getSomething( SwXTextTable::getUnoTunnelId() )));
			ASSERT( pXTable, "SwXTextTable missing" );
		}

		Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
		Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
		Reference < XText> xText( xCell, UNO_QUERY );
		xOldCursor = GetImport().GetTextImport()->GetCursor();
		GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );

		// take care of open redlines for tables
		GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_True);
	}
	if( pXTable )
	{
		SwFrmFmt *pTblFrmFmt = pXTable->GetFrmFmt();
		ASSERT( pTblFrmFmt, "table format missing" );
		SwTable *pTbl = SwTable::FindTable( pTblFrmFmt );
		ASSERT( pTbl, "table missing" );
		pTableNode = pTbl->GetTableNode();
		ASSERT( pTableNode, "table node missing" );

		pTblFrmFmt->SetName( sTblName );

		SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
		pBox1 = pLine1->GetTabBoxes()[0U];
		pSttNd1 = pBox1->GetSttNd();
	}
}

SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
		sal_uInt16 nPrfx,
		const OUString& rLName,
        const Reference< xml::sax::XAttributeList > &,
		SwXMLTableContext *pTable,
        OUString const & i_rXmlId ) :
	XMLTextTableContext( rImport, nPrfx, rLName ),
    mXmlId( i_rXmlId ),
	pColumnDefaultCellStyleNames( 0 ),
	pRows( new SwXMLTableRows_Impl ),
	pTableNode( pTable->pTableNode ),
	pBox1( 0 ),
	pSttNd1( 0 ),
	pBoxFmt( 0 ),
	pLineFmt( 0 ),
    pSharedBoxFormats(NULL),
	xParentTable( pTable ),
	pDDESource(NULL),
	bFirstSection( sal_False ),
	bRelWidth( sal_True ),
	bHasSubTables( sal_False ),
	nHeaderRows( 0 ),
	nCurRow( 0UL ),
	nCurCol( 0UL ),
	nWidth( 0UL )
{
}

SwXMLTableContext::~SwXMLTableContext()
{
	delete pColumnDefaultCellStyleNames;
    delete pSharedBoxFormats;
    delete pRows;

    // close redlines on table end nodes
    GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_False);
}

SvXMLImportContext *SwXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
		const OUString& rLocalName,
		const Reference< xml::sax::XAttributeList > & xAttrList )
{
	SvXMLImportContext *pContext = 0;

	const SvXMLTokenMap& rTokenMap = GetSwImport().GetTableElemTokenMap();
	sal_Bool bHeader = sal_False;
	switch( rTokenMap.Get( nPrefix, rLocalName ) )
	{
	case XML_TOK_TABLE_HEADER_COLS:
		bHeader = sal_True;
	case XML_TOK_TABLE_COLS:
		if( IsValid() )
			pContext = new SwXMLTableColsContext_Impl( GetSwImport(), nPrefix,
													   rLocalName, xAttrList,
													   this, bHeader );
		break;
	case XML_TOK_TABLE_COL:
		if( IsValid() && IsInsertColPossible() )
			pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
													  rLocalName, xAttrList,
													  this );
		break;
	case XML_TOK_TABLE_HEADER_ROWS:
		bHeader = sal_True;
	case XML_TOK_TABLE_ROWS:
		pContext = new SwXMLTableRowsContext_Impl( GetSwImport(), nPrefix,
												   rLocalName, xAttrList,
												   this, bHeader );
		break;
	case XML_TOK_TABLE_ROW:
		if( IsInsertRowPossible() )
			pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
													  rLocalName, xAttrList,
													  this );
		break;
	case XML_TOK_OFFICE_DDE_SOURCE:
		// save context for later processing (discard old context, if approp.)
		if( IsValid() )
		{
			if (pDDESource != NULL)
			{
				pDDESource->ReleaseRef();
			}
			pDDESource = new SwXMLDDETableContext_Impl( GetSwImport(), nPrefix,
														rLocalName );
			pDDESource->AddRef();
			pContext = pDDESource;
		}
		break;
	}

	if( !pContext )
		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );

	return pContext;
}

void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, sal_Bool bRelWidth2,
								   	  const OUString *pDfltCellStyleName )
{
	ASSERT( nCurCol < USHRT_MAX,
			"SwXMLTableContext::InsertColumn: no space left" );
	if( nCurCol >= USHRT_MAX )
		return;

	if( nWidth2 < MINLAY )
		nWidth2 = MINLAY;
	else if( nWidth2 > USHRT_MAX )
		nWidth2 = USHRT_MAX;
	aColumnWidths.Insert( (sal_uInt16)nWidth2, aColumnWidths.Count() );
	aColumnRelWidths.push_back( bRelWidth2 );
	if( (pDfltCellStyleName && pDfltCellStyleName->getLength() > 0) ||
		pColumnDefaultCellStyleNames )
	{
		if( !pColumnDefaultCellStyleNames )
		{
			pColumnDefaultCellStyleNames = new SvStringsDtor;
			size_t nCount = aColumnRelWidths.size() - 1;
			while( nCount-- )
				pColumnDefaultCellStyleNames->Insert( new String,
					pColumnDefaultCellStyleNames->Count() );
		}

		pColumnDefaultCellStyleNames->Insert(
			pDfltCellStyleName ? new String( *pDfltCellStyleName ) : new String,
			pColumnDefaultCellStyleNames->Count() );
	}
}

sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
											 sal_uInt32 nColSpan ) const
{
	sal_uInt32 nLast = nCol+nColSpan;
	if( nLast > aColumnWidths.Count() )
		nLast = aColumnWidths.Count();

	sal_Int32 nWidth2 = 0L;
	for( sal_uInt16 i=(sal_uInt16)nCol; i < nLast; i++ )
		nWidth2 += aColumnWidths[i];

	return nWidth2;
}

OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
{
	OUString sRet;
	if( pColumnDefaultCellStyleNames )
		sRet =  *(*pColumnDefaultCellStyleNames)[(sal_uInt16)nCol];

	return sRet;
}

void SwXMLTableContext::InsertCell( const OUString& rStyleName,
									sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
									const SwStartNode *pStartNode,
                                    const OUString & i_rXmlId,
									SwXMLTableContext *pTable,
									sal_Bool bProtect,
									const OUString* pFormula,
									sal_Bool bHasValue,
									double fValue,
									sal_Bool bTextValue )
{
	ASSERT( nCurCol < GetColumnCount(),
			"SwXMLTableContext::InsertCell: row is full" );
	ASSERT( nCurRow < USHRT_MAX,
			"SwXMLTableContext::InsertCell: table is full" );
	if( nCurCol >= USHRT_MAX || nCurRow > USHRT_MAX )
		return;

	ASSERT( nRowSpan >=1UL, "SwXMLTableContext::InsertCell: row span is 0" );
	if( 0UL == nRowSpan )
		nRowSpan = 1UL;
	ASSERT( nColSpan >=1UL, "SwXMLTableContext::InsertCell: col span is 0" );
	if( 0UL == nColSpan )
		nColSpan = 1UL;

	sal_uInt32 i, j;

	// Until it is possible to add columns here, fix the column span.
	sal_uInt32 nColsReq = nCurCol + nColSpan;
	if( nColsReq > GetColumnCount() )
	{
		nColSpan = GetColumnCount() - nCurCol;
		nColsReq = GetColumnCount();
	}

	// Check whether there are cells from a previous line already that reach
	// into the current row.
	if( nCurRow > 0UL && nColSpan > 1UL )
	{
		SwXMLTableRow_Impl *pCurRow = (*pRows)[(sal_uInt16)nCurRow];
		sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
													 : nColsReq;
		for( i=nCurCol+1UL; i<nLastCol; i++ )
		{
			if( pCurRow->GetCell(i)->IsUsed() )
			{
				// If this cell is used, the column span is truncated
				nColSpan = i - nCurCol;
				nColsReq = i;
				break;
			}
		}
	}

	sal_uInt32 nRowsReq = nCurRow + nRowSpan;
	if( nRowsReq > USHRT_MAX )
	{
		nRowSpan = USHRT_MAX - nCurRow;
		nRowsReq = USHRT_MAX;
	}

	// Add columns (if # required columns greater than # columns):
    // This should never happen, since we require column definitions!
    if ( nColsReq > GetColumnCount() )
    {
        for( i=GetColumnCount(); i<nColsReq; i++ )
        {
            aColumnWidths.Insert( MINLAY, aColumnWidths.Count() );
            aColumnRelWidths.push_back( sal_True );
        }
        // adjust columns in *all* rows, if columns must be inserted
        for( i=0; i<pRows->Count(); i++ )
            (*pRows)[(sal_uInt16)i]->Expand( nColsReq, i<nCurRow );
    }

	// Add rows
	if( pRows->Count() < nRowsReq )
	{
		OUString aStyleName2;
		for( i = pRows->Count(); i < nRowsReq; ++i )
			pRows->Insert( new SwXMLTableRow_Impl(aStyleName2, GetColumnCount()),
						   pRows->Count() );
	}

	OUString sStyleName( rStyleName );
	if( !sStyleName.getLength() )
	{
		sStyleName = ((*pRows)[(sal_uInt16)nCurRow])->GetDefaultCellStyleName();
		if( !sStyleName.getLength() && HasColumnDefaultCellStyleNames() )
		{
			sStyleName = GetColumnDefaultCellStyleName( nCurCol );
			if( !sStyleName.getLength() )
				sStyleName = aDfltCellStyleName;
		}
	}

	// Fill the cells
	for( i=nColSpan; i>0UL; i-- )
    {
		for( j=nRowSpan; j>0UL; j-- )
        {
            const bool bCovered = i != nColSpan || j != nRowSpan;
            GetCell( nRowsReq-j, nColsReq-i )
				->Set( sStyleName, j, i, pStartNode,
                       pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
                       bTextValue, i_rXmlId );
        }
    }

	// Set current col to the next (free) column
	nCurCol = nColsReq;
	while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
		nCurCol++;
}

void SwXMLTableContext::InsertRow( const OUString& rStyleName,
								   const OUString& rDfltCellStyleName,
								   sal_Bool bInHead,
                                   const OUString & i_rXmlId )
{
	ASSERT( nCurRow < USHRT_MAX,
			"SwXMLTableContext::InsertRow: no space left" );
	if( nCurRow >= USHRT_MAX )
		return;

	// Make sure there is at least one column.
	if( 0==nCurRow && 0UL == GetColumnCount()  )
		InsertColumn( USHRT_MAX, sal_True );

	if( nCurRow < pRows->Count() )
	{
		// The current row has already been inserted because of a row span
		// of a previous row.
		(*pRows)[(sal_uInt16)nCurRow]->Set(
            rStyleName, rDfltCellStyleName, i_rXmlId );
	}
	else
	{
		// add a new row
		pRows->Insert( new SwXMLTableRow_Impl( rStyleName, GetColumnCount(),
											   &rDfltCellStyleName, i_rXmlId ),
					   pRows->Count() );
	}

	// We start at the first column ...
	nCurCol=0UL;

	// ... but this cell may be occupied already.
	while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
		nCurCol++;

	if( bInHead  &&  nHeaderRows == nCurRow )
		nHeaderRows++;
}

void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
{
	const SwXMLTableRow_Impl *pSrcRow = (*pRows)[(sal_uInt16)nCurRow-1];
	while( nCount > 1 && IsInsertRowPossible() )
	{
		InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
				   sal_False );
		while( nCurCol < GetColumnCount() )
		{
			if( !GetCell(nCurRow,nCurCol)->IsUsed() )
			{
				const SwXMLTableCell_Impl *pSrcCell =
					GetCell( nCurRow-1, nCurCol );
				InsertCell( pSrcCell->GetStyleName(), 1U,
							pSrcCell->GetColSpan(),
							InsertTableSection(),
                            OUString(),
                            0, pSrcCell->IsProtected(),
							&pSrcCell->GetFormula(),
							pSrcCell->HasValue(), pSrcCell->GetValue(),
							pSrcCell->HasTextValue() );
			}
		}
		FinishRow();
		nCount--;
	}
}

void SwXMLTableContext::FinishRow()
{
	// Insert an empty cell at the end of the line if the row is not complete
	if( nCurCol < GetColumnCount() )
	{
		OUString aStyleName2;
		InsertCell( aStyleName2, 1U, GetColumnCount() - nCurCol,
					InsertTableSection() );
	}

	// Move to the next row.
	nCurRow++;
}

const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
														sal_uInt32 nCol ) const
{
	const SwXMLTableCell_Impl *pPrevCell = 0;
	if( GetColumnCount() == nCol )
	{
		// The last cell is the right one here.
		pPrevCell = GetCell( pRows->Count()-1U, GetColumnCount()-1UL );
	}
	else if( 0UL == nRow )
	{
		// There are no vertically merged cells within the first row, so the
		// previous cell is the right one always.
		if( nCol > 0UL )
			pPrevCell = GetCell( nRow, nCol-1UL );
	}
	else
	{
		// If there is a previous cell in the current row that is not spanned
		// from the previous row, its the right one.
		const SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nRow-1U];
		sal_uInt32 i = nCol;
		while( !pPrevCell &&  i > 0UL )
		{
			i--;
			if( 1UL == pPrevRow->GetCell( i )->GetRowSpan() )
				pPrevCell = GetCell( nRow, i );
		}

		// Otherwise, the last cell from the previous row is the right one.
		if( !pPrevCell )
			pPrevCell = pPrevRow->GetCell( GetColumnCount()-1UL );
	}

    const SwStartNode *pSttNd = 0;
	if( pPrevCell )
	{
		if( pPrevCell->GetStartNode() )
			pSttNd = pPrevCell->GetStartNode();
        // --> OD 2009-03-19 #i95726# - Some fault tolerance
//        else
        else if ( pPrevCell->GetSubTable() )
        // <--
			pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();

        ASSERT( pSttNd != 0,
                "table corrupt" );
	}

	return pSttNd;
}

void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
									sal_uInt32 nColSpan )
{
	sal_uInt32 nLastCol = nCol + nColSpan;
	for( sal_uInt16 i = (sal_uInt16)nCol; i < nLastCol; i++ )
	{
		sal_uInt32 j = nRow;
		sal_uInt32 nRowSpan = 1UL;
		SwXMLTableCell_Impl *pCell = GetCell( j, i );
		while( pCell && pCell->GetRowSpan() > 1UL )
		{
			pCell->SetRowSpan( nRowSpan++ );
			pCell = j > 0UL ? GetCell( --j, i ) : 0;
		}
	}
}

void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
{
    const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
    const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );

    const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
    sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
    sal_uInt32 nLastCol = nCol + pCell->GetColSpan();

    for( sal_uInt32 i=nRow; i<nLastRow; i++ )
    {
        SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
        for( sal_uInt32 j=nCol; j<nLastCol; j++ )
            pRow->GetCell( j )->SetStartNode( pSttNd );
    }

}

SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
									 		SwTableLine *pUpper )
{
	// The topmost table is the only table that maintains the two members
	// pBox1 and bFirstSection.
	if( xParentTable.Is() )
		return ((SwXMLTableContext *)&xParentTable)->NewTableBox( pStNd,
																  pUpper );

	SwTableBox *pBox;

	if( pBox1 &&
		pBox1->GetSttNd() == pStNd )
	{
		// wenn der StartNode dem StartNode der initial angelegten Box
		// entspricht nehmen wir diese Box
		pBox = pBox1;
		pBox->SetUpper( pUpper );
		pBox1 = 0;
	}
	else
		pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );

	return pBox;
}

SwTableBoxFmt* SwXMLTableContext::GetSharedBoxFormat(
    SwTableBox* pBox,
    const OUString& rStyleName,
    sal_Int32 nColumnWidth,
    sal_Bool bProtected,
    sal_Bool bMayShare,
    sal_Bool& bNew,
    sal_Bool* pModifyLocked )
{
    if ( pSharedBoxFormats == NULL )
        pSharedBoxFormats = new map_BoxFmt();

    SwTableBoxFmt* pBoxFmt2;

    TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
    map_BoxFmt::iterator aIter = pSharedBoxFormats->find( aKey );
    if ( aIter == pSharedBoxFormats->end() )
    {
        // unknown format so far -> construct a new one

        // get the old format, and reset all attributes
        // (but preserve FillOrder)
        pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
        SwFmtFillOrder aFillOrder( pBoxFmt2->GetFillOrder() );
        // --> OD 2007-01-25 #i73790# - method renamed
        pBoxFmt2->ResetAllFmtAttr();
        // <--
        pBoxFmt2->SetFmtAttr( aFillOrder );
        bNew = sal_True;    // it's a new format now

        // share this format, if allowed
        if ( bMayShare )
            (*pSharedBoxFormats)[ aKey ] = pBoxFmt2;
    }
    else
    {
        // set the shared format
        pBoxFmt2 = aIter->second;
        pBox->ChgFrmFmt( pBoxFmt2 );
        bNew = sal_False;   // copied from an existing format

        // claim it, if we are not allowed to share
        if ( !bMayShare )
            pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
    }

    // lock format (if so desired)
    if ( pModifyLocked != NULL )
    {
        (*pModifyLocked) = pBoxFmt2->IsModifyLocked();
        pBoxFmt2->LockModify();
    }

    return pBoxFmt2;
}

SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
                                             sal_uInt32 nTopRow,
                                             sal_uInt32 nLeftCol,
                                             sal_uInt32 nBottomRow,
                                             sal_uInt32 nRightCol )
{
//FIXME: here would be a great place to handle XmlId for cell
    SwTableBox *pBox = new SwTableBox( pBoxFmt, 0, pUpper );

    sal_uInt32 nColSpan = nRightCol - nLeftCol;
    sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );

	// TODO: Share formats!
	SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
	SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
    // --> OD 2007-01-25 #i73790# - method renamed
    pFrmFmt->ResetAllFmtAttr();
    // <--
    pFrmFmt->SetFmtAttr( aFillOrder );

    pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );

    SwTableLines& rLines = pBox->GetTabLines();
    sal_Bool bSplitted = sal_False;

    while( !bSplitted )
    {
        sal_uInt32 nStartRow = nTopRow;
        sal_uInt32 i;

        for( i = nTopRow; i < nBottomRow; i++ )
        {
            // Could the table be splitted behind the current row?
            sal_Bool bSplit = sal_True;
            SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
            for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
            {
                bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
                if( !bSplit )
                    break;
            }
            if( bSplit && (nStartRow>nTopRow || i+1UL<nBottomRow) )
            {
                SwTableLine *pLine =
                    MakeTableLine( pBox, nStartRow, nLeftCol, i+1UL,
                                   nRightCol );

                rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );

                nStartRow = i+1UL;
                bSplitted = sal_True;
            }
        }
        if( !bSplitted )
        {
            // No splitting was possible. That for, we have to force it.
            // Ruthless!

            nStartRow = nTopRow;
            while( nStartRow < nBottomRow )
            {
                sal_uInt32 nMaxRowSpan = 0UL;
                SwXMLTableRow_Impl *pStartRow = (*pRows)[(sal_uInt16)nStartRow];
                SwXMLTableCell_Impl *pCell;
                for( i=nLeftCol; i<nRightCol; i++ )
                    if( ( pCell=pStartRow->GetCell(i),
                          pCell->GetRowSpan() > nMaxRowSpan ) )
                        nMaxRowSpan = pCell->GetRowSpan();

                nStartRow += nMaxRowSpan;
                if( nStartRow<nBottomRow )
                {
                    SwXMLTableRow_Impl *pPrevRow =
                                        (*pRows)[(sal_uInt16)nStartRow-1U];
                    i = nLeftCol;
                    while( i < nRightCol )
                    {
                        if( pPrevRow->GetCell(i)->GetRowSpan() > 1UL )
                        {
                            const SwXMLTableCell_Impl *pCell2 =
                                GetCell( nStartRow, i );
                            const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
                            FixRowSpan( nStartRow-1UL, i, nColSpan2 );
                            ReplaceWithEmptyCell( nStartRow, i, true );
                            i += nColSpan2;
                        }
                        else
                        {
                            i++;
                        }
                    }
                }
            }
            // und jetzt nochmal von vorne ...
        }
    }

    return pBox;
}

SwTableBox *SwXMLTableContext::MakeTableBox(
		SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
		sal_uInt32 /*nTopRow*/, sal_uInt32 nLeftCol, sal_uInt32 /*nBottomRow*/,
		sal_uInt32 nRightCol )
{
//FIXME: here would be a great place to handle XmlId for cell
	SwTableBox *pBox;
	sal_uInt32 nColSpan = nRightCol - nLeftCol;
    sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );

	if( pCell->GetStartNode() )
	{
		pBox = NewTableBox( pCell->GetStartNode(), pUpper );
	}
	else
	{
		// und die ist eine Tabelle: dann bauen wir eine neue
		// Box und fuegen die Zeilen der Tabelle in die Zeilen
		// der Box ein
		pBox = new SwTableBox( pBoxFmt, 0, pUpper );
		pCell->GetSubTable()->MakeTable( pBox, nColWidth );
	}

	// Share formats!
    OUString sStyleName = pCell->GetStyleName();
    sal_Bool bModifyLocked;
    sal_Bool bNew;
	SwTableBoxFmt *pBoxFmt2 = GetSharedBoxFormat(
        pBox, sStyleName, nColWidth, pCell->IsProtected(),
        pCell->GetStartNode() && pCell->GetFormula().getLength() == 0 &&
            ! pCell->HasValue(),
        bNew, &bModifyLocked  );

    // if a new format was created, then we need to set the style
    if ( bNew )
    {
        // set style
        const SfxItemSet *pAutoItemSet = 0;
        if( pCell->GetStartNode() && sStyleName &&
            GetSwImport().FindAutomaticStyle(
                XML_STYLE_FAMILY_TABLE_CELL, sStyleName, &pAutoItemSet ) )
        {
            if( pAutoItemSet )
                pBoxFmt2->SetFmtAttr( *pAutoItemSet );
        }
    }

	if( pCell->GetStartNode() )
	{

        // #104801# try to rescue broken documents with a certain pattern
        // if: 1) the cell has a default number format (number 0)
        //     2) the call has no formula
        //     3) the value is 0.0
        //     4) the text doesn't look anything like 0.0
        //        [read: length > 10, or length smaller 10 and no 0 in it]
        // then make it a text cell!
        bool bSuppressNumericContent = false;
        if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
            (pCell->GetFormula().getLength() == 0) &&
            (sStyleName.getLength() != 0) )
        {
            // default num format?
			const SfxPoolItem* pItem = NULL;
            if( pBoxFmt2->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
                            == SFX_ITEM_SET )
            {
                const SwTblBoxNumFormat* pNumFormat =
                    static_cast<const SwTblBoxNumFormat*>( pItem );
                if( ( pNumFormat != NULL ) && ( pNumFormat->GetValue() == 0 ) )
                {
                    // only one text node?
                    SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
                    if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
                          aNodeIndex.GetNode().StartOfSectionIndex() ) == 2 )
                    {
                        SwTxtNode* pTxtNode= aNodeIndex.GetNode().GetTxtNode();
                        if( pTxtNode != NULL )
                        {
                            // check text: does it look like some form of 0.0?
                            const String& rText = pTxtNode->GetTxt();
                            if( ( rText.Len() > 10 ) ||
                                ( rText.Search( '0' ) == STRING_NOTFOUND ) )
                            {
                                bSuppressNumericContent = true;
                            }
                        }
                    }
					else
						bSuppressNumericContent = true; // several nodes
                }
            }
        }

        if( bSuppressNumericContent )
        {
            // suppress numeric content? Then reset number format!
            pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMULA );
            pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMAT );
            pBoxFmt2->ResetFmtAttr( RES_BOXATR_VALUE );
        }
        else
        {
            // the normal case: set formula and value (if available)

            const OUString& rFormula = pCell->GetFormula();
            if (rFormula.getLength() > 0)
            {
                // formula cell: insert formula if valid
                SwTblBoxFormula aFormulaItem( rFormula );
                pBoxFmt2->SetFmtAttr( aFormulaItem );
            }
			else if( !pCell->HasValue() && pCell->HasTextValue() )
			{
				// Check for another inconsistency:
				// No value but a non-textual format, i.e. a number format
				// Solution: the number format will be removed,
				// the cell gets the default text format.
				const SfxPoolItem* pItem = NULL;
				if( pBoxFmt->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
					== SFX_ITEM_SET )
				{
					const SwDoc* pDoc = pBoxFmt->GetDoc();
					const SvNumberFormatter* pNumberFormatter = pDoc ?
						pDoc->GetNumberFormatter() : 0;
					const SwTblBoxNumFormat* pNumFormat =
						static_cast<const SwTblBoxNumFormat*>( pItem );
					if( pNumFormat != NULL && pNumberFormatter &&
						!pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
                        pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
				}
			}
            // always insert value, even if default
            if( pCell->HasValue() )
            {
                SwTblBoxValue aValueItem( pCell->GetValue() );
                pBoxFmt2->SetFmtAttr( aValueItem );
            }
        }

		// update cell content depend on the default language
		pBox->ActualiseValueBox();
	}

	// table cell protection
	if( pCell->IsProtected() )
	{
        SvxProtectItem aProtectItem( RES_PROTECT );
		aProtectItem.SetCntntProtect( sal_True );
        pBoxFmt2->SetFmtAttr( aProtectItem );
	}

	// restore old modify-lock state
	if (! bModifyLocked)
		pBoxFmt2->UnlockModify();

    pBoxFmt2->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );

	return pBox;
}

SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
                                               sal_uInt32 nTopRow,
                                               sal_uInt32 nLeftCol,
                                               sal_uInt32 nBottomRow,
                                               sal_uInt32 nRightCol )
{
//FIXME: here would be a great place to handle XmlId for row
	SwTableLine *pLine;
	if( !pUpper && 0UL==nTopRow )
	{
		pLine = pTableNode->GetTable().GetTabLines()[0U];
	}
	else
	{
		pLine = new SwTableLine( pLineFmt, 0, pUpper );
	}

	// TODO: Share formats!
	SwFrmFmt *pFrmFmt = pLine->ClaimFrmFmt();
	SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
    // --> OD 2007-01-25 #i73790# - method renamed
    pFrmFmt->ResetAllFmtAttr();
    // <--
    pFrmFmt->SetFmtAttr( aFillOrder );

	const SfxItemSet *pAutoItemSet = 0;
	const OUString& rStyleName = (*pRows)[(sal_uInt16)nTopRow]->GetStyleName();
    if( 1UL == (nBottomRow - nTopRow) &&
        rStyleName.getLength() &&
		GetSwImport().FindAutomaticStyle(
			XML_STYLE_FAMILY_TABLE_ROW, rStyleName, &pAutoItemSet ) )
	{
		if( pAutoItemSet )
            pFrmFmt->SetFmtAttr( *pAutoItemSet );
	}

	SwTableBoxes& rBoxes = pLine->GetTabBoxes();

	sal_uInt32 nStartCol = nLeftCol;
	while( nStartCol < nRightCol )
	{
        for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
            (*pRows)[(sal_uInt16)nRow]->SetSplitable( sal_True );

        sal_uInt32 nCol = nStartCol;
		sal_uInt32 nSplitCol = nRightCol;
		sal_Bool bSplitted = sal_False;
		while( !bSplitted )
		{
			ASSERT( nCol < nRightCol, "Zu weit gelaufen" );

            // Kann hinter der aktuellen HTML-Tabellen-Spalte gesplittet
            // werden? Wenn ja, koennte der enstehende Bereich auch noch
            // in Zeilen zerlegt werden, wenn man die naechste Spalte
            // hinzunimmt?
            sal_Bool bSplit = sal_True;
            sal_Bool bHoriSplitMayContinue = sal_False;
            sal_Bool bHoriSplitPossible = sal_False;

            if ( bHasSubTables )
            {
                // Convert row spans if the table has subtables:
                for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
                {
                    SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
                    // Could the table fragment be splitted horizontally behind
                    // the current line?
                    sal_Bool bHoriSplit = (*pRows)[(sal_uInt16)nRow]->IsSplitable() &&
                                      nRow+1UL < nBottomRow &&
                                      1UL == pCell->GetRowSpan();
                    (*pRows)[(sal_uInt16)nRow]->SetSplitable( bHoriSplit );

                    // Could the table fragment be splitted vertically behind the
                    // current column (uptp the current line?
                    bSplit &= ( 1UL == pCell->GetColSpan() );
                    if( bSplit )
                    {
                        bHoriSplitPossible |= bHoriSplit;

                        // Could the current table fragment be splitted
                        // horizontally behind the next collumn, too?
                        bHoriSplit &= (nCol+1UL < nRightCol &&
                                       1UL == GetCell(nRow,nCol+1UL)->GetRowSpan());
                        bHoriSplitMayContinue |= bHoriSplit;
                    }
                }
            }
            else
            {
                // No subtabels: We use the new table model.
                SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);

                // --> OD 2009-03-19 #i95726# - some fault tolerance
                if ( pCell == 0 )
                {
                    ASSERT( false, "table seems to be corrupt." );
                    break;
                }
                // <--

                // Could the table fragment be splitted vertically behind the
                // current column (uptp the current line?
                bSplit = 1UL == pCell->GetColSpan();
            }

#ifdef DBG_UTIL
            if( nCol == nRightCol-1UL )
            {
                ASSERT( bSplit, "Split-Flag falsch" );
                if ( bHasSubTables )
                {
                    ASSERT( !bHoriSplitMayContinue,
                            "HoriSplitMayContinue-Flag falsch" );
                    SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
                    ASSERT( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
                            !bHoriSplitPossible, "HoriSplitPossible-Flag falsch" );
                }
            }
#endif

            ASSERT( !bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
                    "bHoriSplitMayContinue, aber nicht bHoriSplitPossible" );

			if( bSplit )
			{
				SwTableBox* pBox = 0;
				SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
                // --> OD 2009-03-19 #i95726# - some fault tolerance
                if( ( !bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
                    pCell->GetColSpan() == (nCol+1UL-nStartCol) &&
                    ( pCell->GetStartNode() || pCell->GetSubTable() ) )
                // <--
				{
                    // insert new empty cell for covered cells:
                    long nBoxRowSpan = 1;
                    if ( !bHasSubTables )
                    {
                        nBoxRowSpan = pCell->GetRowSpan();
                        if ( pCell->IsCovered() )
                        {
                            nBoxRowSpan = -1 * nBoxRowSpan;
                            ReplaceWithEmptyCell( nTopRow, nStartCol, false );
                        }
                    }

                    // The remaining box neither contains lines nor rows (i.e.
					// is a content box
					nSplitCol = nCol + 1UL;

					pBox = MakeTableBox( pLine, pCell,
                                         nTopRow, nStartCol,
                                         nBottomRow, nSplitCol );

                    if ( 1 != nBoxRowSpan )
                        pBox->setRowSpan( nBoxRowSpan );

                    bSplitted = sal_True;
				}
                else if( bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
                {
                    // The table fragment could be splitted behind the current
                    // column, and the remaining fragment could be divided
                    // into lines. Anyway, it could be that this applies to
                    // the next column, too. That for, we check the next
                    // column but rememeber the current one as a good place to
                    // split.
                    nSplitCol = nCol + 1UL;
                }
                else if ( bHasSubTables )
                {
                    // If the table resulting table fragment could be divided
                    // into lines if spllitting behind the current column, but
                    // this doesn't apply for thr next column, we split begind
                    // the current column. This applies for the last column,
                    // too.
                    // If the resulting box cannot be splitted into rows,
                    // the split at the last split position we remembered.
                    if( bHoriSplitPossible || nSplitCol > nCol+1 )
                    {
                        ASSERT( !bHoriSplitMayContinue,
                                "bHoriSplitMayContinue==sal_True" );
                        ASSERT( bHoriSplitPossible || nSplitCol == nRightCol,
                                "bHoriSplitPossible-Flag sollte gesetzt sein" );

                        nSplitCol = nCol + 1UL;
                    }

                    pBox = MakeTableBox( pLine, nTopRow, nStartCol,
                                         nBottomRow, nSplitCol );
                    bSplitted = sal_True;
                }

                ASSERT( bHasSubTables || pBox, "Colspan trouble" )

                if( pBox )
					rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
			}
			nCol++;
		}
		nStartCol = nSplitCol;
	}

	return pLine;
}

void SwXMLTableContext::_MakeTable( SwTableBox *pBox )
{
	// fix column widths
	sal_uInt32 i;
	sal_uInt32 nCols = GetColumnCount();

	// If there are empty rows (because of some row span of previous rows)
	// the have to be deleted. The previous rows have to be truncated.

	if( pRows->Count() > nCurRow )
	{
		SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nCurRow-1U];
		SwXMLTableCell_Impl *pCell;
		for( i=0UL; i<nCols; i++ )
		{
			if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1UL ) )
			{
				FixRowSpan( nCurRow-1UL, i, 1UL );
			}
		}
		for( i=(sal_uInt32)pRows->Count()-1UL; i>=nCurRow; i-- )
			pRows->DeleteAndDestroy( (sal_uInt16)i );
	}

	if( 0UL == pRows->Count() )
	{
		OUString aStyleName2;
		InsertCell( aStyleName2, 1U, nCols, InsertTableSection() );
	}

	// TODO: Do we have to keep both values, the realtive and the absolute
	// width?
	sal_Int32 nAbsWidth = 0L;
	sal_Int32 nMinAbsColWidth = 0L;
	sal_Int32 nRelWidth = 0L;
	sal_Int32 nMinRelColWidth = 0L;
	sal_uInt32 nRelCols = 0UL;
	for( i=0U; i < nCols; i++ )
	{
		sal_Int32 nColWidth = aColumnWidths[(sal_uInt16)i];
		if( aColumnRelWidths[(sal_uInt16)i] )
		{
			nRelWidth += nColWidth;
			if( 0L == nMinRelColWidth || nColWidth < nMinRelColWidth )
				nMinRelColWidth = nColWidth;
			nRelCols++;
		}
		else
		{
			nAbsWidth += nColWidth;
			if( 0L == nMinAbsColWidth || nColWidth < nMinAbsColWidth )
				nMinAbsColWidth = nColWidth;
		}
	}
	sal_uInt32 nAbsCols = nCols - nRelCols;

	if( bRelWidth )
	{
		// If there a columns that have an absolute width, we have to
		// calculate a relative one for them.
		if( nAbsCols > 0UL )
		{
			// All column that have absolute widths get relative widths;
			// these widths relate to each over like the original absolute
			// widths. The smallest column gets a width that hat the same
			// value as the smallest column that has an relative width
			// already.
			if( 0L == nMinRelColWidth )
                nMinRelColWidth = nMinAbsColWidth;

			for( i=0UL; nAbsCols > 0UL && i < nCols; i++ )
			{
				if( !aColumnRelWidths[(sal_uInt16)i] )
				{
					sal_Int32 nRelCol = (aColumnWidths[(sal_uInt16)i] * nMinRelColWidth) /
								   nMinAbsColWidth;
					aColumnWidths.Replace( (sal_uInt16)nRelCol, (sal_uInt16)i );
					nRelWidth += nRelCol;
					nAbsCols--;
				}
			}
		}

		if( !nWidth )
		{
			// This happens only for percentage values for the table itself.
			// In this case, the columns get the correct width even if the
			// the sum of the relative withs is smaller than the available
			// width in TWIP. Therfore, we can use the relative width.
			//
			nWidth = nRelWidth > USHRT_MAX ? USHRT_MAX : nRelWidth;
		}
		if( nRelWidth != nWidth && nRelWidth && nCols )
		{
			double n = (double)nWidth / (double)nRelWidth;
			nRelWidth = 0L;
			for( i=0U; i < nCols-1UL; i++ )
			{
				sal_Int32 nW = (sal_Int32)(aColumnWidths[(sal_uInt16)i] * n);
				aColumnWidths.Replace( (sal_uInt16)nW, (sal_uInt16)i );
				nRelWidth += nW;
			}
			aColumnWidths.Replace( (sal_uInt16)(nWidth-nRelWidth),
								   (sal_uInt16)nCols-1U );
		}
	}
	else
	{
		// If there are columns that have relative widths, we have to
		// calculate a absolute widths for them.
		if( nRelCols > 0UL )
		{
			// The absolute space that is available for all columns with a
			// relative width.
			sal_Int32 nAbsForRelWidth =
					nWidth > nAbsWidth ? nWidth - nAbsWidth : (sal_Int32)0L;

			// The relative width that has to be distributed in addition to
			// equally widthed columns.
			sal_Int32 nExtraRel = nRelWidth - (nRelCols * nMinRelColWidth);

			// The absolute space that may be distributed in addition to
			// minumum widthed columns.
			sal_Int32 nMinAbs = nRelCols * MINLAY;
			sal_Int32 nExtraAbs =
					nAbsForRelWidth > nMinAbs ? nAbsForRelWidth - nMinAbs : (sal_Int32)0L;

			sal_Bool bMin = sal_False;		// Do all columns get the mininum width?
			sal_Bool bMinExtra = sal_False;	// Do all columns get the minimum width plus
									// some extra space?

			if( nAbsForRelWidth <= nMinAbs )
			{
				// If there is not enough space left for all columns to
				// get the minimum width, they get the minimum width, anyway.
				nAbsForRelWidth = nMinAbs;
				bMin = sal_True;
			}
			else if( nAbsForRelWidth <= (nRelWidth * MINLAY) /
					                    nMinRelColWidth )
			{
				// If there is enougth space for all columns to get the
				// minimum width, but not to get a width that takes the
				// relative width into account, each column gets the minimum
				// width plus some extra space that is based on the additional
				// space that is available.
				bMinExtra = sal_True;
			}
			// Otherwise, if there is enouth space for every column, every
			// column gets this space.

			for( i=0UL; nRelCols > 0UL && i < nCols; i++ )
			{
				if( aColumnRelWidths[(sal_uInt16)i] )
				{
					sal_Int32 nAbsCol;
					if( 1UL == nRelCols )
					{
						// The last column that has a relative width gets
						// all absolute space that is left.
						nAbsCol = nAbsForRelWidth;
					}
					else
					{
						if( bMin )
						{
							nAbsCol = MINLAY;
						}
						else if( bMinExtra )
						{
							sal_Int32 nExtraRelCol =
								aColumnWidths[(sal_uInt16)i] - nMinRelColWidth;
							nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
										  	   nExtraRel;
						}
						else
						{
							nAbsCol = (aColumnWidths[(sal_uInt16)i] * nAbsForRelWidth) /
									  nRelWidth;
						}
					}
					aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
					nAbsForRelWidth -= nAbsCol;
					nAbsWidth += nAbsCol;
					nRelCols--;
				}
			}
		}

        if( nCols && nAbsWidth )
        {
            if( nAbsWidth < nWidth )
            {
                // If the table's width is larger than the absolute column widths,
                // every column get some extra width.
                sal_Int32 nExtraAbs = nWidth - nAbsWidth;
                sal_Int32 nAbsLastCol =
                        aColumnWidths[(sal_uInt16)nCols-1U] + nExtraAbs;
                for( i=0UL; i < nCols-1UL; i++ )
                {
                    sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
                    sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
                                             nAbsWidth;
                    nAbsCol += nExtraAbsCol;
                    aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
                    nAbsLastCol -= nExtraAbsCol;
                }
                aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
            }
            else if( nAbsWidth > nWidth )
            {
                // If the table's width is smaller than the absolute column
                // widths, every column gets the minimum width plus some extra
                // width.
                sal_Int32 nExtraAbs = nWidth - (nCols * MINLAY);
                sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
                for( i=0UL; i < nCols-1UL; i++ )
                {
                    sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
                    sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
                                             nAbsWidth;
                    nAbsCol = MINLAY + nExtraAbsCol;
                    aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
                    nAbsLastCol -= nExtraAbsCol;
                }
                aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
            }
        }
	}

	SwTableLines& rLines =
		pBox ? pBox->GetTabLines()
			 : pTableNode->GetTable().GetTabLines();

    sal_uInt32 nStartRow = 0UL;
    sal_uInt32 nRows = pRows->Count();
	for( i=0UL; i<nRows; i++ )
	{
        // Could we split the table behind the current line?
        sal_Bool bSplit = sal_True;
        if ( bHasSubTables )
        {
            SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
            for( sal_uInt32 j=0UL; j<nCols; j++ )
            {
                bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
                if( !bSplit )
                    break;
            }
        }

        if( bSplit )
        {
            SwTableLine *pLine =
                MakeTableLine( pBox, nStartRow, 0UL, i+1UL, nCols );
            if( pBox || nStartRow>0UL )
                rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
            nStartRow = i+1UL;
        }
    }
}

void SwXMLTableContext::MakeTable()
{
    // this method will modify the document directly -> lock SolarMutex
    // This will call all other MakeTable*(..) methods, so
    // those don't need to be locked separately.
    vos::OGuard aGuard(Application::GetSolarMutex());

    // #i97274# handle invalid tables
    if (!pRows || !pRows->Count() || !GetColumnCount())
    {
        ASSERT(false, "invalid table: no cells; deleting...");
        pTableNode->GetDoc()->DeleteSection( pTableNode );
        pTableNode = 0;
        pBox1 = 0;
        pSttNd1 = 0;
        return;
    }

	SwXMLImport& rSwImport = GetSwImport();

	SwFrmFmt *pFrmFmt = pTableNode->GetTable().GetFrmFmt();

    sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
	sal_Bool bSetHoriOrient = sal_False;

	sal_uInt16 nPrcWidth = 0U;

    pTableNode->GetTable().SetRowsToRepeat( nHeaderRows );
    pTableNode->GetTable().SetTableModel( !bHasSubTables );

	const SfxItemSet *pAutoItemSet = 0;
	if( aStyleName.getLength() &&
		rSwImport.FindAutomaticStyle(
			XML_STYLE_FAMILY_TABLE_TABLE, aStyleName, &pAutoItemSet ) &&
	 	pAutoItemSet )
	{
		const SfxPoolItem *pItem;
		const SvxLRSpaceItem *pLRSpace = 0;
		if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_LR_SPACE, sal_False,
														&pItem ) )
			pLRSpace = (const SvxLRSpaceItem *)pItem;

		if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_HORI_ORIENT, sal_False,
														&pItem ) )
		{
			eHoriOrient = ((const SwFmtHoriOrient *)pItem)->GetHoriOrient();
			switch( eHoriOrient )
			{
            case text::HoriOrientation::FULL:
				if( pLRSpace )
				{
                    eHoriOrient = text::HoriOrientation::NONE;
					bSetHoriOrient = sal_True;
				}
				break;
            case text::HoriOrientation::LEFT:
				if( pLRSpace )
				{
                    eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
					bSetHoriOrient = sal_True;
				}
				break;
			default:
				;
			}
		}
		else
		{
			bSetHoriOrient = sal_True;
		}

		const SwFmtFrmSize *pSize = 0;
		if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
														&pItem ) )
			pSize = (const SwFmtFrmSize *)pItem;

		switch( eHoriOrient )
		{
        case text::HoriOrientation::FULL:
        case text::HoriOrientation::NONE:
            // #78246#: For text::HoriOrientation::NONE we would prefere to use the sum
			// of the relative column widths as reference width.
			// Unfortunately this works only if this sum interpreted as
			// twip value is larger than the space that is avaialable.
			// We don't know that space, so we have to use USHRT_MAX, too.
			// Even if a size is speczified, it will be ignored!
			nWidth = USHRT_MAX;
			break;
		default:
			if( pSize )
			{
				if( pSize->GetWidthPercent() )
				{
					// The width will be set in _MakeTable
					nPrcWidth = pSize->GetWidthPercent();
				}
				else
				{
					nWidth = pSize->GetWidth();
					if( nWidth < (sal_Int32)GetColumnCount() * MINLAY )
					{
						nWidth = GetColumnCount() * MINLAY;
					}
					else if( nWidth > USHRT_MAX )
					{
						nWidth = USHRT_MAX;
					}
					bRelWidth = sal_False;
				}
			}
			else
			{
                eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
                                    ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
				bSetHoriOrient = sal_True;
				nWidth = USHRT_MAX;
			}
			break;
		}

        pFrmFmt->SetFmtAttr( *pAutoItemSet );
	}
	else
	{
		bSetHoriOrient = sal_True;
		nWidth = USHRT_MAX;
	}

	SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
	DBG_ASSERT( pBox1 == pLine1->GetTabBoxes()[0U],
				"Why is box 1 change?" );
	pBox1->pSttNd = pSttNd1;
	pLine1->GetTabBoxes().Remove(0U);

	pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
	pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();

    _MakeTable( 0 );

	if( bSetHoriOrient )
        pFrmFmt->SetFmtAttr( SwFmtHoriOrient( 0, eHoriOrient ) );

	// This must be after the call to _MakeTable, because nWidth might be
	// changed there.
	pFrmFmt->LockModify();
	SwFmtFrmSize aSize( ATT_VAR_SIZE, nWidth );
	aSize.SetWidthPercent( (sal_Int8)nPrcWidth );
    pFrmFmt->SetFmtAttr( aSize );
	pFrmFmt->UnlockModify();


	for( sal_uInt16 i=0; i<pRows->Count(); i++ )
		(*pRows)[i]->Dispose();

	// now that table is complete, change into DDE table (if appropriate)
	if (NULL != pDDESource)
	{
		// change existing table into DDE table:
		// 1) Get DDE field type (get data from dde-source context),
		SwDDEFieldType* pFldType = lcl_GetDDEFieldType( pDDESource,
														pTableNode );

		// 2) release the DDE source context,
		pDDESource->ReleaseRef();

		// 3) create new DDE table, and
		SwDDETable* pDDETable = new SwDDETable( pTableNode->GetTable(),
												pFldType, sal_False );

		// 4) set new (DDE)table at node.
		pTableNode->SetNewTable(pDDETable, sal_False);
	}

    // ??? this is always false: root frame is only created in ViewShell::Init
	if( pTableNode->GetDoc()->GetCurrentViewShell() )	//swmod 071108//swmod 071225
	{
		pTableNode->DelFrms();
		SwNodeIndex aIdx( *pTableNode->EndOfSectionNode(), 1 );
		pTableNode->MakeFrms( &aIdx );
	}
}

void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
{
//FIXME: here would be a great place to handle XmlId for subtable
	pLineFmt = GetParentTable()->pLineFmt;
	pBoxFmt = GetParentTable()->pBoxFmt;
	nWidth = nW;
	bRelWidth = GetParentTable()->bRelWidth;

	_MakeTable( pBox );
}

const SwStartNode *SwXMLTableContext::InsertTableSection(
											const SwStartNode *pPrevSttNd )
{
	// The topmost table is the only table that maintains the two members
	// pBox1 and bFirstSection.
	if( xParentTable.Is() )
		return ((SwXMLTableContext *)&xParentTable)->InsertTableSection( pPrevSttNd );

	const SwStartNode *pStNd;
	Reference<XUnoTunnel> xCrsrTunnel( GetImport().GetTextImport()->GetCursor(),
									   UNO_QUERY);
	ASSERT( xCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
	OTextCursorHelper *pTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
			sal::static_int_cast< sal_IntPtr >( xCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
	ASSERT( pTxtCrsr, "SwXTextCursor missing" );

	if( bFirstSection )
	{
		// The Cursor already is in the first section
		pStNd = pTxtCrsr->GetPaM()->GetNode()->FindTableBoxStartNode();
		bFirstSection = sal_False;
		OUString sStyleName( RTL_CONSTASCII_USTRINGPARAM("Standard") );
		GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
			GetImport().GetTextImport()->GetCursor(), sStyleName, sal_True );
	}
	else
	{
		SwDoc* pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
		const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
											 : pTableNode->EndOfSectionNode();
        // --> OD 2007-07-02 #i78921# - make code robust
#if OSL_DEBUG_LEVEL > 1
        ASSERT( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCrsr> instance." );
#endif
        if ( !pDoc )
        {
            pDoc = const_cast<SwDoc*>(pEndNd->GetDoc());
        }
        // <--
		sal_uInt32 nOffset = pPrevSttNd ? 1UL : 0UL;
		SwNodeIndex aIdx( *pEndNd, nOffset );
		SwTxtFmtColl *pColl =
            pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false );
		pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
												 pColl );
        // --> FLR 2005-08-30 #125369#
        // Consider the case that a table is defined without a row.
        if( !pPrevSttNd && pBox1 != NULL )
        // <--
        {
			pBox1->pSttNd = pStNd;
			SwCntntNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
															->GetCntntNode();
			SwPosition aPos( *pCNd );
			aPos.nContent.Assign( pCNd, 0U );

            const uno::Reference< text::XTextRange > xTextRange =
                SwXTextRange::CreateXTextRange( *pDoc, aPos, 0 );
			Reference < XText > xText = xTextRange->getText();
			Reference < XTextCursor > xTextCursor =
				xText->createTextCursorByRange( xTextRange );
			GetImport().GetTextImport()->SetCursor( xTextCursor );
		}
	}

	return pStNd;
}

void SwXMLTableContext::EndElement()
{
	if( IsValid() && !xParentTable.Is() )
	{
		MakeTable();
		GetImport().GetTextImport()->SetCursor( xOldCursor );
	}
}

Reference < XTextContent > SwXMLTableContext::GetXTextContent() const
{
	return xTextContent;
}
