office-gobmx/chart2/source/view/main/AbstractShapeFactory.cxx
Tor Lillqvist 31c20d6b13 No chartopengl library built for iOS or Android yet
Change-Id: I28a5eac3bbb85b608d60a1404c21150dafe36a6e
2014-01-29 10:33:23 +02:00

360 lines
11 KiB
C++

/* -*- 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 <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/CircleKind.hpp>
#include <com/sun/star/drawing/DoubleSequence.hpp>
#include <com/sun/star/drawing/FlagSequence.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/NormalsKind.hpp>
#include <com/sun/star/drawing/PointSequence.hpp>
#include <com/sun/star/drawing/PolygonKind.hpp>
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
#include <com/sun/star/drawing/ProjectionMode.hpp>
#include <com/sun/star/drawing/ShadeMode.hpp>
#include <com/sun/star/drawing/TextFitToSizeType.hpp>
#include <com/sun/star/drawing/TextureProjectionMode.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <editeng/unoprnms.hxx>
#include <rtl/math.hxx>
#include <svx/svdocirc.hxx>
#include <svx/svdopath.hxx>
#include <vcl/svapp.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <osl/module.hxx>
#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<sal_Int32>(fFactor*rSourceSizeWithCorrectAspectRatio.Width);
aNewSize.Height=static_cast<sal_Int32>(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<sal_Int32>(double(rTargetAreaSize.Width-rObjectSize.Width)/2.0);
aNewPosition.Y += static_cast<sal_Int32>(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<sal_Int32>(
aSize.Width*rtl::math::sin( fAnglePi )
+ aSize.Height*rtl::math::cos( fAnglePi ));
aRet.Width = static_cast<sal_Int32>(
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: */