/* -*- 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/. */ #include "macros.hxx" #include "PropertyMapper.hxx" #include "CommonConverters.hxx" #include "AbstractShapeFactory.hxx" #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 #include "OpenglShapeFactory.hxx" #include "ShapeFactory.hxx" using namespace com::sun::star; using ::com::sun::star::uno::Reference; namespace chart { namespace { typedef opengl::OpenglShapeFactory* (*__getOpenglShapeFactory)(void); #ifndef DISABLE_DYNLOADING static void SAL_CALL thisModule() {} osl::Module* getOpenGLModule() { static osl::Module aModule; if (aModule.is()) // Already loaded. return &aModule; OUString aLibName(SVLIBRARY("chartopengl")); bool bLoaded = aModule.loadRelative(&thisModule, aLibName); if (!bLoaded) bLoaded = aModule.load(aLibName); return bLoaded ? &aModule : NULL; } #endif } #ifdef DISABLE_DYNLOADING extern "C" opengl::OpenglShapeFactory* getOpenglShapeFactory(); #endif AbstractShapeFactory* AbstractShapeFactory::getOrCreateShapeFactory(uno::Reference< lang::XMultiServiceFactory> xFactory) { static AbstractShapeFactory* pShapeFactory = NULL; if(pShapeFactory) return pShapeFactory; if(getenv("CHART_DUMMY_FACTORY") && !Application::IsHeadlessModeEnabled()) { #ifndef DISABLE_DYNLOADING osl::Module* pModule = getOpenGLModule(); if(pModule) { oslGenericFunction fn = pModule->getFunctionSymbol("getOpenglShapeFactory"); if(fn) { pShapeFactory = reinterpret_cast<__getOpenglShapeFactory>(fn)(); pShapeFactory->setShapeFactory(xFactory); } } #elif defined(IOS) || defined(ANDROID) // Library_chartopengl is not portable enough yet pShapeFactory = NULL; #else pShapeFactory = getOpenglShapeFactory(); pShapeFactory->setShapeFactory(xFactory); #endif } if(!pShapeFactory) pShapeFactory = new ShapeFactory(xFactory); return pShapeFactory; } sal_Int32 AbstractShapeFactory::getSymbolCount() { return Symbol_COUNT; } uno::Reference< drawing::XShapes > AbstractShapeFactory::getChartRootShape( const uno::Reference< drawing::XDrawPage>& xDrawPage ) { uno::Reference< drawing::XShapes > xRet; uno::Reference< drawing::XShapes > xShapes( xDrawPage, uno::UNO_QUERY ); if( xShapes.is() ) { sal_Int32 nCount = xShapes->getCount(); uno::Reference< drawing::XShape > xShape; for( sal_Int32 nN = nCount; nN--; ) { if( xShapes->getByIndex( nN ) >>= xShape ) { if( AbstractShapeFactory::getShapeName( xShape ).equals("com.sun.star.chart2.shapes") ) { xRet = uno::Reference< drawing::XShapes >( xShape, uno::UNO_QUERY ); break; } } } } return xRet; } void AbstractShapeFactory::makeShapeInvisible( const uno::Reference< drawing::XShape >& xShape ) { uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); OSL_ENSURE(xShapeProp.is(), "created shape offers no XPropertySet"); if( xShapeProp.is()) { try { xShapeProp->setPropertyValue( "LineStyle", uno::makeAny( drawing::LineStyle_NONE )); xShapeProp->setPropertyValue( "FillStyle", uno::makeAny( drawing::FillStyle_NONE )); } catch( const uno::Exception& e ) { ASSERT_EXCEPTION( e ); } } } // set a name/CID at a shape (is used for selection handling) void AbstractShapeFactory::setShapeName( const uno::Reference< drawing::XShape >& xShape , const OUString& rName ) { if(!xShape.is()) return; uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); OSL_ENSURE(xProp.is(), "shape offers no XPropertySet"); if( xProp.is()) { try { xProp->setPropertyValue( UNO_NAME_MISC_OBJ_NAME , uno::makeAny( rName ) ); } catch( const uno::Exception& e ) { ASSERT_EXCEPTION( e ); } } } OUString AbstractShapeFactory::getShapeName( const uno::Reference< drawing::XShape >& xShape ) { OUString aRet; uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); OSL_ENSURE(xProp.is(), "shape offers no XPropertySet"); if( xProp.is()) { try { xProp->getPropertyValue( UNO_NAME_MISC_OBJ_NAME ) >>= aRet; } catch( const uno::Exception& e ) { ASSERT_EXCEPTION( e ); } } return aRet; } uno::Any AbstractShapeFactory::makeTransformation( const awt::Point& rScreenPosition2D, double fRotationAnglePi ) { ::basegfx::B2DHomMatrix aM; //As autogrow is active the rectangle is automatically expanded to that side //to which the text is not adjusted. // aM.scale( 1, 1 ); Oops? A scale with this parameters is neutral, line commented out aM.rotate( fRotationAnglePi ); aM.translate( rScreenPosition2D.X, rScreenPosition2D.Y ); uno::Any aATransformation = uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ); return aATransformation; } OUString AbstractShapeFactory::getStackedString( const OUString& rString, bool bStacked ) { sal_Int32 nLen = rString.getLength(); if(!bStacked || !nLen) return rString; OUStringBuffer aStackStr; //add a newline after each letter //as we do not no letters here add a newline after each char for( sal_Int32 nPosSrc=0; nPosSrc < nLen; nPosSrc++ ) { if( nPosSrc ) aStackStr.append( '\r' ); aStackStr.append(rString[nPosSrc]); } return aStackStr.makeStringAndClear(); } bool AbstractShapeFactory::hasPolygonAnyLines( drawing::PolyPolygonShape3D& rPoly) { // #i67757# check all contained polygons, if at least one polygon contains 2 or more points, return true for( sal_Int32 nIdx = 0, nCount = rPoly.SequenceX.getLength(); nIdx < nCount; ++nIdx ) if( rPoly.SequenceX[ nIdx ].getLength() > 1 ) return true; return false; } bool AbstractShapeFactory::isPolygonEmptyOrSinglePoint( drawing::PolyPolygonShape3D& rPoly) { // true, if empty polypolygon or one polygon with one point return (rPoly.SequenceX.getLength() == 0) || ((rPoly.SequenceX.getLength() == 1) && (rPoly.SequenceX[0].getLength() <= 1)); } void AbstractShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) { OSL_ENSURE( rPoly.SequenceX.getLength() <= 1, "AbstractShapeFactory::closePolygon - single polygon expected" ); //add a last point == first point if(isPolygonEmptyOrSinglePoint(rPoly)) return; drawing::Position3D aFirst(rPoly.SequenceX[0][0],rPoly.SequenceY[0][0],rPoly.SequenceZ[0][0]); AddPointToPoly( rPoly, aFirst ); } awt::Size AbstractShapeFactory::calculateNewSizeRespectingAspectRatio( const awt::Size& rTargetSize , const awt::Size& rSourceSizeWithCorrectAspectRatio ) { awt::Size aNewSize; double fFactorWidth = double(rTargetSize.Width)/double(rSourceSizeWithCorrectAspectRatio.Width); double fFactorHeight = double(rTargetSize.Height)/double(rSourceSizeWithCorrectAspectRatio.Height); double fFactor = std::min(fFactorWidth,fFactorHeight); aNewSize.Width=static_cast(fFactor*rSourceSizeWithCorrectAspectRatio.Width); aNewSize.Height=static_cast(fFactor*rSourceSizeWithCorrectAspectRatio.Height); return aNewSize; } awt::Point AbstractShapeFactory::calculateTopLeftPositionToCenterObject( const awt::Point& rTargetAreaPosition , const awt::Size& rTargetAreaSize , const awt::Size& rObjectSize ) { awt::Point aNewPosition(rTargetAreaPosition); aNewPosition.X += static_cast(double(rTargetAreaSize.Width-rObjectSize.Width)/2.0); aNewPosition.Y += static_cast(double(rTargetAreaSize.Height-rObjectSize.Height)/2.0); return aNewPosition; } ::basegfx::B2IRectangle AbstractShapeFactory::getRectangleOfShape( const uno::Reference< drawing::XShape >& xShape ) { ::basegfx::B2IRectangle aRet; if( xShape.is() ) { awt::Point aPos = xShape->getPosition(); awt::Size aSize = xShape->getSize(); aRet = BaseGFXHelper::makeRectangle(aPos,aSize); } return aRet; } awt::Size AbstractShapeFactory::getSizeAfterRotation( const uno::Reference< drawing::XShape >& xShape, double fRotationAngleDegree ) { awt::Size aRet(0,0); if(xShape.is()) { const awt::Size aSize( xShape->getSize() ); if( ::rtl::math::approxEqual( fRotationAngleDegree, 0.0 ) ) aRet = aSize; else { while(fRotationAngleDegree>=360.0) fRotationAngleDegree-=360.0; while(fRotationAngleDegree<0.0) fRotationAngleDegree+=360.0; if(fRotationAngleDegree>270.0) fRotationAngleDegree=360.0-fRotationAngleDegree; else if(fRotationAngleDegree>180.0) fRotationAngleDegree=fRotationAngleDegree-180.0; else if(fRotationAngleDegree>90.0) fRotationAngleDegree=180.0-fRotationAngleDegree; const double fAnglePi = fRotationAngleDegree*F_PI/180.0; aRet.Height = static_cast( aSize.Width*rtl::math::sin( fAnglePi ) + aSize.Height*rtl::math::cos( fAnglePi )); aRet.Width = static_cast( aSize.Width*rtl::math::cos( fAnglePi ) + aSize.Height*rtl::math::sin( fAnglePi )); } } return aRet; } void AbstractShapeFactory::removeSubShapes( const uno::Reference< drawing::XShapes >& xShapes ) { if( xShapes.is() ) { sal_Int32 nSubCount = xShapes->getCount(); uno::Reference< drawing::XShape > xShape; for( sal_Int32 nS = nSubCount; nS--; ) { if( xShapes->getByIndex( nS ) >>= xShape ) xShapes->remove( xShape ); } } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */