diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx new file mode 100644 index 000000000000..3c964a15b1e7 --- /dev/null +++ b/chart2/source/view/charttypes/CandleStickChart.cxx @@ -0,0 +1,415 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: CandleStickChart.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: vg $ $Date: 2007-05-22 19:15:23 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "CandleStickChart.hxx" +#include "ShapeFactory.hxx" +//#include "chartview/servicenames_charttypes.hxx" +//#include "servicenames_coosystems.hxx" +#include "CommonConverters.hxx" +#include "ObjectIdentifier.hxx" +#include "LabelPositionHelper.hxx" +#include "BarPositionHelper.hxx" +#include "macros.hxx" +#include "VLegendSymbolFactory.hxx" +#include "FormattedStringHelper.hxx" +#include "DataSeriesHelper.hxx" + +#ifndef _TOOLS_DEBUG_HXX +#include +#endif +#ifndef INCLUDED_RTL_MATH_HXX +#include +#endif +#ifndef _SVX_UNOPRNMS_HXX +#include +#endif + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::rtl::math; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::rtl::OUString; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +CandleStickChart::CandleStickChart( const uno::Reference& xChartTypeModel + , sal_Int32 nDimensionCount ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount ) + , m_pMainPosHelper( new BarPositionHelper() ) +{ + PlotterBase::m_pPosHelper = m_pMainPosHelper; + VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper; +} + +CandleStickChart::~CandleStickChart() +{ + delete m_pMainPosHelper; +} + +//------------------------------------------------------------------------- +// MinimumAndMaximumSupplier +//------------------------------------------------------------------------- + +double CandleStickChart::getMinimumX() +{ + if( m_bCategoryXAxis ) + return 0.5;//first category (index 0) matches with real number 1.0 + return VSeriesPlotter::getMinimumX(); +} +double CandleStickChart::getMaximumX() +{ + if( m_bCategoryXAxis ) + { + //return category count + sal_Int32 nPointCount = getPointCount(); + return nPointCount+0.5;//first category (index 0) matches with real number 1.0 + } + return VSeriesPlotter::getMaximumX(); +} +bool CandleStickChart::isSeperateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) +{ + return false; +} + +//----------------------------------------------------------------- +//----------------------------------------------------------------- +//----------------------------------------------------------------- + +LegendSymbolStyle CandleStickChart::getLegendSymbolStyle() +{ + return chart2::LegendSymbolStyle_VERTICAL_LINE; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo +//----------------------------------------------------------------- +/* +APPHELPER_XSERVICEINFO_IMPL(CandleStickChart,CHART2_VIEW_CANDLESTICKCHART_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > CandleStickChart +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART2_VIEW_CANDLESTICKCHART_SERVICE_NAME; + return aSNS; +} +*/ +/* +//----------------------------------------------------------------- +// chart2::XPlotter +//----------------------------------------------------------------- + + ::rtl::OUString SAL_CALL CandleStickChart +::getCoordinateSystemTypeID() + throw (uno::RuntimeException) +{ + return CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME; +} +*/ + +drawing::Direction3D CandleStickChart::getPreferredDiagramAspectRatio() const +{ + return drawing::Direction3D(-1,-1,-1); +} + +void CandleStickChart::addSeries( VDataSeries* pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) +{ + //ignore y stacking for candle stick chart + VSeriesPlotter::addSeries( pSeries, 0, xSlot, ySlot ); +} + +void CandleStickChart::createShapes() +{ + if( m_aZSlots.begin() == m_aZSlots.end() ) //no series + return; + + if( m_nDimension!=2 ) + return; + + DBG_ASSERT(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"CandleStickChart is not proper initialized"); + if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //the text labels should be always on top of the other series shapes + //therefore create an own group for the texts to move them to front + //(because the text group is created after the series group the texts are displayed on top) + + uno::Reference< drawing::XShapes > xSeriesTarget( + createGroupShape( m_xLogicTarget,rtl::OUString() )); + uno::Reference< drawing::XShapes > xLossTarget( + createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_STOCK_LOSS, rtl::OUString() ))); + uno::Reference< drawing::XShapes > xGainTarget( + createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_STOCK_GAIN, rtl::OUString() ))); + uno::Reference< drawing::XShapes > xTextTarget( + m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() )); + + //--------------------------------------------- + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + bool bJapaneseStyle=true;//@todo is this the correct default? + bool bShowFirst = true;//is only important if bJapaneseStyle == false + tNameSequence aWhiteBox_Names, aBlackBox_Names; + tAnySequence aWhiteBox_Values, aBlackBox_Values; + try + { + if( m_xChartTypeModelProps.is() ) + { + m_xChartTypeModelProps->getPropertyValue( C2U( "ShowFirst" ) ) >>= bShowFirst; + + uno::Reference< beans::XPropertySet > xWhiteDayProps(0); + uno::Reference< beans::XPropertySet > xBlackDayProps(0); + m_xChartTypeModelProps->getPropertyValue( C2U( "Japanese" ) ) >>= bJapaneseStyle; + m_xChartTypeModelProps->getPropertyValue( C2U( "WhiteDay" ) ) >>= xWhiteDayProps; + m_xChartTypeModelProps->getPropertyValue( C2U( "BlackDay" ) ) >>= xBlackDayProps; + + tPropertyNameValueMap aWhiteBox_Map; + PropertyMapper::getValueMap( aWhiteBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xWhiteDayProps ); + PropertyMapper::getMultiPropertyListsFromValueMap( aWhiteBox_Names, aWhiteBox_Values, aWhiteBox_Map ); + + tPropertyNameValueMap aBlackBox_Map; + PropertyMapper::getValueMap( aBlackBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xBlackDayProps ); + PropertyMapper::getMultiPropertyListsFromValueMap( aBlackBox_Names, aBlackBox_Values, aBlackBox_Map ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + + //(@todo maybe different iteration for breaks in axis ?) + sal_Int32 nStartCategoryIndex = m_pMainPosHelper->getStartCategoryIndex(); // inclusive + sal_Int32 nEndCategoryIndex = m_pMainPosHelper->getEndCategoryIndex(); //inclusive +//============================================================================= + //iterate through all shown categories + for( sal_Int32 nIndex = nStartCategoryIndex; nIndex < nEndCategoryIndex; nIndex++ ) + { + ::std::vector< ::std::vector< VDataSeriesGroup > >::iterator aZSlotIter = m_aZSlots.begin(); + const ::std::vector< ::std::vector< VDataSeriesGroup > >::const_iterator aZSlotEnd = m_aZSlots.end(); +//============================================================================= + for( sal_Int32 nZ=0; aZSlotIter != aZSlotEnd; aZSlotIter++, nZ++ ) + { + ::std::vector< VDataSeriesGroup >::iterator aXSlotIter = aZSlotIter->begin(); + const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = aZSlotIter->end(); + + sal_Int32 nAttachedAxisIndex = 0; + BarPositionHelper* pPosHelper = m_pMainPosHelper; + if( aXSlotIter != aXSlotEnd ) + { + nAttachedAxisIndex = aXSlotIter->getAttachedAxisIndexForFirstSeries(); + //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot + pPosHelper = dynamic_cast(&( this->getPlottingPositionHelper( nAttachedAxisIndex ) ) ); + if(!pPosHelper) + pPosHelper = m_pMainPosHelper; + } + PlotterBase::m_pPosHelper = pPosHelper; + + //update/create information for current group + pPosHelper->updateSeriesCount( aZSlotIter->size() ); +//============================================================================= + //iterate through all x slots in this category + for( double fSlotX=0; aXSlotIter != aXSlotEnd; aXSlotIter++, fSlotX+=1.0 ) + { + ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector); + + ::std::vector< VDataSeries* >::const_iterator aSeriesIter = pSeriesList->begin(); + const ::std::vector< VDataSeries* >::const_iterator aSeriesEnd = pSeriesList->end(); + aSeriesIter = pSeriesList->begin(); + //============================================================================= + //iterate through all series in this x slot + for( ; aSeriesIter != aSeriesEnd; aSeriesIter++ ) + { + //collect data point information (logic coordinates, style ): + double fLogicX = pPosHelper->getSlotPos( (*aSeriesIter)->getX( nIndex ), fSlotX ); + double fY_First = (*aSeriesIter)->getY_First( nIndex ); + double fY_Last = (*aSeriesIter)->getY_Last( nIndex ); + double fY_Min = (*aSeriesIter)->getY_Min( nIndex ); + double fY_Max = (*aSeriesIter)->getY_Max( nIndex ); + + bool bBlack=false; + if(fY_Last<=fY_First) + { + std::swap(fY_First,fY_Last); + bBlack=true; + } + if(fY_Max 4) + double fHalfWidth = pPosHelper->getSlotWidth()/2.0; + drawing::Position3D aPosLeftFirst( pPosHelper->transformLogicToScene( fLogicX-fHalfWidth, fY_First ,0 ,true ) ); + drawing::Position3D aPosRightLast( pPosHelper->transformLogicToScene( fLogicX+fHalfWidth, fY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleFirst( pPosHelper->transformLogicToScene( fLogicX, fY_First ,0 ,true ) ); + drawing::Position3D aPosMiddleLast( pPosHelper->transformLogicToScene( fLogicX, fY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleMinimum( pPosHelper->transformLogicToScene( fLogicX, fY_Min ,0 ,true ) ); + drawing::Position3D aPosMiddleMaximum( pPosHelper->transformLogicToScene( fLogicX, fY_Max ,0 ,true ) ); + + uno::Reference< drawing::XShapes > xLossGainTarget( xGainTarget ); + if(bBlack) + xLossGainTarget = xLossTarget; + + uno::Reference< beans::XPropertySet > xPointProp( (*aSeriesIter)->getPropertiesOfPoint( nIndex )); + uno::Reference< drawing::XShapes > xPointGroupShape_Shapes(0); + { + rtl::OUString aPointCID = ObjectIdentifier::createPointCID( (*aSeriesIter)->getPointCID_Stub(), nIndex ); + uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes( getSeriesGroupShape(*aSeriesIter, xSeriesTarget) ); + xPointGroupShape_Shapes = createGroupShape(xSeriesGroupShape_Shapes,aPointCID); + } + + //create min-max line + if( isValidPosition(aPosMiddleMinimum) && isValidPosition(aPosMiddleMaximum) ) + { + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.drawing.PolyLineShape" ) ) ), uno::UNO_QUERY ); + xPointGroupShape_Shapes->add(xShape); + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if(xProp.is()) + { + drawing::PolyPolygonShape3D aPoly; + sal_Int32 nLineIndex =0; + AddPointToPoly( aPoly, aPosMiddleMinimum, nLineIndex); + if( fY_First>fY_Min && fY_LastsetPropertyValue( C2U( UNO_NAME_POLYPOLYGON ), uno::makeAny( PolyToPointSequence(aPoly) ) ); + } + this->setMappedProperties( xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + } + + //create first-last shape + if(bJapaneseStyle && isValidPosition(aPosLeftFirst) && isValidPosition(aPosRightLast) ) + { + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.drawing.RectangleShape" ) ) ), uno::UNO_QUERY ); + xLossGainTarget->add(xShape); + + xShape->setPosition( Position3DToAWTPoint( aPosLeftFirst ) ); + drawing::Direction3D aDiff = aPosRightLast-aPosLeftFirst; + awt::Size aAWTSize( Direction3DToAWTSize( aDiff )); + // workaround for bug in drawing: if height is 0 the box gets infinitely large + if( aAWTSize.Height == 0 ) + aAWTSize.Height = 1; + xShape->setSize( aAWTSize ); + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if(xProp.is()) + { + if(bBlack) + PropertyMapper::setMultiProperties( aBlackBox_Names, aBlackBox_Values, xProp ); + else + PropertyMapper::setMultiProperties( aWhiteBox_Names, aWhiteBox_Values, xProp ); + } + } + else + { + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.drawing.PolyLineShape" ) ) ), uno::UNO_QUERY ); + xPointGroupShape_Shapes->add(xShape); + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if(xProp.is()) + { + drawing::PolyPolygonShape3D aPoly; + + sal_Int32 nLineIndex = 0; + if( bShowFirst && isValidPosition(aPosLeftFirst) && isValidPosition(aPosMiddleFirst) ) + { + AddPointToPoly( aPoly, aPosLeftFirst, nLineIndex ); + AddPointToPoly( aPoly, aPosMiddleFirst, nLineIndex++ ); + } + if( isValidPosition(aPosMiddleLast) && isValidPosition(aPosRightLast) ) + { + AddPointToPoly( aPoly, aPosMiddleLast, nLineIndex ); + AddPointToPoly( aPoly, aPosRightLast, nLineIndex ); + } + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ), uno::makeAny( PolyToPointSequence(aPoly) ) ); + this->setMappedProperties( xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + } + } + + //create data point label + if( (**aSeriesIter).getDataPointLabelIfLabel(nIndex) ) + { + if(isValidPosition(aPosMiddleFirst)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fY_First, 1.0, Position3DToAWTPoint(aPosMiddleFirst), LABEL_ALIGN_LEFT_BOTTOM ); + if(isValidPosition(aPosMiddleLast)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fY_Last, 1.0, Position3DToAWTPoint(aPosMiddleLast), LABEL_ALIGN_RIGHT_TOP ); + if(isValidPosition(aPosMiddleMinimum)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fY_Min, 1.0, Position3DToAWTPoint(aPosMiddleMinimum), LABEL_ALIGN_BOTTOM ); + if(isValidPosition(aPosMiddleMaximum)) + this->createDataLabel( xTextTarget, **aSeriesIter, nIndex + , fY_Max, 1.0, Position3DToAWTPoint(aPosMiddleMaximum), LABEL_ALIGN_TOP ); + } + }//next series in x slot (next y slot) + }//next x slot + }//next z slot + }//next category +//============================================================================= +//============================================================================= +//============================================================================= + /* @todo remove series shapes if empty + //remove and delete point-group-shape if empty + if(!xSeriesGroupShape_Shapes->getCount()) + { + (*aSeriesIter)->m_xShape.set(NULL); + m_xLogicTarget->remove(xSeriesGroupShape_Shape); + } + */ + + //remove and delete series-group-shape if empty + + //... todo +} + +//............................................................................. +} //namespace chart +//.............................................................................