blob: e2704e11d2f50803f6b2b8a33f1ea44e4734961a [file] [log] [blame]
/**************************************************************
*
* 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 "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.isEmpty() &&
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 );
for( sal_uInt16 i=0; i<pRows->Count(); i++ ) // i113600, to break the cyclic reference to SwXMLTableContext object
(*pRows)[i]->Dispose();
}
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;
}