summaryrefslogtreecommitdiff
path: root/sw/source/filter/xml/xmltbli.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/xml/xmltbli.cxx')
-rw-r--r--sw/source/filter/xml/xmltbli.cxx2951
1 files changed, 2951 insertions, 0 deletions
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
new file mode 100644
index 000000000000..4b6af56066fc
--- /dev/null
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -0,0 +1,2951 @@
+/*************************************************************************
+ *
+ * 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.Insert( bRelWidth2, aColumnRelWidths.Count() );
+ if( (pDfltCellStyleName && pDfltCellStyleName->getLength() > 0) ||
+ pColumnDefaultCellStyleNames )
+ {
+ if( !pColumnDefaultCellStyleNames )
+ {
+ pColumnDefaultCellStyleNames = new SvStringsDtor;
+ sal_uInt16 nCount = aColumnRelWidths.Count() - 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.Insert( sal_True, aColumnRelWidths.Count() );
+ }
+ // 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, 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, 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, FALSE );
+
+ // 4) set new (DDE)table at node.
+ pTableNode->SetNewTable(pDDETable, FALSE);
+ }
+
+ // ??? this is always false: root frame is only created in ViewShell::Init
+ if( pTableNode->GetDoc()->GetRootFrm() )
+ {
+ 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;
+}