/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace com::sun::star::drawing { class XShape; } namespace chart { using namespace ::com::sun::star; using namespace ::com::sun::star::chart2; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Any; const sal_Unicode m_aMultiClick[] = u"MultiClick"; const sal_Unicode m_aDragMethodEquals[] = u"DragMethod="; const sal_Unicode m_aDragParameterEquals[] = u"DragParameter="; const sal_Unicode m_aProtocol[] = u"CID/"; const OUString m_aPieSegmentDragMethodServiceName("PieSegmentDragging"); namespace { OUString lcl_createClassificationStringForType( ObjectType eObjectType , std::u16string_view rDragMethodServiceName , std::u16string_view rDragParameterString ) { OUStringBuffer aRet; switch( eObjectType ) { //these object types are all selected only after their parents was selected before case OBJECTTYPE_LEGEND_ENTRY: //parent is intended to be OBJECTTYPE_LEGEND case OBJECTTYPE_DATA_POINT: //parent is intended to be OBJECTTYPE_DATA_SERIES case OBJECTTYPE_DATA_LABEL: //parent is intended to be OBJECTTYPE_DATA_LABELS case OBJECTTYPE_DATA_ERRORS_X: //parent is intended to be OBJECTTYPE_DATA_ERRORS case OBJECTTYPE_DATA_ERRORS_Y: //parent is intended to be OBJECTTYPE_DATA_ERRORS case OBJECTTYPE_DATA_ERRORS_Z: //parent is intended to be OBJECTTYPE_DATA_ERRORS aRet=m_aMultiClick; break; default: break;//empty string } if( !rDragMethodServiceName.empty() ) { if( !aRet.isEmpty() ) aRet.append(":"); aRet.append( m_aDragMethodEquals ); aRet.append( rDragMethodServiceName ); if( !rDragParameterString.empty() ) { if( !aRet.isEmpty() ) aRet.append(":"); aRet.append( m_aDragParameterEquals ); aRet.append( rDragParameterString ); } } return aRet.makeStringAndClear(); } typedef std::map< TitleHelper::eTitleType, OUString > tTitleMap; const tTitleMap& lcl_getTitleMap() { //maps the title type to the ParentParticle for that title static tTitleMap s_aTitleMap{ {TitleHelper::MAIN_TITLE, ""}, {TitleHelper::SUB_TITLE, "D=0"}, {TitleHelper::X_AXIS_TITLE, "D=0:CS=0:Axis=0,0"}, {TitleHelper::Y_AXIS_TITLE, "D=0:CS=0:Axis=1,0"}, {TitleHelper::Z_AXIS_TITLE, "D=0:CS=0:Axis=2,0"}, {TitleHelper::SECONDARY_X_AXIS_TITLE, "D=0:CS=0:Axis=0,1"}, {TitleHelper::SECONDARY_Y_AXIS_TITLE, "D=0:CS=0:Axis=1,1"}}; return s_aTitleMap; } OUString lcl_getTitleParentParticle( TitleHelper::eTitleType aTitleType ) { OUString aRet; const tTitleMap& rMap = lcl_getTitleMap(); tTitleMap::const_iterator aIt( rMap.find( aTitleType ) ); if( aIt != rMap.end()) aRet = (*aIt).second; return aRet; } rtl::Reference lcl_getFirstStockChartType( const rtl::Reference<::chart::ChartModel>& xChartModel ) { rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); if(!xDiagram.is()) return nullptr; //iterate through all coordinate systems const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysList ) { //iterate through all chart types in the current coordinate system for( rtl::Reference< ChartType > const & xChartType : coords->getChartTypes2() ) { OUString aChartType = xChartType->getChartType(); if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) return xChartType; } } return nullptr; } std::u16string_view lcl_getIndexStringAfterString( std::u16string_view rString, std::u16string_view rSearchString ) { size_t nIndexStart = rString.rfind( rSearchString ); if( nIndexStart == std::u16string_view::npos ) return std::u16string_view(); nIndexStart += rSearchString.size(); size_t nIndexEnd = rString.size(); size_t nNextColon = rString.find( ':', nIndexStart ); if( nNextColon != std::u16string_view::npos ) nIndexEnd = nNextColon; return rString.substr(nIndexStart,nIndexEnd-nIndexStart); } sal_Int32 lcl_StringToIndex( std::u16string_view rIndexString ) { sal_Int32 nRet = -1; if( !rIndexString.empty() ) { nRet = o3tl::toInt32(rIndexString); if( nRet < -1 ) nRet = -1; } return nRet; } void lcl_parseCooSysIndices( sal_Int32& rnDiagram, sal_Int32& rnCooSys, std::u16string_view rString ) { rnDiagram = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u"D=" ) ); rnCooSys = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u"CS=" ) ); } void lcl_parseAxisIndices( sal_Int32& rnDimensionIndex, sal_Int32& rnAxisIndex, std::u16string_view rString ) { std::u16string_view aAxisIndexString = lcl_getIndexStringAfterString( rString, u":Axis=" ); sal_Int32 nCharacterIndex=0; rnDimensionIndex = lcl_StringToIndex( o3tl::getToken(aAxisIndexString, 0, ',', nCharacterIndex ) ); rnAxisIndex = lcl_StringToIndex( o3tl::getToken(aAxisIndexString, 0, ',', nCharacterIndex ) ); } void lcl_parseGridIndices( sal_Int32& rnSubGridIndex, std::u16string_view rString ) { rnSubGridIndex = -1; rnSubGridIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u":SubGrid=" ) ); } void lcl_parseSeriesIndices( sal_Int32& rnChartTypeIndex, sal_Int32& rnSeriesIndex, sal_Int32& rnPointIndex, std::u16string_view rString ) { rnChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u"CT=" ) ); rnSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u"Series=" ) ); rnPointIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, u"Point=" ) ); } void lcl_getDiagramAndCooSys( std::u16string_view rObjectCID , const rtl::Reference<::chart::ChartModel>& xChartModel , rtl::Reference< Diagram >& xDiagram , rtl::Reference< BaseCoordinateSystem >& xCooSys ) { sal_Int32 nDiagramIndex = -1; sal_Int32 nCooSysIndex = -1; lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rObjectCID ); xDiagram = ChartModelHelper::findDiagram( xChartModel );//todo use nDiagramIndex when more than one diagram is possible in future if( !xDiagram.is() ) return; if( nCooSysIndex > -1 ) { const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysList( xDiagram->getBaseCoordinateSystems() ); if( o3tl::make_unsigned(nCooSysIndex) < aCooSysList.size() ) xCooSys = aCooSysList[nCooSysIndex]; } } } //anonymous namespace ObjectIdentifier::ObjectIdentifier() { } ObjectIdentifier::ObjectIdentifier( OUString aObjectCID ) :m_aObjectCID(std::move( aObjectCID )) { } ObjectIdentifier::ObjectIdentifier( const Reference< drawing::XShape >& rxShape ) : m_xAdditionalShape( rxShape ) { } ObjectIdentifier::ObjectIdentifier( const Any& rAny ) { const uno::Type& rType = rAny.getValueType(); if ( rType == cppu::UnoType::get() ) { rAny >>= m_aObjectCID; } else if ( rType == cppu::UnoType< drawing::XShape >::get() ) { rAny >>= m_xAdditionalShape; } } bool ObjectIdentifier::operator==( const ObjectIdentifier& rOID ) const { return areIdenticalObjects( m_aObjectCID, rOID.m_aObjectCID ) && ( m_xAdditionalShape == rOID.m_xAdditionalShape ); } bool ObjectIdentifier::operator!=( const ObjectIdentifier& rOID ) const { return !operator==( rOID ); } bool ObjectIdentifier::operator<( const ObjectIdentifier& rOID ) const { bool bReturn = false; if ( !(m_aObjectCID.isEmpty() || rOID.m_aObjectCID.isEmpty()) ) { bReturn = ( m_aObjectCID.compareTo( rOID.m_aObjectCID ) < 0 ); } else if ( !m_aObjectCID.isEmpty() ) { bReturn = true; } else if ( !rOID.m_aObjectCID.isEmpty() ) { bReturn = false; } else if ( m_xAdditionalShape.is() && rOID.m_xAdditionalShape.is() ) { bReturn = ( m_xAdditionalShape < rOID.m_xAdditionalShape ); } return bReturn; } OUString ObjectIdentifier::createClassifiedIdentifierForObject( const Reference< uno::XInterface >& xObject , const rtl::Reference<::chart::ChartModel>& xChartModel ) { OUString aRet; enum ObjectType eObjectType = OBJECTTYPE_UNKNOWN; const std::u16string_view aObjectID; OUString aParentParticle; const std::u16string_view aDragMethodServiceName; const std::u16string_view aDragParameterString; try { //title Reference< XTitle > xTitle( xObject, uno::UNO_QUERY ); if( xTitle.is() ) { TitleHelper::eTitleType aTitleType; if( TitleHelper::getTitleType( aTitleType, xTitle, xChartModel ) ) { eObjectType = OBJECTTYPE_TITLE; aParentParticle = lcl_getTitleParentParticle( aTitleType ); aRet = ObjectIdentifier::createClassifiedIdentifierWithParent( eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString ); } return aRet; } uno::Reference xDataTable(xObject, uno::UNO_QUERY); if (xDataTable.is()) { return createClassifiedIdentifierForParticle(createParticleForDataTable(xChartModel)); } //axis Reference< XAxis > xAxis( xObject, uno::UNO_QUERY ); if( xAxis.is() ) { rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) ) ); OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, xChartModel ) ); sal_Int32 nDimensionIndex=-1; sal_Int32 nAxisIndex=-1; AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) ); return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle ); } //legend Reference< XLegend > xLegend( xObject, uno::UNO_QUERY ); if( xLegend.is() ) { return createClassifiedIdentifierForParticle( createParticleForLegend( xChartModel ) ); } //diagram Reference< XDiagram > xDiagram( xObject, uno::UNO_QUERY ); if( xDiagram.is() ) { return createClassifiedIdentifierForParticle( createParticleForDiagram() ); } //todo //XDataSeries //CooSys //charttype //datapoint? //Gridproperties } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("chart2"); } if( eObjectType != OBJECTTYPE_UNKNOWN ) { aRet = ObjectIdentifier::createClassifiedIdentifierWithParent( eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString ); } else { OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); } return aRet; } OUString ObjectIdentifier::createClassifiedIdentifierForObject( const rtl::Reference< Legend >& xLegend , const rtl::Reference<::chart::ChartModel>& xChartModel ) { try { if( xLegend.is() ) { return createClassifiedIdentifierForParticle( createParticleForLegend( xChartModel ) ); } } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("chart2"); } OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); return OUString(); } OUString ObjectIdentifier::createClassifiedIdentifierForObject( const rtl::Reference<::chart::Axis>& xAxis , const rtl::Reference<::chart::ChartModel>& xChartModel ) { try { //axis if( xAxis.is() ) { rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) ) ); OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, xChartModel ) ); sal_Int32 nDimensionIndex=-1; sal_Int32 nAxisIndex=-1; AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) ); return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle ); } } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("chart2"); } OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); return OUString(); } OUString ObjectIdentifier::createClassifiedIdentifierForParticle( std::u16string_view rParticle ) { return ObjectIdentifier::createClassifiedIdentifierForParticles( rParticle, u"" ); } OUString ObjectIdentifier::createClassifiedIdentifierForParticles( std::u16string_view rParentParticle , std::u16string_view rChildParticle , std::u16string_view rDragMethodServiceName , std::u16string_view rDragParameterString ) { ObjectType eObjectType( ObjectIdentifier::getObjectType( rChildParticle ) ); if( eObjectType == OBJECTTYPE_UNKNOWN ) eObjectType = ObjectIdentifier::getObjectType( rParentParticle ); OUStringBuffer aRet( m_aProtocol ); aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString )); if(o3tl::make_unsigned(aRet.getLength()) >= std::size(m_aProtocol)) aRet.append("/"); if(!rParentParticle.empty()) { aRet.append(rParentParticle); if( !rChildParticle.empty() ) aRet.append(":"); } aRet.append(rChildParticle); return aRet.makeStringAndClear(); } OUString ObjectIdentifier::createParticleForDiagram() { //TODO: if more than one diagram is implemented, add the correct diagram index here return "D=0"; } OUString ObjectIdentifier::createParticleForCoordinateSystem( const rtl::Reference< BaseCoordinateSystem >& xCooSys , const rtl::Reference<::chart::ChartModel>& xChartModel ) { OUString aRet; rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); if( xDiagram.is() ) { std::size_t nCooSysIndex = 0; const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); for( ; nCooSysIndex < aCooSysList.size(); ++nCooSysIndex ) { if( xCooSys == aCooSysList[nCooSysIndex] ) { aRet = ObjectIdentifier::createParticleForDiagram() + ":CS=" + OUString::number( nCooSysIndex ); break; } } } return aRet; } OUString ObjectIdentifier::createParticleForAxis( sal_Int32 nDimensionIndex , sal_Int32 nAxisIndex ) { return "Axis=" + OUString::number( nDimensionIndex ) + "," + OUString::number( nAxisIndex ); } OUString ObjectIdentifier::createParticleForGrid( sal_Int32 nDimensionIndex , sal_Int32 nAxisIndex ) { OUString aRet = "Axis=" + OUString::number( nDimensionIndex ) + "," + OUString::number( nAxisIndex ) + ":Grid=0"; return aRet; } OUString ObjectIdentifier::createClassifiedIdentifierForGrid( const Reference< XAxis >& xAxis , const rtl::Reference<::chart::ChartModel>& xChartModel , sal_Int32 nSubGridIndex ) { //-1: main grid, 0: first subgrid etc OUString aAxisCID( createClassifiedIdentifierForObject( xAxis, xChartModel ) ); OUString aGridCID( addChildParticle( aAxisCID , createChildParticleWithIndex( OBJECTTYPE_GRID, 0 ) ) ); if( nSubGridIndex >= 0 ) { aGridCID = addChildParticle( aGridCID , createChildParticleWithIndex( OBJECTTYPE_SUBGRID, 0 ) ); } return aGridCID; } OUString ObjectIdentifier::createParticleForSeries( sal_Int32 nDiagramIndex, sal_Int32 nCooSysIndex , sal_Int32 nChartTypeIndex, sal_Int32 nSeriesIndex ) { return "D=" + OUString::number( nDiagramIndex ) + ":CS=" + OUString::number( nCooSysIndex ) + ":CT=" + OUString::number( nChartTypeIndex ) + ":" + getStringForType( OBJECTTYPE_DATA_SERIES ) + "=" + OUString::number( nSeriesIndex ); } OUString ObjectIdentifier::createParticleForLegend( const rtl::Reference<::chart::ChartModel>& ) { //todo: if more than one diagram is implemented, find the correct diagram which is owner of the given legend return ObjectIdentifier::createParticleForDiagram() + ":" + getStringForType( OBJECTTYPE_LEGEND ) + "="; } OUString ObjectIdentifier::createParticleForDataTable(const rtl::Reference<::chart::ChartModel>& /* xChartModel */) { return ObjectIdentifier::createParticleForDiagram() + ":" + getStringForType(OBJECTTYPE_DATA_TABLE) + "="; } OUString ObjectIdentifier::createClassifiedIdentifier( enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_SERIES , std::u16string_view rParticleID )//e.g. SeriesID { return createClassifiedIdentifierWithParent( eObjectType, rParticleID, u"" ); } OUString ObjectIdentifier::createClassifiedIdentifierWithParent( enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_POINT or OBJECTTYPE_GRID , std::u16string_view rParticleID //e.g. Point Index or SubGrid Index , std::u16string_view rParentPartical //e.g. "Series=SeriesID" or "Grid=GridId" , std::u16string_view rDragMethodServiceName , std::u16string_view rDragParameterString ) //, bool bIsMultiClickObject ) //e.g. true { //e.g. "MultiClick/Series=2:Point=34" OUStringBuffer aRet( m_aProtocol ); aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString )); if(o3tl::make_unsigned(aRet.getLength()) >= std::size(m_aProtocol)) aRet.append("/"); aRet.append(rParentPartical); if(!rParentPartical.empty()) aRet.append(":"); aRet.append(getStringForType( eObjectType )); aRet.append("="); aRet.append(rParticleID); return aRet.makeStringAndClear(); } const OUString& ObjectIdentifier::getPieSegmentDragMethodServiceName() { return m_aPieSegmentDragMethodServiceName; } OUString ObjectIdentifier::createPieSegmentDragParameterString( sal_Int32 nOffsetPercent , const awt::Point& rMinimumPosition , const awt::Point& rMaximumPosition ) { OUString aRet = OUString::number( nOffsetPercent ) + "," + OUString::number( rMinimumPosition.X ) + "," + OUString::number( rMinimumPosition.Y ) + "," + OUString::number( rMaximumPosition.X ) + "," + OUString::number( rMaximumPosition.Y ); return aRet; } bool ObjectIdentifier::parsePieSegmentDragParameterString( std::u16string_view rDragParameterString , sal_Int32& rOffsetPercent , awt::Point& rMinimumPosition , awt::Point& rMaximumPosition ) { sal_Int32 nCharacterIndex = 0; std::u16string_view aValueString( o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ) ); rOffsetPercent = o3tl::toInt32(aValueString); if( nCharacterIndex < 0 ) return false; aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); rMinimumPosition.X = o3tl::toInt32(aValueString); if( nCharacterIndex < 0 ) return false; aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); rMinimumPosition.Y = o3tl::toInt32(aValueString); if( nCharacterIndex < 0 ) return false; aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); rMaximumPosition.X = o3tl::toInt32(aValueString); if( nCharacterIndex < 0 ) return false; aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); rMaximumPosition.Y = o3tl::toInt32(aValueString); return nCharacterIndex >= 0; } std::u16string_view ObjectIdentifier::getDragMethodServiceName( std::u16string_view rCID ) { std::u16string_view aRet; size_t nIndexStart = rCID.find( m_aDragMethodEquals ); if( nIndexStart != std::u16string_view::npos ) { nIndexStart = rCID.find( '=', nIndexStart ); if( nIndexStart != std::u16string_view::npos ) { nIndexStart++; size_t nNextSlash = rCID.find( '/', nIndexStart ); if( nNextSlash != std::u16string_view::npos ) { sal_Int32 nIndexEnd = nNextSlash; size_t nNextColon = rCID.find( ':', nIndexStart ); if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash ) nIndexEnd = nNextColon; aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart); } } } return aRet; } std::u16string_view ObjectIdentifier::getDragParameterString( std::u16string_view rCID ) { std::u16string_view aRet; size_t nIndexStart = rCID.find( m_aDragParameterEquals ); if( nIndexStart != std::u16string_view::npos ) { nIndexStart = rCID.find( '=', nIndexStart ); if( nIndexStart != std::u16string_view::npos ) { nIndexStart++; size_t nNextSlash = rCID.find( '/', nIndexStart ); if( nNextSlash != std::u16string_view::npos ) { sal_Int32 nIndexEnd = nNextSlash; size_t nNextColon = rCID.find( ':', nIndexStart ); if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash ) nIndexEnd = nNextColon; aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart); } } } return aRet; } bool ObjectIdentifier::isDragableObject( std::u16string_view rClassifiedIdentifier ) { bool bReturn = false; ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier ); switch( eObjectType ) { case OBJECTTYPE_TITLE: case OBJECTTYPE_LEGEND: case OBJECTTYPE_DIAGRAM: case OBJECTTYPE_DATA_LABEL: case OBJECTTYPE_DATA_CURVE_EQUATION: //case OBJECTTYPE_DIAGRAM_WALL: bReturn = true; break; default: std::u16string_view aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( rClassifiedIdentifier ) ); bReturn = !aDragMethodServiceName.empty(); break; } return bReturn; } bool ObjectIdentifier::isDragableObject() const { bool bReturn = false; if ( isAutoGeneratedObject() ) { bReturn = isDragableObject( m_aObjectCID ); } else if ( isAdditionalShape() ) { bReturn = true; } return bReturn; } bool ObjectIdentifier::isRotateableObject( std::u16string_view rClassifiedIdentifier ) { bool bReturn = false; ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier ); switch( eObjectType ) { case OBJECTTYPE_DIAGRAM: //case OBJECTTYPE_DIAGRAM_WALL: bReturn = true; break; default: bReturn = false; break; } return bReturn; } bool ObjectIdentifier::isMultiClickObject( std::u16string_view rClassifiedIdentifier ) { //the name of a shape is it's ClassifiedIdentifier //a MultiClickObject is an object that is selectable by more than one click only ; //before a MultiClickObject can be selected it is necessary that a named parent group object //was selected before; //!!!!! by definition the name of a MultiClickObject starts with "CID/MultiClick:" bool bRet = o3tl::starts_with(rClassifiedIdentifier.substr( std::size(m_aProtocol)-1 ), m_aMultiClick); return bRet; } bool ObjectIdentifier::areSiblings( std::u16string_view rCID1, std::u16string_view rCID2 ) { bool bRet=false; size_t nLastSign1 = rCID1.rfind( '=' ); size_t nLastSign2 = rCID2.rfind( '=' ); if( nLastSign1 == rCID1.find( '=' ) )//CID cannot be sibling if only one "=" occurs bRet=false; else if( nLastSign2 == rCID2.find( '=' ) )//CID cannot be sibling if only one "=" occurs bRet=false; else if( ObjectIdentifier::areIdenticalObjects( rCID1, rCID2 ) ) bRet=false; else { std::u16string_view aParent1( ObjectIdentifier::getFullParentParticle( rCID1 ) ); if( !aParent1.empty() ) { std::u16string_view aParent2( ObjectIdentifier::getFullParentParticle( rCID2 ) ); bRet=aParent1 == aParent2; } //legend entries are special: if(!bRet) { if( getObjectType(rCID1) == OBJECTTYPE_LEGEND_ENTRY && getObjectType(rCID2) == OBJECTTYPE_LEGEND_ENTRY ) bRet = true; } } return bRet; } bool ObjectIdentifier::areIdenticalObjects( std::u16string_view rCID1, std::u16string_view rCID2 ) { if( rCID1 == rCID2 ) return true; //draggable pie or donut segments need special treatment, as their CIDs do change with offset { if( rCID1.find( m_aPieSegmentDragMethodServiceName ) == std::u16string_view::npos || rCID2.find( m_aPieSegmentDragMethodServiceName ) == std::u16string_view::npos ) return false; OUString aID1( ObjectIdentifier::getObjectID( rCID1 ) ); OUString aID2( ObjectIdentifier::getObjectID( rCID2 ) ); if( !aID1.isEmpty() && aID1 == aID2 ) return true; } return false; } OUString ObjectIdentifier::getStringForType( ObjectType eObjectType ) { OUString aRet; switch( eObjectType ) { case OBJECTTYPE_PAGE: aRet="Page"; break; case OBJECTTYPE_TITLE: aRet="Title"; break; case OBJECTTYPE_LEGEND: aRet="Legend"; break; case OBJECTTYPE_LEGEND_ENTRY: aRet="LegendEntry"; break; case OBJECTTYPE_DIAGRAM: aRet="D"; break; case OBJECTTYPE_DIAGRAM_WALL: aRet="DiagramWall"; break; case OBJECTTYPE_DIAGRAM_FLOOR: aRet="DiagramFloor"; break; case OBJECTTYPE_AXIS: aRet="Axis"; break; case OBJECTTYPE_AXIS_UNITLABEL: aRet="AxisUnitLabel"; break; case OBJECTTYPE_GRID: aRet="Grid"; break; case OBJECTTYPE_SUBGRID: aRet="SubGrid"; break; case OBJECTTYPE_DATA_SERIES: aRet="Series"; break; case OBJECTTYPE_DATA_POINT: aRet="Point"; break; case OBJECTTYPE_DATA_LABELS: aRet="DataLabels"; break; case OBJECTTYPE_DATA_LABEL: aRet="DataLabel"; break; case OBJECTTYPE_DATA_ERRORS_X: aRet="ErrorsX"; break; case OBJECTTYPE_DATA_ERRORS_Y: aRet="ErrorsY"; break; case OBJECTTYPE_DATA_ERRORS_Z: aRet="ErrorsZ"; break; case OBJECTTYPE_DATA_CURVE: aRet="Curve"; break; case OBJECTTYPE_DATA_CURVE_EQUATION: aRet="Equation"; break; case OBJECTTYPE_DATA_AVERAGE_LINE: aRet="Average"; break; case OBJECTTYPE_DATA_STOCK_RANGE: aRet="StockRange"; break; case OBJECTTYPE_DATA_STOCK_LOSS: aRet="StockLoss"; break; case OBJECTTYPE_DATA_STOCK_GAIN: aRet="StockGain"; break; case OBJECTTYPE_DATA_TABLE: aRet="DataTable"; break; default: //OBJECTTYPE_UNKNOWN ; } return aRet; } ObjectType ObjectIdentifier::getObjectType( std::u16string_view aCID ) { ObjectType eRet; size_t nLastSign = aCID.rfind( ':' );//last sign before the type string if(nLastSign == std::u16string_view::npos) nLastSign = aCID.rfind( '/' ); if(nLastSign == std::u16string_view::npos) { size_t nEndIndex = aCID.rfind( '=' ); if(nEndIndex == std::u16string_view::npos) return OBJECTTYPE_UNKNOWN; nLastSign = 0; } if( nLastSign>0 ) nLastSign++; aCID = aCID.substr(nLastSign); if( o3tl::starts_with(aCID, u"Page") ) eRet = OBJECTTYPE_PAGE; else if( o3tl::starts_with(aCID, u"Title") ) eRet = OBJECTTYPE_TITLE; else if( o3tl::starts_with(aCID, u"LegendEntry") ) eRet = OBJECTTYPE_LEGEND_ENTRY; else if( o3tl::starts_with(aCID, u"Legend") ) eRet = OBJECTTYPE_LEGEND; else if( o3tl::starts_with(aCID, u"DiagramWall") ) eRet = OBJECTTYPE_DIAGRAM_WALL; else if( o3tl::starts_with(aCID, u"DiagramFloor") ) eRet = OBJECTTYPE_DIAGRAM_FLOOR; else if( o3tl::starts_with(aCID, u"D=") ) eRet = OBJECTTYPE_DIAGRAM; else if( o3tl::starts_with(aCID, u"AxisUnitLabel") ) eRet = OBJECTTYPE_AXIS_UNITLABEL; else if( o3tl::starts_with(aCID, u"Axis") ) eRet = OBJECTTYPE_AXIS; else if( o3tl::starts_with(aCID, u"Grid") ) eRet = OBJECTTYPE_GRID; else if( o3tl::starts_with(aCID, u"SubGrid") ) eRet = OBJECTTYPE_SUBGRID; else if( o3tl::starts_with(aCID, u"Series") ) eRet = OBJECTTYPE_DATA_SERIES; else if( o3tl::starts_with(aCID, u"Point") ) eRet = OBJECTTYPE_DATA_POINT; else if( o3tl::starts_with(aCID, u"DataLabels") ) eRet = OBJECTTYPE_DATA_LABELS; else if( o3tl::starts_with(aCID, u"DataLabel") ) eRet = OBJECTTYPE_DATA_LABEL; else if( o3tl::starts_with(aCID, u"ErrorsX") ) eRet = OBJECTTYPE_DATA_ERRORS_X; else if( o3tl::starts_with(aCID, u"ErrorsY") ) eRet = OBJECTTYPE_DATA_ERRORS_Y; else if( o3tl::starts_with(aCID, u"ErrorsZ") ) eRet = OBJECTTYPE_DATA_ERRORS_Z; else if( o3tl::starts_with(aCID, u"Curve") ) eRet = OBJECTTYPE_DATA_CURVE; else if( o3tl::starts_with(aCID, u"Equation") ) eRet = OBJECTTYPE_DATA_CURVE_EQUATION; else if( o3tl::starts_with(aCID, u"Average") ) eRet = OBJECTTYPE_DATA_AVERAGE_LINE; else if( o3tl::starts_with(aCID, u"StockRange") ) eRet = OBJECTTYPE_DATA_STOCK_RANGE; else if( o3tl::starts_with(aCID, u"StockLoss") ) eRet = OBJECTTYPE_DATA_STOCK_LOSS; else if( o3tl::starts_with(aCID, u"StockGain") ) eRet = OBJECTTYPE_DATA_STOCK_GAIN; else if( o3tl::starts_with(aCID, u"DataTable") ) eRet = OBJECTTYPE_DATA_TABLE; else eRet = OBJECTTYPE_UNKNOWN; return eRet; } ObjectType ObjectIdentifier::getObjectType() const { ObjectType eObjectType( OBJECTTYPE_UNKNOWN ); if ( isAutoGeneratedObject() ) { eObjectType = getObjectType( m_aObjectCID ); } else if ( isAdditionalShape() ) { eObjectType = OBJECTTYPE_SHAPE; } return eObjectType; } OUString ObjectIdentifier::createDataCurveCID( std::u16string_view rSeriesParticle , sal_Int32 nCurveIndex , bool bAverageLine ) { OUString aParticleID( OUString::number( nCurveIndex ) ); ObjectType eType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE; return createClassifiedIdentifierWithParent( eType, aParticleID, rSeriesParticle ); } OUString ObjectIdentifier::createDataCurveEquationCID( std::u16string_view rSeriesParticle , sal_Int32 nCurveIndex ) { OUString aParticleID( OUString::number( nCurveIndex ) ); return createClassifiedIdentifierWithParent( OBJECTTYPE_DATA_CURVE_EQUATION, aParticleID, rSeriesParticle ); } OUString ObjectIdentifier::addChildParticle( std::u16string_view rParticle, std::u16string_view rChildParticle ) { OUStringBuffer aRet(rParticle); if( !aRet.isEmpty() && !rChildParticle.empty() ) aRet.append(":"); if( !rChildParticle.empty() ) aRet.append(rChildParticle); return aRet.makeStringAndClear(); } OUString ObjectIdentifier::createChildParticleWithIndex( ObjectType eObjectType, sal_Int32 nIndex ) { OUStringBuffer aRet( getStringForType( eObjectType ) ); if( !aRet.isEmpty() ) { aRet.append("="); aRet.append(nIndex); } return aRet.makeStringAndClear(); } sal_Int32 ObjectIdentifier::getIndexFromParticleOrCID( std::u16string_view rParticleOrCID ) { const std::u16string_view aIndexString = lcl_getIndexStringAfterString( rParticleOrCID, u"=" ); return lcl_StringToIndex( o3tl::getToken(aIndexString, 0, ',' ) ); } OUString ObjectIdentifier::createSeriesSubObjectStub( ObjectType eSubObjectType , std::u16string_view rSeriesParticle , std::u16string_view rDragMethodServiceName , std::u16string_view rDragParameterString ) { OUString aChildParticle = getStringForType( eSubObjectType ) + "="; return createClassifiedIdentifierForParticles( rSeriesParticle, aChildParticle , rDragMethodServiceName, rDragParameterString ); } OUString ObjectIdentifier::createPointCID( std::u16string_view rPointCID_Stub, sal_Int32 nIndex ) { return rPointCID_Stub + OUString::number( nIndex ); } std::u16string_view ObjectIdentifier::getParticleID( std::u16string_view rCID ) { std::u16string_view aRet; size_t nLast = rCID.rfind('='); if(nLast != std::u16string_view::npos) aRet = rCID.substr(++nLast); return aRet; } std::u16string_view ObjectIdentifier::getFullParentParticle( std::u16string_view rCID ) { std::u16string_view aRet; size_t nStartPos = rCID.rfind('/'); if( nStartPos != std::u16string_view::npos ) { nStartPos++; size_t nEndPos = rCID.rfind(':'); if( nEndPos != std::u16string_view::npos && nStartPos < nEndPos ) { aRet = rCID.substr(nStartPos,nEndPos-nStartPos); } } return aRet; } OUString ObjectIdentifier::getObjectID( std::u16string_view rCID ) { OUString aRet; size_t nStartPos = rCID.rfind('/'); if( nStartPos != std::u16string_view::npos ) { nStartPos++; size_t nEndPos = rCID.size(); aRet = rCID.substr(nStartPos,nEndPos-nStartPos); } return aRet; } bool ObjectIdentifier::isCID( std::u16string_view rName ) { return !rName.empty() && o3tl::starts_with( rName, m_aProtocol ); } Reference< beans::XPropertySet > ObjectIdentifier::getObjectPropertySet( std::u16string_view rObjectCID , const rtl::Reference<::chart::ChartModel>& xChartModel ) { //return the model object that is indicated by rObjectCID if(rObjectCID.empty()) return nullptr; if(!xChartModel.is()) return nullptr; Reference< beans::XPropertySet > xObjectProperties; try { ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID ); std::u16string_view aParticleID = ObjectIdentifier::getParticleID( rObjectCID ); rtl::Reference< Diagram > xDiagram; rtl::Reference< BaseCoordinateSystem > xCooSys; lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); switch(eObjectType) { case OBJECTTYPE_PAGE: { xObjectProperties.set( xChartModel->getPageBackground() ); } break; case OBJECTTYPE_TITLE: { TitleHelper::eTitleType aTitleType = getTitleTypeForCID( rObjectCID ); Reference< XTitle > xTitle( TitleHelper::getTitle( aTitleType, xChartModel ) ); xObjectProperties.set( xTitle, uno::UNO_QUERY ); } break; case OBJECTTYPE_LEGEND: { if( xDiagram.is() ) xObjectProperties.set( xDiagram->getLegend(), uno::UNO_QUERY ); } break; case OBJECTTYPE_LEGEND_ENTRY: break; case OBJECTTYPE_DIAGRAM: { xObjectProperties = xDiagram; } break; case OBJECTTYPE_DIAGRAM_WALL: { if( xDiagram.is() ) xObjectProperties.set( xDiagram->getWall() ); } break; case OBJECTTYPE_DIAGRAM_FLOOR: { if( xDiagram.is() ) xObjectProperties.set( xDiagram->getFloor() ); } break; case OBJECTTYPE_AXIS: { sal_Int32 nDimensionIndex = -1; sal_Int32 nAxisIndex = -1; lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ); if( xAxis.is() ) xObjectProperties = xAxis; } break; case OBJECTTYPE_AXIS_UNITLABEL: break; case OBJECTTYPE_GRID: case OBJECTTYPE_SUBGRID: { sal_Int32 nDimensionIndex = -1; sal_Int32 nAxisIndex = -1; lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); sal_Int32 nSubGridIndex = -1; lcl_parseGridIndices( nSubGridIndex, rObjectCID ); xObjectProperties.set( AxisHelper::getGridProperties( xCooSys , nDimensionIndex, nAxisIndex, nSubGridIndex ) ); } break; case OBJECTTYPE_DATA_LABELS: case OBJECTTYPE_DATA_SERIES: { rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID, xChartModel ) ); if( xSeries.is() ) xObjectProperties = xSeries; break; } case OBJECTTYPE_DATA_LABEL: case OBJECTTYPE_DATA_POINT: { rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID, xChartModel ); if(xSeries.is()) { sal_Int32 nIndex = o3tl::toInt32(aParticleID); xObjectProperties = xSeries->getDataPointByIndex( nIndex ); } break; } case OBJECTTYPE_DATA_ERRORS_X: case OBJECTTYPE_DATA_ERRORS_Y: case OBJECTTYPE_DATA_ERRORS_Z: { rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID, xChartModel ); if(xSeries.is()) { Reference< beans::XPropertySet > xErrorBarProp; OUString errorBar; if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X) errorBar = CHART_UNONAME_ERRORBAR_X; else if (eObjectType == OBJECTTYPE_DATA_ERRORS_Y) errorBar = CHART_UNONAME_ERRORBAR_Y; else errorBar = "ErrorBarZ"; xSeries->getPropertyValue( errorBar ) >>= xErrorBarProp; xObjectProperties = xErrorBarProp; } break; } case OBJECTTYPE_DATA_AVERAGE_LINE: case OBJECTTYPE_DATA_CURVE: case OBJECTTYPE_DATA_CURVE_EQUATION: { rtl::Reference< DataSeries > xRegressionContainer = ObjectIdentifier::getDataSeriesForCID( rObjectCID, xChartModel ); if(xRegressionContainer.is()) { sal_Int32 nIndex = o3tl::toInt32(aParticleID); const std::vector< rtl::Reference< RegressionCurveModel > > & aCurveList = xRegressionContainer->getRegressionCurves2(); if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aCurveList.size() ) { if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) xObjectProperties = aCurveList[nIndex]->getEquationProperties(); else xObjectProperties = aCurveList[nIndex]; } } break; } case OBJECTTYPE_DATA_STOCK_RANGE: break; case OBJECTTYPE_DATA_STOCK_LOSS: { rtl::Reference xChartType( lcl_getFirstStockChartType( xChartModel ) ); if(xChartType.is()) xChartType->getPropertyValue( "BlackDay" ) >>= xObjectProperties; } break; case OBJECTTYPE_DATA_STOCK_GAIN: { rtl::Reference xChartType( lcl_getFirstStockChartType( xChartModel ) ); if(xChartType.is()) xChartType->getPropertyValue( "WhiteDay" ) >>= xObjectProperties; } break; case OBJECTTYPE_DATA_TABLE: { if (xDiagram.is()) xObjectProperties.set(xDiagram->getDataTable(), uno::UNO_QUERY); } break; break; default: //OBJECTTYPE_UNKNOWN break; } } catch(const uno::Exception&) { DBG_UNHANDLED_EXCEPTION("chart2"); } return xObjectProperties; } rtl::Reference< Axis > ObjectIdentifier::getAxisForCID( std::u16string_view rObjectCID , const rtl::Reference<::chart::ChartModel>& xChartModel ) { rtl::Reference< Diagram > xDiagram; rtl::Reference< BaseCoordinateSystem > xCooSys; lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); sal_Int32 nDimensionIndex = -1; sal_Int32 nAxisIndex = -1; lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); return AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ); } rtl::Reference< DataSeries > ObjectIdentifier::getDataSeriesForCID( std::u16string_view rObjectCID , const rtl::Reference<::chart::ChartModel>& xChartModel ) { rtl::Reference< Diagram > xDiagram; rtl::Reference< BaseCoordinateSystem > xCooSys; lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); sal_Int32 nChartTypeIndex = -1; sal_Int32 nSeriesIndex = -1; sal_Int32 nPointIndex = -1; lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rObjectCID ); rtl::Reference< DataSeries > xSeries; rtl::Reference< ChartType > xDataSeriesContainer( DiagramHelper::getChartTypeByIndex( xDiagram, nChartTypeIndex ) ); if( xDataSeriesContainer.is() ) { const std::vector< rtl::Reference< DataSeries > > & aDataSeriesSeq( xDataSeriesContainer->getDataSeries2() ); if( nSeriesIndex >= 0 && o3tl::make_unsigned(nSeriesIndex) < aDataSeriesSeq.size() ) xSeries = aDataSeriesSeq[nSeriesIndex]; } return xSeries; } rtl::Reference< Diagram > ObjectIdentifier::getDiagramForCID( std::u16string_view rObjectCID , const rtl::Reference<::chart::ChartModel>& xChartModel ) { rtl::Reference< Diagram > xDiagram; rtl::Reference< BaseCoordinateSystem > xCooSys; lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); return xDiagram; } TitleHelper::eTitleType ObjectIdentifier::getTitleTypeForCID( std::u16string_view rCID ) { TitleHelper::eTitleType eRet( TitleHelper::MAIN_TITLE ); std::u16string_view aParentParticle = ObjectIdentifier::getFullParentParticle( rCID ); const tTitleMap& rMap = lcl_getTitleMap(); tTitleMap::const_iterator aIt = std::find_if(rMap.begin(), rMap.end(), [&aParentParticle](tTitleMap::const_reference rEntry) { return aParentParticle == rEntry.second; }); if (aIt != rMap.end()) eRet = (*aIt).first; return eRet; } OUString ObjectIdentifier::getSeriesParticleFromCID( std::u16string_view rCID ) { sal_Int32 nDiagramIndex = -1; sal_Int32 nCooSysIndex = -1; lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rCID ); sal_Int32 nChartTypeIndex = -1; sal_Int32 nSeriesIndex = -1; sal_Int32 nPointIndex = -1; lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rCID ); return ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex ); } OUString ObjectIdentifier::getMovedSeriesCID( std::u16string_view rObjectCID, bool bForward ) { sal_Int32 nDiagramIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, u"CID/D=" ) ); sal_Int32 nCooSysIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, u"CS=" ) ); sal_Int32 nChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, u"CT=" ) ); sal_Int32 nSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, u"Series=" ) ); if( bForward ) nSeriesIndex--; else nSeriesIndex++; OUString aRet = ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex ); return ObjectIdentifier::createClassifiedIdentifierForParticle( aRet ); } bool ObjectIdentifier::isValid() const { return ( isAutoGeneratedObject() || isAdditionalShape() ); } bool ObjectIdentifier::isAutoGeneratedObject() const { return ( !m_aObjectCID.isEmpty() ); } bool ObjectIdentifier::isAdditionalShape() const { return m_xAdditionalShape.is(); } Any ObjectIdentifier::getAny() const { Any aAny; if ( isAutoGeneratedObject() ) { aAny <<= getObjectCID(); } else if ( isAdditionalShape() ) { aAny <<= getAdditionalShape(); } return aAny; } } //namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */