| /************************************************************** |
| * |
| * 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_xmloff.hxx" |
| |
| #include "SchXMLTableContext.hxx" |
| #include "SchXMLParagraphContext.hxx" |
| #include "SchXMLTextListContext.hxx" |
| #include "SchXMLImport.hxx" |
| #include "SchXMLTools.hxx" |
| #include "transporttypes.hxx" |
| #include "XMLStringBufferImportContext.hxx" |
| #include <tools/debug.hxx> |
| #include <rtl/math.hxx> |
| #include "xmloff/xmlnmspe.hxx" |
| #include <xmloff/xmltoken.hxx> |
| #include <xmloff/nmspmap.hxx> |
| #include <xmloff/xmluconv.hxx> |
| #include <com/sun/star/frame/XModel.hpp> |
| #include <com/sun/star/chart2/XAnyDescriptionAccess.hpp> |
| #include <com/sun/star/chart2/XDataSeriesContainer.hpp> |
| #include <com/sun/star/chart2/XChartDocument.hpp> |
| #include <com/sun/star/chart2/XChartTypeContainer.hpp> |
| #include <com/sun/star/chart2/XInternalDataProvider.hpp> |
| #include <com/sun/star/chart/ChartSeriesAddress.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| #include <com/sun/star/beans/XPropertySetInfo.hpp> |
| #include <com/sun/star/beans/PropertyAttribute.hpp> |
| |
| #include <com/sun/star/chart2/XDiagram.hpp> |
| #include <com/sun/star/chart2/XAxis.hpp> |
| #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> |
| #include <com/sun/star/chart2/AxisType.hpp> |
| |
| #include <vector> |
| #include <algorithm> |
| |
| using namespace com::sun::star; |
| using namespace ::xmloff::token; |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::uno::Reference; |
| using ::rtl::OUString; |
| |
| namespace |
| { |
| |
| const OUString lcl_aLabelPrefix( RTL_CONSTASCII_USTRINGPARAM("label ")); |
| const OUString lcl_aCategoriesRange( RTL_CONSTASCII_USTRINGPARAM("categories")); |
| |
| typedef ::std::multimap< ::rtl::OUString, ::rtl::OUString > |
| lcl_tOriginalRangeToInternalRangeMap; |
| |
| Sequence< OUString > lcl_getCategoriesFromTable( const SchXMLTable & rTable, bool bHasLabels ) |
| { |
| sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size())); |
| OSL_ENSURE( static_cast< size_t >( nNumRows ) == rTable.aData.size(), "Table too big" ); |
| |
| sal_Int32 nOffset(bHasLabels ? 1 : 0); |
| Sequence< OUString > aResult( nNumRows - nOffset ); |
| sal_Int32 i=nOffset; |
| for( ; i<nNumRows; ++i ) |
| { |
| if( !rTable.aData[i].empty() && (rTable.aData[i].front().eType == SCH_CELL_TYPE_STRING )) |
| aResult[i - nOffset] = rTable.aData[i].front().aString; |
| } |
| return aResult; |
| } |
| |
| std::vector< Reference< chart2::XAxis > > lcl_getAxesHoldingCategoriesFromDiagram( |
| const Reference< chart2::XDiagram > & xDiagram ) |
| { |
| std::vector< Reference< chart2::XAxis > > aRet; |
| |
| Reference< chart2::XAxis > xResult; |
| // return first x-axis as fall-back |
| Reference< chart2::XAxis > xFallBack; |
| try |
| { |
| Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( |
| xDiagram, uno::UNO_QUERY_THROW ); |
| Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( |
| xCooSysCnt->getCoordinateSystems()); |
| for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i ) |
| { |
| Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[i] ); |
| OSL_ASSERT( xCooSys.is()); |
| for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) |
| { |
| const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN); |
| for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) |
| { |
| Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN,nI ); |
| OSL_ASSERT( xAxis.is()); |
| if( xAxis.is()) |
| { |
| chart2::ScaleData aScaleData = xAxis->getScaleData(); |
| if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) ) |
| { |
| aRet.push_back(xAxis); |
| } |
| if( (nN == 0) && !xFallBack.is()) |
| xFallBack.set( xAxis ); |
| } |
| } |
| } |
| } |
| } |
| catch( uno::Exception & ) |
| { |
| } |
| |
| if( aRet.empty()) |
| aRet.push_back(xFallBack); |
| |
| return aRet; |
| } |
| |
| struct lcl_ApplyCellToData : public ::std::unary_function< SchXMLCell, void > |
| { |
| lcl_ApplyCellToData( Sequence< double > & rOutData ) : |
| m_rData( rOutData ), |
| m_nIndex( 0 ), |
| m_nSize( rOutData.getLength()) |
| { |
| ::rtl::math::setNan( &m_fNaN ); |
| } |
| |
| void operator() ( const SchXMLCell & rCell ) |
| { |
| if( m_nIndex < m_nSize ) |
| { |
| if( rCell.eType == SCH_CELL_TYPE_FLOAT ) |
| m_rData[m_nIndex] = rCell.fValue; |
| else |
| m_rData[m_nIndex] = m_fNaN; |
| } |
| ++m_nIndex; |
| } |
| |
| sal_Int32 getCurrentIndex() const |
| { |
| return m_nIndex; |
| } |
| |
| private: |
| Sequence< double > & m_rData; |
| sal_Int32 m_nIndex; |
| sal_Int32 m_nSize; |
| double m_fNaN; |
| }; |
| |
| Sequence< Sequence< double > > lcl_getSwappedArray( const Sequence< Sequence< double > > & rData ) |
| { |
| sal_Int32 nOldOuterSize = rData.getLength(); |
| sal_Int32 nOldInnerSize = (nOldOuterSize == 0 ? 0 : rData[0].getLength()); |
| Sequence< Sequence< double > > aResult( nOldInnerSize ); |
| |
| for( sal_Int32 i=0; i<nOldInnerSize; ++i ) |
| aResult[i].realloc( nOldOuterSize ); |
| |
| for( sal_Int32 nOuter=0; nOuter<nOldOuterSize; ++nOuter ) |
| for( sal_Int32 nInner=0; nInner<nOldInnerSize; ++nInner ) |
| aResult[nInner][nOuter] = rData[nOuter][nInner]; |
| |
| return aResult; |
| } |
| |
| void lcl_fillRangeMapping( |
| const SchXMLTable & rTable, |
| lcl_tOriginalRangeToInternalRangeMap & rOutRangeMap, |
| chart::ChartDataRowSource eDataRowSource ) |
| { |
| sal_Int32 nRowOffset = ( rTable.bHasHeaderRow ? 1 : 0 ); |
| sal_Int32 nColOffset = ( rTable.bHasHeaderColumn ? 1 : 0 ); |
| |
| // Fill range mapping |
| const size_t nTableRowCount( rTable.aData.size()); |
| for( size_t nRow = 0; nRow < nTableRowCount; ++nRow ) |
| { |
| const ::std::vector< SchXMLCell > & rRow( rTable.aData[nRow] ); |
| const size_t nTableColCount( rRow.size()); |
| for( size_t nCol = 0; nCol < nTableColCount; ++nCol ) |
| { |
| OUString aRangeId( rRow[nCol].aRangeId ); |
| if( aRangeId.getLength()) |
| { |
| if( eDataRowSource == chart::ChartDataRowSource_COLUMNS ) |
| { |
| if( nCol == 0 && rTable.bHasHeaderColumn ) |
| { |
| OSL_ASSERT( static_cast< sal_Int32 >( nRow ) == nRowOffset ); |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, lcl_aCategoriesRange )); |
| } |
| else |
| { |
| OUString aColNumStr = OUString::valueOf( static_cast< sal_Int32 >( nCol - nColOffset )); |
| if( nRow == 0 && rTable.bHasHeaderRow ) |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, lcl_aLabelPrefix + aColNumStr )); |
| else |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, aColNumStr )); |
| } |
| } |
| else // eDataRowSource == chart::ChartDataRowSource_ROWS |
| { |
| if( nRow == 0 && rTable.bHasHeaderRow ) |
| { |
| OSL_ASSERT( static_cast< sal_Int32 >( nCol ) == nColOffset ); |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, lcl_aCategoriesRange )); |
| } |
| else |
| { |
| OUString aRowNumStr = OUString::valueOf( static_cast< sal_Int32 >( nRow - nRowOffset )); |
| if( nCol == 0 && rTable.bHasHeaderColumn ) |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, lcl_aLabelPrefix + aRowNumStr )); |
| else |
| rOutRangeMap.insert( lcl_tOriginalRangeToInternalRangeMap::value_type( |
| aRangeId, aRowNumStr )); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| Reference< chart2::data::XDataSequence > |
| lcl_reassignDataSequence( |
| const Reference< chart2::data::XDataSequence > & xSequence, |
| const Reference< chart2::data::XDataProvider > & xDataProvider, |
| lcl_tOriginalRangeToInternalRangeMap & rRangeMap, |
| const OUString & rRange ) |
| { |
| Reference< chart2::data::XDataSequence > xResult( xSequence ); |
| lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); |
| if( aIt != rRangeMap.end()) |
| { |
| // set sequence with correct data |
| xResult.set( xDataProvider->createDataSequenceByRangeRepresentation( aIt->second )); |
| // remove translation, because it was used |
| rRangeMap.erase( aIt ); |
| } |
| |
| return xResult; |
| } |
| |
| bool lcl_mapContainsRange( |
| lcl_tOriginalRangeToInternalRangeMap & rRangeMap, |
| const OUString & rRange ) |
| { |
| lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); |
| return ( aIt != rRangeMap.end()); |
| } |
| |
| bool lcl_tableOfRangeMatches( |
| const ::rtl::OUString & rRange, |
| const ::rtl::OUString & rTableName ) |
| { |
| // both strings are non-empty and the table name is part of the range |
| return ( (rRange.getLength() > 0) && |
| (rTableName.getLength() > 0) && |
| (rRange.indexOf( rTableName ) != -1 )); |
| } |
| |
| template< typename T > |
| ::std::vector< T > lcl_SequenceToVector( const uno::Sequence< T > & rSequence ) |
| { |
| ::std::vector< T > aResult( rSequence.getLength()); |
| ::std::copy( rSequence.getConstArray(), rSequence.getConstArray() + rSequence.getLength(), |
| aResult.begin()); |
| return aResult; |
| } |
| |
| } // anonymous namespace |
| |
| |
| // ---------------------------------------- |
| // class SchXMLTableContext |
| // ---------------------------------------- |
| |
| SchXMLTableContext::SchXMLTableContext( SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ), |
| mbHasRowPermutation( false ), |
| mbHasColumnPermutation( false ) |
| { |
| mrTable.nColumnIndex = -1; |
| mrTable.nMaxColumnIndex = -1; |
| mrTable.nRowIndex = -1; |
| mrTable.aData.clear(); |
| } |
| |
| SchXMLTableContext::~SchXMLTableContext() |
| { |
| } |
| |
| SvXMLImportContext *SchXMLTableContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const rtl::OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| SvXMLImportContext* pContext = 0; |
| const SvXMLTokenMap& rTokenMap = mrImportHelper.GetTableElemTokenMap(); |
| |
| switch( rTokenMap.Get( nPrefix, rLocalName )) |
| { |
| case XML_TOK_TABLE_HEADER_COLS: |
| mrTable.bHasHeaderColumn = true; |
| // fall through intended |
| case XML_TOK_TABLE_COLUMNS: |
| pContext = new SchXMLTableColumnsContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| break; |
| |
| case XML_TOK_TABLE_COLUMN: |
| pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| break; |
| |
| case XML_TOK_TABLE_HEADER_ROWS: |
| mrTable.bHasHeaderRow = true; |
| // fall through intended |
| case XML_TOK_TABLE_ROWS: |
| pContext = new SchXMLTableRowsContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| break; |
| |
| case XML_TOK_TABLE_ROW: |
| pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| break; |
| |
| default: |
| pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| } |
| |
| return pContext; |
| } |
| |
| void SchXMLTableContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) |
| { |
| // get table-name |
| sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; |
| |
| for( sal_Int16 i = 0; i < nAttrCount; i++ ) |
| { |
| rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); |
| rtl::OUString aLocalName; |
| sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); |
| if ( nPrefix == XML_NAMESPACE_TABLE ) |
| { |
| if ( IsXMLToken( aLocalName, XML_NAME ) ) |
| { |
| mrTable.aTableNameOfFile = xAttrList->getValueByIndex( i ); |
| } |
| else if ( IsXMLToken( aLocalName, XML_PROTECTED ) ) |
| { |
| if ( IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) ) |
| { |
| mrTable.bProtected = true; |
| } |
| } |
| } |
| } |
| } |
| |
| void SchXMLTableContext::EndElement() |
| { |
| if( mbHasColumnPermutation ) |
| { |
| OSL_ASSERT( !mbHasRowPermutation ); |
| ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maColumnPermutation )); |
| OSL_ASSERT( !aPermutation.empty()); |
| if( aPermutation.empty()) |
| return; |
| |
| // permute the values of all rows according to aPermutation |
| for( ::std::vector< ::std::vector< SchXMLCell > >::iterator aRowIt( mrTable.aData.begin()); |
| aRowIt != mrTable.aData.end(); ++aRowIt ) |
| { |
| bool bModified = false; |
| ::std::vector< SchXMLCell > aModifiedRow; |
| const size_t nPermSize = aPermutation.size(); |
| OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end()))); |
| const size_t nRowSize = aRowIt->size(); |
| const size_t nDestSize = ::std::min( nPermSize, nRowSize ); |
| for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) |
| { |
| const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); |
| if( nSourceIndex != nDestinationIndex && |
| nSourceIndex < nRowSize ) |
| { |
| // copy original on first real permutation |
| if( !bModified ) |
| { |
| OSL_ASSERT( aModifiedRow.empty()); |
| aModifiedRow.reserve( aRowIt->size()); |
| ::std::copy( aRowIt->begin(), aRowIt->end(), ::std::back_inserter( aModifiedRow )); |
| OSL_ASSERT( !aModifiedRow.empty()); |
| } |
| OSL_ASSERT( nDestinationIndex < aModifiedRow.size()); |
| aModifiedRow[ nDestinationIndex ] = (*aRowIt)[ nSourceIndex ]; |
| bModified = true; |
| } |
| } |
| // copy back |
| if( bModified ) |
| ::std::copy( aModifiedRow.begin(), aModifiedRow.end(), aRowIt->begin()); |
| } |
| } |
| else if( mbHasRowPermutation ) |
| { |
| ::std::vector< sal_Int32 > aPermutation( lcl_SequenceToVector( maRowPermutation )); |
| OSL_ASSERT( !aPermutation.empty()); |
| if( aPermutation.empty()) |
| return; |
| |
| bool bModified = false; |
| const size_t nPermSize = aPermutation.size(); |
| OSL_ASSERT( static_cast< sal_Int32 >( nPermSize ) - 1 == *(::std::max_element( aPermutation.begin(), aPermutation.end()))); |
| const size_t nTableRowCount = mrTable.aData.size(); |
| const size_t nDestSize = ::std::min( nPermSize, nTableRowCount ); |
| ::std::vector< ::std::vector< SchXMLCell > > aDestination; |
| for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) |
| { |
| const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); |
| if( nSourceIndex != nDestinationIndex && |
| nSourceIndex < nTableRowCount ) |
| { |
| // copy original on first real permutation |
| if( !bModified ) |
| { |
| OSL_ASSERT( aDestination.empty()); |
| aDestination.reserve( mrTable.aData.size()); |
| ::std::copy( mrTable.aData.begin(), mrTable.aData.end(), ::std::back_inserter( aDestination )); |
| OSL_ASSERT( !aDestination.empty()); |
| } |
| OSL_ASSERT( nDestinationIndex < aDestination.size()); |
| aDestination[ nDestinationIndex ] = mrTable.aData[ nSourceIndex ]; |
| bModified = true; |
| } |
| } |
| if( bModified ) |
| { |
| // copy back |
| ::std::copy( aDestination.begin(), aDestination.end(), mrTable.aData.begin()); |
| } |
| } |
| } |
| |
| void SchXMLTableContext::setRowPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) |
| { |
| maRowPermutation = rPermutation; |
| mbHasRowPermutation = ( rPermutation.getLength() > 0 ); |
| |
| if( mbHasRowPermutation && mbHasColumnPermutation ) |
| { |
| mbHasColumnPermutation = false; |
| maColumnPermutation.realloc( 0 ); |
| } |
| } |
| |
| void SchXMLTableContext::setColumnPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) |
| { |
| maColumnPermutation = rPermutation; |
| mbHasColumnPermutation = ( rPermutation.getLength() > 0 ); |
| |
| if( mbHasColumnPermutation && mbHasRowPermutation ) |
| { |
| mbHasRowPermutation = false; |
| maRowPermutation.realloc( 0 ); |
| } |
| } |
| |
| // ======================================== |
| // classes for columns |
| // ======================================== |
| |
| // ---------------------------------------- |
| // class SchXMLTableColumnsContext |
| // ---------------------------------------- |
| |
| SchXMLTableColumnsContext::SchXMLTableColumnsContext( |
| SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLocalName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ) |
| { |
| } |
| |
| SchXMLTableColumnsContext::~SchXMLTableColumnsContext() |
| { |
| } |
| |
| SvXMLImportContext* SchXMLTableColumnsContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const rtl::OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| SvXMLImportContext* pContext = 0; |
| |
| if( nPrefix == XML_NAMESPACE_TABLE && |
| IsXMLToken( rLocalName, XML_TABLE_COLUMN ) ) |
| { |
| pContext = new SchXMLTableColumnContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| } |
| else |
| pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| |
| return pContext; |
| } |
| |
| // ---------------------------------------- |
| // class SchXMLTableColumnContext |
| // ---------------------------------------- |
| |
| SchXMLTableColumnContext::SchXMLTableColumnContext( |
| SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLocalName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ) |
| { |
| } |
| |
| void SchXMLTableColumnContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) |
| { |
| // get number-columns-repeated attribute |
| sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; |
| sal_Int32 nRepeated = 1; |
| bool bHidden = false; |
| |
| for( sal_Int16 i = 0; i < nAttrCount; i++ ) |
| { |
| rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); |
| rtl::OUString aLocalName; |
| sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); |
| |
| if( nPrefix == XML_NAMESPACE_TABLE && |
| IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) ) |
| { |
| rtl::OUString aValue = xAttrList->getValueByIndex( i ); |
| if( aValue.getLength()) |
| nRepeated = aValue.toInt32(); |
| } |
| else if( nPrefix == XML_NAMESPACE_TABLE && |
| IsXMLToken( aLocalName, XML_VISIBILITY ) ) |
| { |
| rtl::OUString aVisibility = xAttrList->getValueByIndex( i ); |
| bHidden = aVisibility.equals( GetXMLToken( XML_COLLAPSE ) ); |
| } |
| } |
| |
| sal_Int32 nOldCount = mrTable.nNumberOfColsEstimate; |
| sal_Int32 nNewCount = nOldCount + nRepeated; |
| mrTable.nNumberOfColsEstimate = nNewCount; |
| |
| if( bHidden ) |
| { |
| //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) |
| sal_Int32 nColOffset = ( mrTable.bHasHeaderColumn ? 1 : 0 ); |
| for( sal_Int32 nN = nOldCount; nN<nNewCount; nN++ ) |
| { |
| sal_Int32 nHiddenColumnIndex = nN-nColOffset; |
| if( nHiddenColumnIndex>=0 ) |
| mrTable.aHiddenColumns.push_back(nHiddenColumnIndex); |
| } |
| } |
| } |
| |
| SchXMLTableColumnContext::~SchXMLTableColumnContext() |
| { |
| } |
| |
| // ======================================== |
| // classes for rows |
| // ======================================== |
| |
| // ---------------------------------------- |
| // class SchXMLTableRowsContext |
| // ---------------------------------------- |
| |
| SchXMLTableRowsContext::SchXMLTableRowsContext( |
| SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLocalName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ) |
| { |
| } |
| |
| SchXMLTableRowsContext::~SchXMLTableRowsContext() |
| { |
| } |
| |
| SvXMLImportContext* SchXMLTableRowsContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const rtl::OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| SvXMLImportContext* pContext = 0; |
| |
| if( nPrefix == XML_NAMESPACE_TABLE && |
| IsXMLToken( rLocalName, XML_TABLE_ROW ) ) |
| { |
| pContext = new SchXMLTableRowContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| } |
| else |
| { |
| pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| } |
| |
| return pContext; |
| } |
| |
| // ---------------------------------------- |
| // class SchXMLTableRowContext |
| // ---------------------------------------- |
| |
| SchXMLTableRowContext::SchXMLTableRowContext( |
| SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLocalName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ) |
| { |
| mrTable.nColumnIndex = -1; |
| mrTable.nRowIndex++; |
| |
| std::vector< SchXMLCell > aNewRow; |
| aNewRow.reserve( mrTable.nNumberOfColsEstimate ); |
| while( mrTable.aData.size() <= (unsigned long)mrTable.nRowIndex ) |
| mrTable.aData.push_back( aNewRow ); |
| } |
| |
| SchXMLTableRowContext::~SchXMLTableRowContext() |
| { |
| } |
| |
| SvXMLImportContext* SchXMLTableRowContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const rtl::OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| SvXMLImportContext* pContext = 0; |
| |
| // <table:table-cell> element |
| if( nPrefix == XML_NAMESPACE_TABLE && |
| IsXMLToken(rLocalName, XML_TABLE_CELL ) ) |
| { |
| pContext = new SchXMLTableCellContext( mrImportHelper, GetImport(), rLocalName, mrTable ); |
| } |
| else |
| { |
| pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| } |
| |
| return pContext; |
| } |
| |
| //--------------------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------------------- |
| |
| class SchXMLRangeSomewhereContext : public SvXMLImportContext |
| { |
| //#i113950# previously the range was exported to attribute text:id, |
| //but that attribute does not allow arbitrary strings anymore |
| //so we need to find an alternative to save that range info for copy/paste scenario ... |
| //-> use description at an empty group element for now |
| |
| private: |
| ::rtl::OUString& mrRangeString; |
| ::rtl::OUStringBuffer maRangeStringBuffer; |
| |
| public: |
| SchXMLRangeSomewhereContext( SvXMLImport& rImport, |
| sal_uInt16 nPrefix, |
| const ::rtl::OUString& rLocalName, |
| ::rtl::OUString& rRangeString ); |
| virtual ~SchXMLRangeSomewhereContext(); |
| |
| virtual SvXMLImportContext* CreateChildContext( |
| sal_uInt16 nPrefix, |
| const ::rtl::OUString& rLocalName, |
| const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttrList ); |
| virtual void EndElement(); |
| }; |
| |
| //--------------------------------------------------------------------------------------------------- |
| //--------------------------------------------------------------------------------------------------- |
| |
| // ======================================== |
| // classes for cells and their content |
| // ======================================== |
| |
| // ---------------------------------------- |
| // class SchXMLTableCellContext |
| // ---------------------------------------- |
| |
| SchXMLTableCellContext::SchXMLTableCellContext( |
| SchXMLImportHelper& rImpHelper, |
| SvXMLImport& rImport, |
| const rtl::OUString& rLocalName, |
| SchXMLTable& aTable ) : |
| SvXMLImportContext( rImport, XML_NAMESPACE_TABLE, rLocalName ), |
| mrImportHelper( rImpHelper ), |
| mrTable( aTable ) |
| { |
| } |
| |
| SchXMLTableCellContext::~SchXMLTableCellContext() |
| { |
| } |
| |
| void SchXMLTableCellContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) |
| { |
| sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0; |
| rtl::OUString aValue; |
| rtl::OUString aLocalName; |
| rtl::OUString aCellContent; |
| SchXMLCellType eValueType = SCH_CELL_TYPE_UNKNOWN; |
| const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetCellAttrTokenMap(); |
| |
| for( sal_Int16 i = 0; i < nAttrCount; i++ ) |
| { |
| rtl::OUString sAttrName = xAttrList->getNameByIndex( i ); |
| sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); |
| |
| switch( rAttrTokenMap.Get( nPrefix, aLocalName )) |
| { |
| case XML_TOK_CELL_VAL_TYPE: |
| aValue = xAttrList->getValueByIndex( i ); |
| if( IsXMLToken( aValue, XML_FLOAT ) ) |
| eValueType = SCH_CELL_TYPE_FLOAT; |
| else if( IsXMLToken( aValue, XML_STRING ) ) |
| eValueType = SCH_CELL_TYPE_STRING; |
| break; |
| |
| case XML_TOK_CELL_VALUE: |
| aCellContent = xAttrList->getValueByIndex( i ); |
| break; |
| } |
| } |
| |
| mbReadText = sal_True; |
| SchXMLCell aCell; |
| aCell.eType = eValueType; |
| |
| if( eValueType == SCH_CELL_TYPE_FLOAT ) |
| { |
| double fData; |
| // the result may be false if a NaN is read, but that's ok |
| SvXMLUnitConverter::convertDouble( fData, aCellContent ); |
| |
| aCell.fValue = fData; |
| // dont read text from following <text:p> or <text:list> element |
| mbReadText = sal_False; |
| } |
| |
| mrTable.aData[ mrTable.nRowIndex ].push_back( aCell ); |
| mrTable.nColumnIndex++; |
| if( mrTable.nMaxColumnIndex < mrTable.nColumnIndex ) |
| mrTable.nMaxColumnIndex = mrTable.nColumnIndex; |
| } |
| |
| SvXMLImportContext* SchXMLTableCellContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const rtl::OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| SvXMLImportContext* pContext = 0; |
| |
| // <text:list> element |
| if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_LIST ) && mbReadText ) |
| { |
| SchXMLCell& rCell = mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ]; |
| rCell.pComplexString = new Sequence< OUString >(); |
| rCell.eType = SCH_CELL_TYPE_COMPLEX_STRING; |
| pContext = new SchXMLTextListContext( GetImport(), rLocalName, *rCell.pComplexString ); |
| mbReadText = sal_False;//don't apply text from <text:p> |
| } |
| // <text:p> element - read text (and range from text:id old version) |
| else if( nPrefix == XML_NAMESPACE_TEXT && IsXMLToken( rLocalName, XML_P ) ) |
| { |
| pContext = new SchXMLParagraphContext( GetImport(), rLocalName, maCellContent, &maRangeId ); |
| } |
| // <draw:g> element - read range |
| else if( nPrefix == XML_NAMESPACE_DRAW && IsXMLToken( rLocalName, XML_G ) ) |
| { |
| //#i113950# previously the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore |
| //so we need to find an alternative to save that range info for copy/paste scenario ... -> use description at an empty group element for now |
| pContext = new SchXMLRangeSomewhereContext( GetImport(), nPrefix, rLocalName, maRangeId ); |
| } |
| else |
| { |
| pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| } |
| |
| return pContext; |
| } |
| |
| void SchXMLTableCellContext::EndElement() |
| { |
| if( mbReadText && maCellContent.getLength() ) //apply text from <text:p> element |
| mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aString = maCellContent; |
| if( maRangeId.getLength()) |
| mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aRangeId = maRangeId; |
| } |
| |
| // ======================================== |
| |
| void lcl_ApplyCellToComplexLabel( const SchXMLCell& rCell, Sequence< uno::Any >& rComplexLabel ) |
| { |
| if( rCell.eType == SCH_CELL_TYPE_STRING ) |
| { |
| rComplexLabel.realloc(1); |
| rComplexLabel[0] = uno::makeAny( rCell.aString ); |
| } |
| else if( rCell.pComplexString && rCell.eType == SCH_CELL_TYPE_COMPLEX_STRING ) |
| { |
| sal_Int32 nCount = rCell.pComplexString->getLength(); |
| rComplexLabel.realloc( nCount ); |
| for( sal_Int32 nN=0; nN<nCount; nN++) |
| rComplexLabel[nN] = uno::makeAny((*rCell.pComplexString)[nN]); |
| } |
| else if( rCell.eType == SCH_CELL_TYPE_FLOAT ) |
| { |
| rComplexLabel.realloc(1); |
| rComplexLabel[0] = uno::makeAny( rCell.fValue ); |
| } |
| } |
| |
| void SchXMLTableHelper::applyTableToInternalDataProvider( |
| const SchXMLTable& rTable, |
| uno::Reference< chart2::XChartDocument > xChartDoc ) |
| { |
| // apply all data read from the local table to the internal data provider |
| if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) |
| return; |
| Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider() ); |
| if( !xDataProv.is() ) |
| return; |
| |
| //prepare the read local table data |
| sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size())); |
| sal_Int32 nRowOffset = 0; |
| if( rTable.bHasHeaderRow ) |
| { |
| --nNumRows; |
| nRowOffset = 1; |
| } |
| sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 ); |
| sal_Int32 nColOffset = 0; |
| if( rTable.bHasHeaderColumn ) |
| { |
| --nNumColumns; |
| nColOffset = 1; |
| } |
| |
| Sequence< Sequence< double > > aDataInRows( nNumRows ); |
| Sequence< Sequence< uno::Any > > aComplexRowDescriptions( nNumRows ); |
| Sequence< Sequence< uno::Any > > aComplexColumnDescriptions( nNumColumns ); |
| for( sal_Int32 i=0; i<nNumRows; ++i ) |
| aDataInRows[i].realloc( nNumColumns ); |
| |
| if( rTable.aData.begin() != rTable.aData.end()) |
| { |
| //apply column labels |
| if( rTable.bHasHeaderRow ) |
| { |
| const ::std::vector< SchXMLCell >& rFirstRow = rTable.aData.front(); |
| const sal_Int32 nColumnLabelsSize = aComplexColumnDescriptions.getLength(); |
| const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize, static_cast< sal_Int32 >( rFirstRow.size()) - nColOffset ); |
| OSL_ASSERT( nMax == nColumnLabelsSize ); |
| for( sal_Int32 i=0; i<nMax; ++i ) |
| lcl_ApplyCellToComplexLabel( rFirstRow[i+nColOffset], aComplexColumnDescriptions[i] ); |
| } |
| |
| std::vector< ::std::vector< SchXMLCell > >::const_iterator aRowIter( rTable.aData.begin() + nRowOffset ); |
| std::vector< ::std::vector< SchXMLCell > >::const_iterator aEnd( rTable.aData.end() ); |
| for( sal_Int32 nRow = 0; aRowIter != aEnd && nRow < nNumRows; ++aRowIter, ++nRow ) |
| { |
| const ::std::vector< SchXMLCell >& rRow = *aRowIter; |
| if( !rRow.empty() ) |
| { |
| // row label |
| if( rTable.bHasHeaderColumn ) |
| lcl_ApplyCellToComplexLabel( rRow.front(), aComplexRowDescriptions[nRow] ); |
| |
| // values |
| Sequence< double >& rTargetRow = aDataInRows[nRow]; |
| lcl_ApplyCellToData aApplyCellToData = ::std::for_each( rRow.begin() + nColOffset, rRow.end(), lcl_ApplyCellToData( rTargetRow ) ); |
| double fNaN = 0.0; |
| ::rtl::math::setNan( &fNaN ); |
| for( sal_Int32 nCurrentIndex = aApplyCellToData.getCurrentIndex(); nCurrentIndex<nNumColumns; nCurrentIndex++ ) |
| rTargetRow[nCurrentIndex] = fNaN;//#i110615# |
| } |
| } |
| } |
| |
| //apply the collected data to the chart |
| Reference< chart2::XAnyDescriptionAccess > xDataAccess( xDataProv, uno::UNO_QUERY ); |
| if( !xDataAccess.is() ) |
| return; |
| |
| xDataAccess->setData( aDataInRows ); |
| if( rTable.bHasHeaderColumn ) |
| xDataAccess->setAnyRowDescriptions( aComplexRowDescriptions ); |
| if( rTable.bHasHeaderRow ) |
| xDataAccess->setAnyColumnDescriptions( aComplexColumnDescriptions ); |
| |
| if ( rTable.bProtected ) |
| { |
| try |
| { |
| Reference< beans::XPropertySet > xProps( xChartDoc, uno::UNO_QUERY_THROW ); |
| xProps->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableDataTableDialog" ) ), uno::makeAny( sal_True ) ); |
| xProps->setPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DisableComplexChartTypes" ) ), uno::makeAny( sal_True ) ); |
| } |
| catch ( uno::Exception& ) |
| { |
| } |
| } |
| } |
| |
| void SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( |
| const SchXMLTable& rTable, |
| const tSchXMLLSequencesPerIndex & rLSequencesPerIndex, |
| uno::Reference< chart2::XChartDocument > xChartDoc, |
| chart::ChartDataRowSource eDataRowSource ) |
| { |
| if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider())) |
| return; |
| |
| // If the range-strings are valid (starting with "local-table") they should |
| // be interpreted like given, otherwise (when the ranges refer to Calc- or |
| // Writer-ranges, but the container is not available like when pasting a |
| // chart from Calc to Impress) the range is ignored, and every object gets |
| // one table column in the order of appearance, which is: 1. categories, |
| // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values) |
| |
| Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider()); |
| |
| // create a mapping from original ranges to new ranges |
| lcl_tOriginalRangeToInternalRangeMap aRangeMap; |
| |
| lcl_fillRangeMapping( rTable, aRangeMap, eDataRowSource ); |
| |
| bool bCategoriesApplied = false; |
| // translate ranges (using the map created before) |
| for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin()); |
| aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt ) |
| { |
| if( aLSeqIt->second.is()) |
| { |
| // values/error bars/categories |
| if( aLSeqIt->first.second == SCH_XML_PART_VALUES || |
| aLSeqIt->first.second == SCH_XML_PART_ERROR_BARS ) |
| { |
| Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getValues()); |
| OUString aRange; |
| if( xSeq.is() && |
| SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && |
| lcl_mapContainsRange( aRangeMap, aRange )) |
| { |
| Reference< chart2::data::XDataSequence > xNewSeq( |
| lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); |
| if( xNewSeq != xSeq ) |
| { |
| SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), |
| Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); |
| aLSeqIt->second->setValues( xNewSeq ); |
| } |
| } |
| else |
| { |
| if( lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) |
| { |
| if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX ) |
| bCategoriesApplied = true; |
| } |
| else |
| { |
| if( aLSeqIt->first.first == SCH_XML_CATEGORIES_INDEX ) |
| { |
| Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY ); |
| Reference< chart2::data::XDataSequence > xNewSequence( |
| xDataProv->createDataSequenceByRangeRepresentation( |
| OUString(RTL_CONSTASCII_USTRINGPARAM("categories")))); |
| SchXMLTools::copyProperties( |
| xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); |
| aLSeqIt->second->setValues( xNewSequence ); |
| bCategoriesApplied = true; |
| } |
| else |
| { |
| Reference< beans::XPropertySet > xOldSequenceProp( aLSeqIt->second->getValues(), uno::UNO_QUERY ); |
| OUString aRep( OUString::valueOf( aLSeqIt->first.first )); |
| Reference< chart2::data::XDataSequence > xNewSequence( |
| xDataProv->createDataSequenceByRangeRepresentation( aRep )); |
| SchXMLTools::copyProperties( |
| xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); |
| aLSeqIt->second->setValues( xNewSequence ); |
| } |
| } |
| } |
| } |
| else // labels |
| { |
| OSL_ASSERT( aLSeqIt->first.second == SCH_XML_PART_LABEL ); |
| // labels |
| Reference< chart2::data::XDataSequence > xSeq( aLSeqIt->second->getLabel()); |
| OUString aRange; |
| if( xSeq.is() && |
| SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && |
| lcl_mapContainsRange( aRangeMap, aRange )) |
| { |
| Reference< chart2::data::XDataSequence > xNewSeq( |
| lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); |
| if( xNewSeq != xSeq ) |
| { |
| SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), |
| Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); |
| aLSeqIt->second->setLabel( xNewSeq ); |
| } |
| } |
| else if( ! lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) |
| { |
| OUString aRep( RTL_CONSTASCII_USTRINGPARAM("label ")); |
| aRep += OUString::valueOf( aLSeqIt->first.first ); |
| |
| Reference< chart2::data::XDataSequence > xNewSeq( |
| xDataProv->createDataSequenceByRangeRepresentation( aRep )); |
| SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), |
| Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); |
| aLSeqIt->second->setLabel( xNewSeq ); |
| } |
| } |
| } |
| } |
| |
| // there exist files with own data without a categories element but with row |
| // descriptions. The row descriptions were used as categories even without |
| // the categories element |
| if( ! bCategoriesApplied ) |
| { |
| SchXMLTools::CreateCategories( |
| xDataProv, xChartDoc, OUString(RTL_CONSTASCII_USTRINGPARAM("categories")), |
| 0 /* nCooSysIndex */, 0 /* nDimension */ ); |
| } |
| |
| //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) |
| //remove series that consist only of hidden columns |
| Reference< chart2::XInternalDataProvider > xInternalDataProvider( xDataProv, uno::UNO_QUERY ); |
| if( xInternalDataProvider.is() && !rTable.aHiddenColumns.empty() ) |
| { |
| try |
| { |
| Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChartDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); |
| Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); |
| for( sal_Int32 nC=0; nC<aCooSysSeq.getLength(); ++nC ) |
| { |
| Reference< chart2::XChartTypeContainer > xCooSysContainer( aCooSysSeq[nC], uno::UNO_QUERY_THROW ); |
| Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCooSysContainer->getChartTypes()); |
| for( sal_Int32 nT=0; nT<aChartTypeSeq.getLength(); ++nT ) |
| { |
| Reference< chart2::XDataSeriesContainer > xSeriesContainer( aChartTypeSeq[nT], uno::UNO_QUERY ); |
| if(!xSeriesContainer.is()) |
| continue; |
| Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesContainer->getDataSeries() ); |
| std::vector< Reference< chart2::XDataSeries > > aRemainingSeries; |
| |
| for( sal_Int32 nS = 0; nS < aSeriesSeq.getLength(); nS++ ) |
| { |
| Reference< chart2::data::XDataSource > xDataSource( aSeriesSeq[nS], uno::UNO_QUERY ); |
| if( xDataSource.is() ) |
| { |
| bool bHasUnhiddenColumns = false; |
| rtl::OUString aRange; |
| uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences() ); |
| for( sal_Int32 nN=0; nN< aSequences.getLength(); ++nN ) |
| { |
| Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aSequences[nN] ); |
| if(!xLabeledSequence.is()) |
| continue; |
| Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); |
| if( xValues.is() ) |
| { |
| aRange = xValues->getSourceRangeRepresentation(); |
| if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aRange.toInt32() ) == rTable.aHiddenColumns.end() ) |
| bHasUnhiddenColumns = true; |
| } |
| if( !bHasUnhiddenColumns ) |
| { |
| Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); |
| if( xLabel.is() ) |
| { |
| aRange = xLabel->getSourceRangeRepresentation(); |
| sal_Int32 nSearchIndex = 0; |
| OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex ); |
| if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aSecondToken.toInt32() ) == rTable.aHiddenColumns.end() ) |
| bHasUnhiddenColumns = true; |
| } |
| } |
| } |
| if( bHasUnhiddenColumns ) |
| aRemainingSeries.push_back( aSeriesSeq[nS] ); |
| } |
| } |
| |
| if( static_cast<sal_Int32>(aRemainingSeries.size()) != aSeriesSeq.getLength() ) |
| { |
| //remove the series that have only hidden data |
| Sequence< Reference< chart2::XDataSeries > > aRemainingSeriesSeq( aRemainingSeries.size()); |
| ::std::copy( aRemainingSeries.begin(), aRemainingSeries.end(), aRemainingSeriesSeq.getArray()); |
| xSeriesContainer->setDataSeries( aRemainingSeriesSeq ); |
| |
| //remove unused sequences |
| Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY ); |
| if( xDataSource.is() ) |
| { |
| //first detect which collumns are really used |
| std::map< sal_Int32, bool > aUsageMap; |
| rtl::OUString aRange; |
| Sequence< Reference< chart2::data::XLabeledDataSequence > > aUsedSequences( xDataSource->getDataSequences() ); |
| for( sal_Int32 nN=0; nN< aUsedSequences.getLength(); ++nN ) |
| { |
| Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aUsedSequences[nN] ); |
| if(!xLabeledSequence.is()) |
| continue; |
| Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); |
| if( xValues.is() ) |
| { |
| aRange = xValues->getSourceRangeRepresentation(); |
| sal_Int32 nIndex = aRange.toInt32(); |
| if( nIndex!=0 || !aRange.equals(lcl_aCategoriesRange) ) |
| aUsageMap[nIndex] = true; |
| } |
| Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); |
| if( xLabel.is() ) |
| { |
| aRange = xLabel->getSourceRangeRepresentation(); |
| sal_Int32 nSearchIndex = 0; |
| OUString aSecondToken = aRange.getToken( 1, ' ', nSearchIndex ); |
| if( aSecondToken.getLength() ) |
| aUsageMap[aSecondToken.toInt32()] = true; |
| } |
| } |
| |
| ::std::vector< sal_Int32 > aSequenceIndexesToDelete; |
| for( ::std::vector< sal_Int32 >::const_iterator aIt( |
| rTable.aHiddenColumns.begin()); aIt != rTable.aHiddenColumns.end(); ++aIt ) |
| { |
| sal_Int32 nSequenceIndex = *aIt; |
| if( aUsageMap.find(nSequenceIndex) != aUsageMap.end() ) |
| continue; |
| aSequenceIndexesToDelete.push_back(nSequenceIndex); |
| } |
| |
| // delete unnecessary sequences of the internal data |
| // iterate using greatest index first, so that deletion does not |
| // shift other sequences that will be deleted later |
| ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); |
| for( ::std::vector< sal_Int32 >::reverse_iterator aIt( |
| aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) |
| { |
| if( *aIt != -1 ) |
| xInternalDataProvider->deleteSequence( *aIt ); |
| } |
| } |
| } |
| } |
| } |
| } |
| catch( uno::Exception & ex ) |
| { |
| (void)ex; // avoid warning for pro build |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------------------------------------------- |
| |
| SchXMLRangeSomewhereContext::SchXMLRangeSomewhereContext( SvXMLImport& rImport, |
| sal_uInt16 nPrefix, |
| const OUString& rLocalName, |
| OUString& rRangeString ) : |
| SvXMLImportContext( rImport, nPrefix, rLocalName ), |
| mrRangeString( rRangeString ) |
| { |
| } |
| |
| SchXMLRangeSomewhereContext::~SchXMLRangeSomewhereContext() |
| { |
| } |
| |
| SvXMLImportContext* SchXMLRangeSomewhereContext::CreateChildContext( |
| sal_uInt16 nPrefix, |
| const OUString& rLocalName, |
| const uno::Reference< xml::sax::XAttributeList >& ) |
| { |
| if( XML_NAMESPACE_SVG == nPrefix && IsXMLToken( rLocalName, XML_DESC ) ) |
| { |
| return new XMLStringBufferImportContext( |
| GetImport(), nPrefix, rLocalName, maRangeStringBuffer ); |
| } |
| return new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); |
| } |
| |
| void SchXMLRangeSomewhereContext::EndElement() |
| { |
| mrRangeString = maRangeStringBuffer.makeStringAndClear(); |
| } |