| /************************************************************** |
| * |
| * 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 |
| // minimum 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; |
| } |