diff options
Diffstat (limited to 'chart2/source/view/main')
26 files changed, 12197 insertions, 0 deletions
diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx new file mode 100644 index 000000000000..83368fa3907a --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.cxx @@ -0,0 +1,257 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "ChartItemPool.hxx" +#include "macros.hxx" + +#include "chartview/ChartSfxItemIds.hxx" +#include <svx/chrtitem.hxx> +#include <svl/intitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/sizeitem.hxx> +#include <svl/stritem.hxx> +#include <svl/ilstitem.hxx> +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <editeng/editids.hrc> +#include <svx/svxids.hrc> + +namespace chart +{ + +ChartItemPool::ChartItemPool(): + SfxItemPool( String( RTL_CONSTASCII_USTRINGPARAM( "ChartItemPool" )), SCHATTR_START, SCHATTR_END, NULL, NULL ) +{ +// OSL_TRACE( "SCH: CTOR: ChartItemPool" ); + /************************************************************************** + * PoolDefaults + **************************************************************************/ + ppPoolDefaults = new SfxPoolItem*[SCHATTR_END - SCHATTR_START + 1]; + + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_NUMBER - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_NUMBER); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_PERCENTAGE- SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_PERCENTAGE); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_CATEGORY - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_CATEGORY); + ppPoolDefaults[SCHATTR_DATADESCR_SHOW_SYMBOL - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_SYMBOL); + ppPoolDefaults[SCHATTR_DATADESCR_SEPARATOR - SCHATTR_START] = new SfxStringItem(SCHATTR_DATADESCR_SEPARATOR,C2U(" ")); + ppPoolDefaults[SCHATTR_DATADESCR_PLACEMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_DATADESCR_PLACEMENT,0); + SvULongs aTmp; + ppPoolDefaults[SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS,aTmp); + ppPoolDefaults[SCHATTR_DATADESCR_NO_PERCENTVALUE - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_NO_PERCENTVALUE); + + ppPoolDefaults[SCHATTR_LEGEND_POS - SCHATTR_START] = new SvxChartLegendPosItem( CHLEGEND_RIGHT, SCHATTR_LEGEND_POS ); +// ppPoolDefaults[SCHATTR_TEXT_ORIENT - SCHATTR_START] = new SvxChartTextOrientItem; + ppPoolDefaults[SCHATTR_TEXT_STACKED - SCHATTR_START] = new SfxBoolItem(SCHATTR_TEXT_STACKED,FALSE); + ppPoolDefaults[SCHATTR_TEXT_ORDER - SCHATTR_START] = new SvxChartTextOrderItem(CHTXTORDER_SIDEBYSIDE, SCHATTR_TEXT_ORDER); + + ppPoolDefaults[SCHATTR_Y_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_AUTO_MIN); + ppPoolDefaults[SCHATTR_Y_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Y_AXIS_MIN); + ppPoolDefaults[SCHATTR_Y_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_AUTO_MAX); + ppPoolDefaults[SCHATTR_Y_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Y_AXIS_MAX); + ppPoolDefaults[SCHATTR_Y_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_AUTO_STEP_MAIN); + ppPoolDefaults[SCHATTR_Y_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Y_AXIS_STEP_MAIN); + ppPoolDefaults[SCHATTR_Y_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_AUTO_STEP_HELP); + ppPoolDefaults[SCHATTR_Y_AXIS_STEP_HELP - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Y_AXIS_STEP_HELP); + ppPoolDefaults[SCHATTR_Y_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_LOGARITHM); + ppPoolDefaults[SCHATTR_Y_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Y_AXIS_AUTO_ORIGIN); + ppPoolDefaults[SCHATTR_Y_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Y_AXIS_ORIGIN); + + ppPoolDefaults[SCHATTR_X_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_AUTO_MIN); + ppPoolDefaults[SCHATTR_X_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_X_AXIS_MIN); + ppPoolDefaults[SCHATTR_X_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_AUTO_MAX); + ppPoolDefaults[SCHATTR_X_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_X_AXIS_MAX); + ppPoolDefaults[SCHATTR_X_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_AUTO_STEP_MAIN); + ppPoolDefaults[SCHATTR_X_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_X_AXIS_STEP_MAIN); + ppPoolDefaults[SCHATTR_X_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_AUTO_STEP_HELP); + ppPoolDefaults[SCHATTR_X_AXIS_STEP_HELP - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_X_AXIS_STEP_HELP); + ppPoolDefaults[SCHATTR_X_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_LOGARITHM); + ppPoolDefaults[SCHATTR_X_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_X_AXIS_AUTO_ORIGIN); + ppPoolDefaults[SCHATTR_X_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_X_AXIS_ORIGIN); + + ppPoolDefaults[SCHATTR_Z_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_AUTO_MIN); + ppPoolDefaults[SCHATTR_Z_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Z_AXIS_MIN); + ppPoolDefaults[SCHATTR_Z_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_AUTO_MAX); + ppPoolDefaults[SCHATTR_Z_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Z_AXIS_MAX); + ppPoolDefaults[SCHATTR_Z_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_AUTO_STEP_MAIN); + ppPoolDefaults[SCHATTR_Z_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Z_AXIS_STEP_MAIN); + ppPoolDefaults[SCHATTR_Z_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_AUTO_STEP_HELP); + ppPoolDefaults[SCHATTR_Z_AXIS_STEP_HELP - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Z_AXIS_STEP_HELP); + ppPoolDefaults[SCHATTR_Z_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_LOGARITHM); + ppPoolDefaults[SCHATTR_Z_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_Z_AXIS_AUTO_ORIGIN); + ppPoolDefaults[SCHATTR_Z_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_Z_AXIS_ORIGIN); + + ppPoolDefaults[SCHATTR_AXISTYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXISTYPE, CHART_AXIS_X); + ppPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_VALUE - SCHATTR_START] = new SfxInt32Item(SCHATTR_PERCENT_NUMBERFORMAT_VALUE, 0); + ppPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_SOURCE - SCHATTR_START] = new SfxBoolItem(SCHATTR_PERCENT_NUMBERFORMAT_SOURCE); + + ppPoolDefaults[SCHATTR_STAT_AVERAGE - SCHATTR_START] = new SfxBoolItem (SCHATTR_STAT_AVERAGE); + ppPoolDefaults[SCHATTR_STAT_KIND_ERROR - SCHATTR_START] = new SvxChartKindErrorItem (CHERROR_NONE, SCHATTR_STAT_KIND_ERROR); + ppPoolDefaults[SCHATTR_STAT_PERCENT - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_PERCENT); + ppPoolDefaults[SCHATTR_STAT_BIGERROR - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_BIGERROR); + ppPoolDefaults[SCHATTR_STAT_CONSTPLUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTPLUS); + ppPoolDefaults[SCHATTR_STAT_CONSTMINUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTMINUS); + ppPoolDefaults[SCHATTR_STAT_INDICATE - SCHATTR_START] = new SvxChartIndicateItem (CHINDICATE_NONE, SCHATTR_STAT_INDICATE); + ppPoolDefaults[SCHATTR_STAT_RANGE_POS - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_POS, String()); + ppPoolDefaults[SCHATTR_STAT_RANGE_NEG - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_NEG, String()); + + ppPoolDefaults[SCHATTR_TEXT_DEGREES - SCHATTR_START] = new SfxInt32Item(SCHATTR_TEXT_DEGREES, 0); + ppPoolDefaults[SCHATTR_TEXT_OVERLAP - SCHATTR_START] = new SfxBoolItem(SCHATTR_TEXT_OVERLAP,FALSE); + + ppPoolDefaults[SCHATTR_STYLE_DEEP - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_DEEP, 0); + ppPoolDefaults[SCHATTR_STYLE_3D - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_3D, 0); + ppPoolDefaults[SCHATTR_STYLE_VERTICAL - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_VERTICAL, 0); + ppPoolDefaults[SCHATTR_STYLE_BASETYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_STYLE_BASETYPE, 0); + ppPoolDefaults[SCHATTR_STYLE_LINES - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_LINES, 0); + ppPoolDefaults[SCHATTR_STYLE_PERCENT - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_PERCENT, 0); + ppPoolDefaults[SCHATTR_STYLE_STACKED - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_STACKED, 0); + ppPoolDefaults[SCHATTR_STYLE_SPLINES - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SPLINES, 0); //Bug: war Bool! ->Fileformat testen (betrifft nur 5er) + ppPoolDefaults[SCHATTR_STYLE_SYMBOL - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SYMBOL, 0); + ppPoolDefaults[SCHATTR_STYLE_SHAPE - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SHAPE, 0); + + ppPoolDefaults[SCHATTR_AXIS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS,2); //2 = Y-Achse!!! + + ppPoolDefaults[SCHATTR_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MIN); + ppPoolDefaults[SCHATTR_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MIN); + ppPoolDefaults[SCHATTR_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MAX); + ppPoolDefaults[SCHATTR_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MAX); + ppPoolDefaults[SCHATTR_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN); + ppPoolDefaults[SCHATTR_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_MAIN); + ppPoolDefaults[SCHATTR_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP); +// ppPoolDefaults[SCHATTR_AXIS_STEP_HELP - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_HELP); + // type changed from double to sal_Int32 + ppPoolDefaults[SCHATTR_AXIS_STEP_HELP - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_STEP_HELP,0); + ppPoolDefaults[SCHATTR_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LOGARITHM); + ppPoolDefaults[SCHATTR_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN); + ppPoolDefaults[SCHATTR_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_ORIGIN); + + ppPoolDefaults[SCHATTR_AXIS_TICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_TICKS,CHAXIS_MARK_OUTER); + ppPoolDefaults[SCHATTR_AXIS_NUMFMT - SCHATTR_START] = new SfxUInt32Item(SCHATTR_AXIS_NUMFMT,0); + ppPoolDefaults[SCHATTR_AXIS_NUMFMTPERCENT - SCHATTR_START] = new SfxUInt32Item(SCHATTR_AXIS_NUMFMTPERCENT,11); + ppPoolDefaults[SCHATTR_AXIS_SHOWAXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWAXIS,0); + ppPoolDefaults[SCHATTR_AXIS_SHOWDESCR - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWDESCR,0); + ppPoolDefaults[SCHATTR_AXIS_SHOWMAINGRID - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWMAINGRID,0); + ppPoolDefaults[SCHATTR_AXIS_SHOWHELPGRID - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWHELPGRID,0); + ppPoolDefaults[SCHATTR_AXIS_TOPDOWN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_TOPDOWN,0); + ppPoolDefaults[SCHATTR_AXIS_HELPTICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_HELPTICKS,0); + ppPoolDefaults[SCHATTR_AXIS_REVERSE - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_REVERSE,0); + + ppPoolDefaults[SCHATTR_AXIS_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_POSITION,0); + ppPoolDefaults[SCHATTR_AXIS_POSITION_VALUE - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_POSITION_VALUE); + ppPoolDefaults[SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT - SCHATTR_START] = new SfxUInt32Item(SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT,0); + ppPoolDefaults[SCHATTR_AXIS_LABEL_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_LABEL_POSITION,0); + ppPoolDefaults[SCHATTR_AXIS_MARK_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_MARK_POSITION,0); + + ppPoolDefaults[SCHATTR_SYMBOL_BRUSH - SCHATTR_START] = new SvxBrushItem(SCHATTR_SYMBOL_BRUSH); + ppPoolDefaults[SCHATTR_STOCK_VOLUME - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_VOLUME,0); + ppPoolDefaults[SCHATTR_STOCK_UPDOWN - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_UPDOWN,0); + ppPoolDefaults[SCHATTR_SYMBOL_SIZE - SCHATTR_START] = new SvxSizeItem(SCHATTR_SYMBOL_SIZE,Size(0,0)); + + // new for New Chart + ppPoolDefaults[SCHATTR_BAR_OVERLAP - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_OVERLAP,0); + ppPoolDefaults[SCHATTR_BAR_GAPWIDTH - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_GAPWIDTH,0); + ppPoolDefaults[SCHATTR_BAR_CONNECT - SCHATTR_START] = new SfxBoolItem(SCHATTR_BAR_CONNECT, FALSE); + ppPoolDefaults[SCHATTR_NUM_OF_LINES_FOR_BAR - SCHATTR_START] = new SfxInt32Item( SCHATTR_NUM_OF_LINES_FOR_BAR, 0 ); + ppPoolDefaults[SCHATTR_SPLINE_ORDER - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_ORDER, 3 ); + ppPoolDefaults[SCHATTR_SPLINE_RESOLUTION - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_RESOLUTION, 20 ); + ppPoolDefaults[SCHATTR_DIAGRAM_STYLE - SCHATTR_START] = new SvxChartStyleItem( CHSTYLE_2D_COLUMN, SCHATTR_DIAGRAM_STYLE ); + ppPoolDefaults[SCHATTR_TEXTBREAK - SCHATTR_START] = new SfxBoolItem( SCHATTR_TEXTBREAK, FALSE ); + ppPoolDefaults[SCHATTR_GROUP_BARS_PER_AXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_GROUP_BARS_PER_AXIS, FALSE); + ppPoolDefaults[SCHATTR_INCLUDE_HIDDEN_CELLS - SCHATTR_START] = new SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, TRUE); + ppPoolDefaults[SCHATTR_STARTING_ANGLE - SCHATTR_START] = new SfxInt32Item( SCHATTR_STARTING_ANGLE, 90 ); + ppPoolDefaults[SCHATTR_CLOCKWISE - SCHATTR_START] = new SfxBoolItem( SCHATTR_CLOCKWISE, FALSE ); + + ppPoolDefaults[SCHATTR_MISSING_VALUE_TREATMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT, 0); + ppPoolDefaults[SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS,aTmp); + + ppPoolDefaults[SCHATTR_AXIS_FOR_ALL_SERIES - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_FOR_ALL_SERIES, 0); + ppPoolDefaults[SCHATTR_REGRESSION_TYPE - SCHATTR_START] = new SvxChartRegressItem (CHREGRESS_NONE, SCHATTR_REGRESSION_TYPE); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_EQUATION - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_EQUATION, 0); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_COEFF - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_COEFF, 0); + + /************************************************************************** + * ItemInfos + **************************************************************************/ + pItemInfos = new SfxItemInfo[SCHATTR_END - SCHATTR_START + 1]; + + USHORT i; + for( i = SCHATTR_START; i <= SCHATTR_END; i++ ) + { + pItemInfos[i - SCHATTR_START]._nSID = 0; + pItemInfos[i - SCHATTR_START]._nFlags = SFX_ITEM_POOLABLE; + } + + // slot ids differing from which ids + pItemInfos[SCHATTR_SYMBOL_BRUSH - SCHATTR_START]._nSID = SID_ATTR_BRUSH; + pItemInfos[SCHATTR_STYLE_SYMBOL - SCHATTR_START]._nSID = SID_ATTR_SYMBOLTYPE; + pItemInfos[SCHATTR_SYMBOL_SIZE - SCHATTR_START]._nSID = SID_ATTR_SYMBOLSIZE; + + SetDefaults(ppPoolDefaults); + SetItemInfos(pItemInfos); +} + +ChartItemPool::ChartItemPool(const ChartItemPool& rPool): + SfxItemPool(rPool) +{ +// OSL_TRACE( "SCH: CTOR: ChartItemPool" ); +} + +ChartItemPool::~ChartItemPool() +{ +// OSL_TRACE( "SCH: DTOR: ChartItemPool" ); + Delete(); + + delete[] pItemInfos; + + const USHORT nMax = SCHATTR_END - SCHATTR_START + 1; + for( USHORT i=0; i<nMax; ++i ) + { + SetRefCount(*ppPoolDefaults[i], 0); + delete ppPoolDefaults[i]; + } + + delete[] ppPoolDefaults; +} + +SfxItemPool* ChartItemPool::Clone() const +{ + return new ChartItemPool(*this); +} + +SfxMapUnit ChartItemPool::GetMetric(USHORT /* nWhich */) const +{ + return SFX_MAPUNIT_100TH_MM; +} + +// static +SfxItemPool* ChartItemPool::CreateChartItemPool() +{ + return new ChartItemPool(); +} + +} // namespace chart diff --git a/chart2/source/view/main/ChartItemPool.hxx b/chart2/source/view/main/ChartItemPool.hxx new file mode 100644 index 000000000000..b8ee9910ce2d --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.hxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CHART2_ITEMPOOL_HXX +#define _CHART2_ITEMPOOL_HXX + +#include <svl/poolitem.hxx> +#include <svl/itempool.hxx> + +namespace chart +{ +class ChartItemPool : public SfxItemPool +{ +private: + SfxPoolItem** ppPoolDefaults; + SfxItemInfo* pItemInfos; + +public: + ChartItemPool(); + ChartItemPool(const ChartItemPool& rPool); +protected: + virtual ~ChartItemPool(); +public: + + virtual SfxItemPool* Clone() const; + SfxMapUnit GetMetric( USHORT nWhich ) const; + + /// creates a pure chart item pool + static SfxItemPool* CreateChartItemPool(); +}; + +} // namespace chart + +#endif +// _CHART2_ITEMPOOL_HXX diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx new file mode 100644 index 000000000000..549ef0273595 --- /dev/null +++ b/chart2/source/view/main/ChartView.cxx @@ -0,0 +1,3058 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "ChartView.hxx" +#include "chartview/DrawModelWrapper.hxx" +#include "ViewDefines.hxx" +#include "VDiagram.hxx" +#include "VTitle.hxx" +#include "ShapeFactory.hxx" +#include "VCoordinateSystem.hxx" +#include "VSeriesPlotter.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "TitleHelper.hxx" +#include "LegendHelper.hxx" +#include "VLegend.hxx" +#include "PropertyMapper.hxx" +#include "ChartModelHelper.hxx" +#include "ChartTypeHelper.hxx" +#include "ScaleAutomatism.hxx" +#include "MinimumAndMaximumSupplier.hxx" +#include "ObjectIdentifier.hxx" +#include "DiagramHelper.hxx" +#include "RelativePositionHelper.hxx" +#include "servicenames.hxx" +#include "AxisHelper.hxx" +#include "AxisIndexDefines.hxx" +#include "ControllerLockGuard.hxx" +#include "BaseGFXHelper.hxx" +#include "DataSeriesHelper.hxx" + +#include <comphelper/scopeguard.hxx> +#include <boost/bind.hpp> +#include <unotools/streamwrap.hxx> +// header for class LocaleDataWrapper +#include <unotools/localedatawrapper.hxx> +// header for class SdrPage +#include <svx/svdpage.hxx> +// header for class SvxDrawPage +#include <svx/unopage.hxx> +// header for class SvxShape +#include <svx/unoshape.hxx> +// header for class Application +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> +#include <svx/unofill.hxx> + +#include <time.h> + +#include <com/sun/star/chart/ChartAxisPosition.hpp> +#include <com/sun/star/chart/DataLabelPlacement.hpp> +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/chart2/ExplicitSubIncrement.hpp> +#include <com/sun/star/chart2/StackingDirection.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp> +#include <com/sun/star/chart2/XChartTypeContainer.hpp> +#include <com/sun/star/chart2/XDataSeriesContainer.hpp> +#include <com/sun/star/chart2/XTitled.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <com/sun/star/chart2/RelativeSize.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/XShapeGroup.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/util/XModifiable.hpp> +#include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/util/NumberFormat.hpp> + +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <svl/languageoptions.hxx> +#include <sot/clsids.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using rtl::OUString; + +//static +const uno::Sequence<sal_Int8>& ExplicitValueProvider::getUnoTunnelId() +{ + static uno::Sequence<sal_Int8> * pSeq = 0; + if( !pSeq ) + { + osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); + if( !pSeq ) + { + static uno::Sequence< sal_Int8 > aSeq( 16 ); + rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); + pSeq = &aSeq; + } + } + return *pSeq; +} + +//static +ExplicitValueProvider* ExplicitValueProvider::getExplicitValueProvider( + const Reference< uno::XInterface >& xChartView ) +{ + ExplicitValueProvider* pExplicitValueProvider=0; + + Reference< lang::XUnoTunnel > xTunnel( xChartView, uno::UNO_QUERY ); + if( xTunnel.is() ) + { + pExplicitValueProvider = reinterpret_cast<ExplicitValueProvider*>(xTunnel->getSomething( + ExplicitValueProvider::getUnoTunnelId() )); + } + return pExplicitValueProvider; +} + +ChartView::ChartView( + uno::Reference<uno::XComponentContext> const & xContext) + : m_aMutex() + , m_xCC(xContext) + , m_xChartModel() + , m_xShapeFactory() + , m_xDrawPage() + , m_pDrawModelWrapper() + , m_aListenerContainer( m_aMutex ) + , m_bViewDirty(true) + , m_bInViewUpdate(false) + , m_bViewUpdatePending(false) + , m_bRefreshAddIn(true) + , m_aPageResolution(1000,1000) + , m_bPointsWereSkipped(false) + , m_nScaleXNumerator(1) + , m_nScaleXDenominator(1) + , m_nScaleYNumerator(1) + , m_nScaleYDenominator(1) + , m_bSdrViewIsInEditMode(sal_False) +{ +} + +void ChartView::impl_setChartModel( const uno::Reference< frame::XModel >& xChartModel ) +{ + if( m_xChartModel != xChartModel ) + { + m_xChartModel = xChartModel; + m_bViewDirty = true; + } +} + +void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, uno::RuntimeException) +{ + DBG_ASSERT(aArguments.getLength() >= 1,"need 1 argument to initialize the view: xModel"); + if( !(aArguments.getLength() >= 1) ) + return; + + uno::Reference< frame::XModel > xNewChartModel; + if( !(aArguments[0] >>= xNewChartModel) ) + { + DBG_ERROR( "need a Reference to frame::XModel as first parameter for view initialization" ); + } + impl_setChartModel( xNewChartModel ); + + if( !m_pDrawModelWrapper.get() ) + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper = ::boost::shared_ptr< DrawModelWrapper >( new DrawModelWrapper( m_xCC ) ); + m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory(); + m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage(); + StartListening( m_pDrawModelWrapper->getSdrModel(), FALSE /*bPreventDups*/ ); + // \-- + } +} + +ChartView::~ChartView() +{ + if( m_pDrawModelWrapper.get() ) + EndListening( m_pDrawModelWrapper->getSdrModel(), FALSE /*bAllDups*/ ); + m_xDrawPage = NULL; + impl_deleteCoordinateSystems(); +} + +void ChartView::impl_deleteCoordinateSystems() +{ + //delete all coordinate systems + ::std::vector< VCoordinateSystem* > aVectorToDeleteObjects; + ::std::swap( aVectorToDeleteObjects, m_aVCooSysList );//#i109770# + ::std::vector< VCoordinateSystem* >::const_iterator aIter = aVectorToDeleteObjects.begin(); + const ::std::vector< VCoordinateSystem* >::const_iterator aEnd = aVectorToDeleteObjects.end(); + for( ; aIter != aEnd; aIter++ ) + { + delete *aIter; + } + aVectorToDeleteObjects.clear(); +} + + +//----------------------------------------------------------------- +// datatransfer::XTransferable +namespace +{ +const rtl::OUString lcl_aGDIMetaFileMIMEType( + RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"")); +const rtl::OUString lcl_aGDIMetaFileMIMETypeHighContrast( + RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"")); +} // anonymous namespace + +void ChartView::getMetaFile( const uno::Reference< io::XOutputStream >& xOutStream + , bool bUseHighContrast ) +{ + if( !m_xDrawPage.is() ) + return; + + uno::Reference< lang::XMultiServiceFactory > xFactory( m_xCC->getServiceManager(), uno::UNO_QUERY ); + if( !xFactory.is() ) + return; + + // creating the graphic exporter + uno::Reference< document::XExporter > xExporter( xFactory->createInstance( + C2U("com.sun.star.drawing.GraphicExportFilter")), uno::UNO_QUERY); + uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY ); + + if( !xExporter.is() || !xFilter.is() ) + return; + + uno::Sequence< beans::PropertyValue > aProps(3); + aProps[0].Name = C2U("FilterName"); + aProps[0].Value <<= C2U("SVM"); + + aProps[1].Name = C2U("OutputStream"); + aProps[1].Value <<= xOutStream; + + uno::Sequence< beans::PropertyValue > aFilterData(4); + aFilterData[0].Name = C2U("ExportOnlyBackground"); + aFilterData[0].Value <<= sal_False; + aFilterData[1].Name = C2U("HighContrast"); + aFilterData[1].Value <<= bUseHighContrast; + + aFilterData[2].Name = C2U("Version"); + const sal_Int32 nVersion = SOFFICE_FILEFORMAT_50; + aFilterData[2].Value <<= nVersion; + + aFilterData[3].Name = C2U("CurrentPage"); + aFilterData[3].Value <<= uno::Reference< uno::XInterface >( m_xDrawPage, uno::UNO_QUERY ); + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + { + aFilterData.realloc( aFilterData.getLength()+4 ); + aFilterData[4].Name = C2U("ScaleXNumerator"); + aFilterData[4].Value = uno::makeAny( m_nScaleXNumerator ); + aFilterData[5].Name = C2U("ScaleXDenominator"); + aFilterData[5].Value = uno::makeAny( m_nScaleXDenominator ); + aFilterData[6].Name = C2U("ScaleYNumerator"); + aFilterData[6].Value = uno::makeAny( m_nScaleYNumerator ); + aFilterData[7].Name = C2U("ScaleYDenominator"); + aFilterData[7].Value = uno::makeAny( m_nScaleYDenominator ); + } + + aProps[2].Name = C2U("FilterData"); + aProps[2].Value <<= aFilterData; + + xExporter->setSourceDocument( uno::Reference< lang::XComponent >( m_xDrawPage, uno::UNO_QUERY) ); + if( xFilter->filter( aProps ) ) + { + xOutStream->flush(); + xOutStream->closeOutput(); + uno::Reference< io::XSeekable > xSeekable( xOutStream, uno::UNO_QUERY ); + if( xSeekable.is() ) + xSeekable->seek(0); + } +} + +uno::Any SAL_CALL ChartView::getTransferData( const datatransfer::DataFlavor& aFlavor ) + throw (datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) +{ + bool bHighContrastMetaFile( aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMETypeHighContrast)); + uno::Any aRet; + if( ! (bHighContrastMetaFile || aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMEType)) ) + return aRet; + + impl_updateView(); + + SvMemoryStream aStream( 1024, 1024 ); + utl::OStreamWrapper* pStreamWrapper = new utl::OStreamWrapper( aStream ); + + uno::Reference< io::XOutputStream > xOutStream( pStreamWrapper ); + uno::Reference< io::XInputStream > xInStream( pStreamWrapper ); + uno::Reference< io::XSeekable > xSeekable( pStreamWrapper ); + + if( xOutStream.is() ) + { + this->getMetaFile( xOutStream, bHighContrastMetaFile ); + + if( xInStream.is() && xSeekable.is() ) + { + xSeekable->seek(0); + sal_Int32 nBytesToRead = xInStream->available(); + uno::Sequence< sal_Int8 > aSeq( nBytesToRead ); + xInStream->readBytes( aSeq, nBytesToRead); + aRet <<= aSeq; + xInStream->closeInput(); + } + } + + return aRet; +} +uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors() + throw (uno::RuntimeException) +{ + uno::Sequence< datatransfer::DataFlavor > aRet(2); + + aRet[0] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMEType, + C2U( "GDIMetaFile" ), + ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); + aRet[1] = datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, + C2U( "GDIMetaFile" ), + ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) ); + + return aRet; +} +::sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) + throw (uno::RuntimeException) +{ + return ( aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMEType) || + aFlavor.MimeType.equals(lcl_aGDIMetaFileMIMETypeHighContrast) ); +} + +//----------------------------------------------------------------- +// ____ XUnoTunnel ___ +::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) + throw( uno::RuntimeException) +{ + if( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( ExplicitValueProvider::getUnoTunnelId().getConstArray(), + aIdentifier.getConstArray(), 16 ) ) + { + ExplicitValueProvider* pProvider = this; + return reinterpret_cast<sal_Int64>(pProvider); + } + return 0; +} + +//----------------------------------------------------------------- +// lang::XServiceInfo + +APPHELPER_XSERVICEINFO_IMPL(ChartView,CHART_VIEW_SERVICE_IMPLEMENTATION_NAME) + + uno::Sequence< rtl::OUString > ChartView +::getSupportedServiceNames_Static() +{ + uno::Sequence< rtl::OUString > aSNS( 1 ); + aSNS.getArray()[ 0 ] = CHART_VIEW_SERVICE_NAME; + return aSNS; +} + +//----------------------------------------------------------------- +//----------------------------------------------------------------- + +::basegfx::B3DHomMatrix createTransformationSceneToScreen( + const ::basegfx::B2IRectangle& rDiagramRectangleWithoutAxes ) +{ + ::basegfx::B3DHomMatrix aM; + aM.scale(double(rDiagramRectangleWithoutAxes.getWidth())/FIXED_SIZE_FOR_3D_CHART_VOLUME + , -double(rDiagramRectangleWithoutAxes.getHeight())/FIXED_SIZE_FOR_3D_CHART_VOLUME, 1.0 ); + aM.translate(double(rDiagramRectangleWithoutAxes.getMinX()) + , double(rDiagramRectangleWithoutAxes.getMinY()+rDiagramRectangleWithoutAxes.getHeight()-1), 0); + return aM; +} + +VCoordinateSystem* findInCooSysList( const std::vector< VCoordinateSystem* >& rVCooSysList + , const uno::Reference< XCoordinateSystem >& xCooSys ) +{ + for( size_t nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(pVCooSys->getModel()==xCooSys) + return pVCooSys; + } + return NULL; +} + +VCoordinateSystem* addCooSysToList( std::vector< VCoordinateSystem* >& rVCooSysList + , const uno::Reference< XCoordinateSystem >& xCooSys + , const uno::Reference< frame::XModel >& xChartModel ) +{ + VCoordinateSystem* pVCooSys = findInCooSysList( rVCooSysList, xCooSys ); + if( !pVCooSys ) + { + pVCooSys = VCoordinateSystem::createCoordinateSystem(xCooSys ); + if(pVCooSys) + { + rtl::OUString aCooSysParticle( ObjectIdentifier::createParticleForCoordinateSystem( xCooSys, xChartModel ) ); + pVCooSys->setParticle(aCooSysParticle); + + pVCooSys->setExplicitCategoriesProvider( new ExplicitCategoriesProvider(xCooSys,xChartModel) ); + + rVCooSysList.push_back( pVCooSys ); + } + } + return pVCooSys; +} + +VCoordinateSystem* lcl_getCooSysForPlotter( const std::vector< VCoordinateSystem* >& rVCooSysList, MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + if(!pMinimumAndMaximumSupplier) + return 0; + for( size_t nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(pVCooSys->hasMinimumAndMaximumSupplier( pMinimumAndMaximumSupplier )) + return pVCooSys; + } + return 0; +} + +typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates wether this is a main or secondary axis +typedef std::pair< VCoordinateSystem* , tFullAxisIndex > tFullCoordinateSystem; +typedef std::map< VCoordinateSystem*, tFullAxisIndex > tCoordinateSystemMap; + +struct AxisUsage +{ + AxisUsage(); + ~AxisUsage(); + + void addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + ::std::vector< VCoordinateSystem* > getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + sal_Int32 getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ); + //tFullAxisIndex getDimensionAndIndexForCooSys( VCoordinateSystem* pCooSys ); + + ScaleAutomatism aScaleAutomatism; + +private: + tCoordinateSystemMap aCoordinateSystems; + std::map< sal_Int32, sal_Int32 > aMaxIndexPerDimension; +}; + +AxisUsage::AxisUsage() + : aScaleAutomatism(AxisHelper::createDefaultScale()) +{ +} + +AxisUsage::~AxisUsage() +{ + aCoordinateSystems.clear(); +} + +/* +tFullScaleIndex AxisUsage::getDimensionAndIndexForCooSys( VCoordinateSystem* pCooSys ) +{ + tFullScaleIndex aRet(0,0); + + tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); + if(aFound!=aCoordinateSystems.end()) + aRet = aFound->second; + + return aRet; +} +*/ + +void AxisUsage::addCoordinateSystem( VCoordinateSystem* pCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + if(!pCooSys) + return; + + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tCoordinateSystemMap::const_iterator aFound( aCoordinateSystems.find(pCooSys) ); + + //use one scale only once for each coordinate system + //main axis are preferred over secondary axis + //value scales are preferred + if(aFound!=aCoordinateSystems.end()) + { + sal_Int32 nFoundAxisIndex = aFound->second.second; + if( nFoundAxisIndex < nAxisIndex ) + return; + sal_Int32 nFoundDimension = aFound->second.first; + if( nFoundDimension ==1 ) + return; + if( nFoundDimension < nDimensionIndex ) + return; + } + aCoordinateSystems[pCooSys] = aFullAxisIndex; + + //set maximum scale index + std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); + if( aIter != aMaxIndexPerDimension.end() ) + { + sal_Int32 nCurrentMaxIndex = aIter->second; + if( nCurrentMaxIndex < nAxisIndex ) + aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; + } + else + aMaxIndexPerDimension[nDimensionIndex]=nAxisIndex; +} +::std::vector< VCoordinateSystem* > AxisUsage::getCoordinateSystems( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + ::std::vector< VCoordinateSystem* > aRet; + + tCoordinateSystemMap::const_iterator aIter; + for( aIter = aCoordinateSystems.begin(); aIter!=aCoordinateSystems.end();++aIter ) + { + if( aIter->second.first != nDimensionIndex ) + continue; + if( aIter->second.second != nAxisIndex ) + continue; + aRet.push_back( aIter->first ); + } + + return aRet; +} +sal_Int32 AxisUsage::getMaxAxisIndexForDimension( sal_Int32 nDimensionIndex ) +{ + sal_Int32 nRet = -1; + std::map< sal_Int32, sal_Int32 >::const_iterator aIter = aMaxIndexPerDimension.find(nDimensionIndex); + if( aIter != aMaxIndexPerDimension.end() ) + nRet = aIter->second; + return nRet; +} + +//----------------------------------------------------- + +class SeriesPlotterContainer +{ +public: + SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList ); + ~SeriesPlotterContainer(); + + void initializeCooSysAndSeriesPlotter( const uno::Reference< frame::XModel >& xChartModel ); + void initAxisUsageList(); + void doAutoScaling( const uno::Reference< frame::XModel >& xChartModel ); + void updateScalesAndIncrementsOnAxes(); + void setScalesFromCooSysToPlotter(); + void setNumberFormatsFromAxes(); + drawing::Direction3D getPreferredAspectRatio(); + + std::vector< VSeriesPlotter* >& getSeriesPlotterList() { return m_aSeriesPlotterList; } + std::vector< VCoordinateSystem* >& getCooSysList() { return m_rVCooSysList; } + std::vector< LegendEntryProvider* > getLegendEntryProviderList(); + + void AdaptScaleOfYAxisWithoutAttachedSeries( const uno::Reference< frame::XModel >& xChartModel ); + +private: + std::vector< VSeriesPlotter* > m_aSeriesPlotterList; + std::vector< VCoordinateSystem* >& m_rVCooSysList; + ::std::map< uno::Reference< XAxis >, AxisUsage > m_aAxisUsageList; + sal_Int32 m_nMaxAxisIndex; + bool m_bChartTypeUsesShiftedXAxisTicksPerDefault; +}; + +SeriesPlotterContainer::SeriesPlotterContainer( std::vector< VCoordinateSystem* >& rVCooSysList ) + : m_rVCooSysList( rVCooSysList ) + , m_nMaxAxisIndex(0) + , m_bChartTypeUsesShiftedXAxisTicksPerDefault(false) +{ +} + +SeriesPlotterContainer::~SeriesPlotterContainer() +{ + // - remove plotter from coordinatesystems + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + m_rVCooSysList[nC]->clearMinimumAndMaximumSupplierList(); + // - delete all plotter + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + delete *aPlotterIter; + m_aSeriesPlotterList.clear(); +} + +std::vector< LegendEntryProvider* > SeriesPlotterContainer::getLegendEntryProviderList() +{ + std::vector< LegendEntryProvider* > aRet( m_aSeriesPlotterList.size() ); + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + sal_Int32 nN = 0; + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; ++aPlotterIter, nN++ ) + aRet[nN] = *aPlotterIter; + return aRet; +} + +void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter( + const uno::Reference< frame::XModel >& xChartModel ) +{ + //------------ get model series from model + sal_Int32 nDiagramIndex = 0;//todo if more than one diagam is supported + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( !xDiagram.is()) + return; + + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartModel, uno::UNO_QUERY ); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if(!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + sal_Bool bSortByXValues = sal_False; + sal_Bool bConnectBars = sal_False; + sal_Bool bGroupBarsPerAxis = sal_True; + sal_Bool bIncludeHiddenCells = sal_True; + sal_Int32 nStartingAngle = 90; + try + { + uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY_THROW ); + xDiaProp->getPropertyValue( C2U( "SortByXValues" ) ) >>= bSortByXValues; + xDiaProp->getPropertyValue( C2U( "ConnectBars" ) ) >>= bConnectBars; + xDiaProp->getPropertyValue( C2U( "GroupBarsPerAxis" ) ) >>= bGroupBarsPerAxis; + xDiaProp->getPropertyValue( C2U( "IncludeHiddenCells" ) ) >>= bIncludeHiddenCells; + xDiaProp->getPropertyValue( C2U( "StartingAngle" ) ) >>= nStartingAngle; + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + //--------------------------------------------------------------------- + //prepare for autoscaling and shape creation + // - create plotter for charttypes (for each first scale group at each plotter, as they are independent) + // - add series to plotter (thus each charttype can provide minimum and maximum values for autoscaling) + // - add plotter to coordinate systems + + //iterate through all coordinate systems + uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + OSL_ASSERT( xCooSysContainer.is()); + if( !xCooSysContainer.is()) + return; + uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + sal_Int32 nGlobalSeriesIndex = 0;//for automatic symbols + for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS ) + { + uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] ); + VCoordinateSystem* pVCooSys = addCooSysToList(m_rVCooSysList,xCooSys,xChartModel); + + //iterate through all chart types in the current coordinate system + uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); + OSL_ASSERT( xChartTypeContainer.is()); + if( !xChartTypeContainer.is() ) + continue; + uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); + for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT ) + { + uno::Reference< XChartType > xChartType( aChartTypeList[nT] ); + + if(nT==0) + m_bChartTypeUsesShiftedXAxisTicksPerDefault = ChartTypeHelper::shiftTicksAtXAxisPerDefault( xChartType ); + + VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( xChartType, nDimensionCount ); + if( !pPlotter ) + continue; + m_aSeriesPlotterList.push_back( pPlotter ); + pPlotter->setNumberFormatsSupplier( xNumberFormatsSupplier ); + pPlotter->setColorScheme( xColorScheme ); + pPlotter->setExplicitCategoriesProvider( pVCooSys->getExplicitCategoriesProvider() ); + sal_Int32 nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( xDiagram, xChartType ); + + if(pVCooSys) + pVCooSys->addMinimumAndMaximumSupplier(pPlotter); + + //------------ add series to plotter and thus prepare him for providing minimum and maximum values + uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); + OSL_ASSERT( xDataSeriesContainer.is()); + if( !xDataSeriesContainer.is() ) + continue; + sal_Int32 zSlot=-1; + sal_Int32 xSlot=-1; + sal_Int32 ySlot=-1; + uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); + for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS ) + { + uno::Reference< XDataSeries > xDataSeries( aSeriesList[nS], uno::UNO_QUERY ); + if(!xDataSeries.is()) + continue; + if( !bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries) ) + continue; + + VDataSeries* pSeries = new VDataSeries( xDataSeries ); + + pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); + nGlobalSeriesIndex++; + + if( bSortByXValues ) + pSeries->doSortByXValues(); + + pSeries->setConnectBars( bConnectBars ); + pSeries->setGroupBarsPerAxis( bGroupBarsPerAxis ); + pSeries->setStartingAngle( nStartingAngle ); + + pSeries->setMissingValueTreatment( nMissingValueTreatment ); + + rtl::OUString aSeriesParticle( ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCS, nT, nS ) ); + pSeries->setParticle(aSeriesParticle); + + OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); + pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); + + //ignore secondary axis for charttypes that do not suppoert them + if( pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX && + !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount, 1 ) ) + { + pSeries->setAttachedAxisIndex(MAIN_AXIS_INDEX); + } + + StackingDirection eDirection = pSeries->getStackingDirection(); + switch(eDirection) + { + case StackingDirection_NO_STACKING: + xSlot++; ySlot=-1; + if(zSlot<0) + zSlot=0; + break; + case StackingDirection_Y_STACKING: + ySlot++; + if(xSlot<0) + xSlot=0; + if(zSlot<0) + zSlot=0; + break; + case StackingDirection_Z_STACKING: + zSlot++; xSlot=-1; ySlot=-1; + break; + default: + // UNO enums have one additional auto-generated case + break; + } + pPlotter->addSeries( pSeries, zSlot, xSlot, ySlot ); + } + } + } + + //transport seriesnames to the coordinatesystems if needed + if( m_aSeriesPlotterList.size() ) + { + uno::Sequence< rtl::OUString > aSeriesNames; + bool bSeriesNamesInitialized = false; + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = m_rVCooSysList[nC]; + if(!pVCooSys) + continue; + if( pVCooSys->needSeriesNamesForAxis() ) + { + if(!bSeriesNamesInitialized) + { + VSeriesPlotter* pSeriesPlotter = m_aSeriesPlotterList[0]; + if( pSeriesPlotter ) + aSeriesNames = pSeriesPlotter->getSeriesNames(); + bSeriesNamesInitialized = true; + } + pVCooSys->setSeriesNamesForAxis( aSeriesNames ); + } + } + } +} + +void SeriesPlotterContainer::initAxisUsageList() +{ + m_aAxisUsageList.clear(); + size_t nC; + for( nC=0; nC < m_rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = m_rVCooSysList[nC]; + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + uno::Reference< XCoordinateSystem > xCooSys = pVCooSys->getModel(); + if( nDimensionIndex >= xCooSys->getDimension() ) + continue; + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + uno::Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + if(m_aAxisUsageList.find(xAxis)==m_aAxisUsageList.end()) + m_aAxisUsageList[xAxis].aScaleAutomatism = ScaleAutomatism(xAxis->getScaleData()); + AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; + rAxisUsage.addCoordinateSystem(pVCooSys,nDimensionIndex,nAxisIndex); + } + } + } + } + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + //init m_nMaxAxisIndex + m_nMaxAxisIndex = 0; + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + sal_Int32 nLocalMax = aAxisIter->second.getMaxAxisIndexForDimension( nDimensionIndex ); + if( m_nMaxAxisIndex < nLocalMax ) + m_nMaxAxisIndex = nLocalMax; + } + } +} + +void SeriesPlotterContainer::setScalesFromCooSysToPlotter() +{ + //set scales to plotter to enable them to provide the preferred scene AspectRatio + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); + if(pVCooSys) + { + pSeriesPlotter->setScales( pVCooSys->getExplicitScales(0,0), pVCooSys->getPropertySwapXAndYAxis() ); + sal_Int32 nMaxAxisIndex = pVCooSys->getMaximumAxisIndexByDimension(1);//only additional value axis are relevant for series plotter + for( sal_Int32 nI=1; nI<=nMaxAxisIndex; nI++ ) + pSeriesPlotter->addSecondaryValueScale( pVCooSys->getExplicitScale(1,nI), nI ); + } + } +} + +void SeriesPlotterContainer::setNumberFormatsFromAxes() +{ + //set numberfarmats to plotter to enable them to display the data labels in the numberfromat of teh axis + + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( m_rVCooSysList, pSeriesPlotter ); + if(pVCooSys) + { + AxesNumberFormats aAxesNumberFormats; + uno::Reference< XCoordinateSystem > xCooSys = pVCooSys->getModel(); + sal_Int32 nDimensionCount = xCooSys->getDimension(); + for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nDimensionCount; ++nDimensionIndex) + { + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + try + { + Reference< beans::XPropertySet > xAxisProp( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ), uno::UNO_QUERY ); + if( xAxisProp.is()) + { + sal_Int32 nNumberFormatKey(0); + if( xAxisProp->getPropertyValue( C2U( "NumberFormat" ) ) >>= nNumberFormatKey ) + { + aAxesNumberFormats.setFormat( nNumberFormatKey, nDimensionIndex, nAxisIndex ); + } + } + } + catch( lang::IndexOutOfBoundsException& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + pSeriesPlotter->setAxesNumberFormats( aAxesNumberFormats ); + } + } +} + +void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() +{ + for( size_t nC=0; nC < m_rVCooSysList.size(); nC++) + m_rVCooSysList[nC]->updateScalesAndIncrementsOnAxes(); +} + +void SeriesPlotterContainer::doAutoScaling( const uno::Reference< frame::XModel >& xChartModel ) +{ + //precondition: need a initialized m_aSeriesPlotterList + //precondition: need a initialized m_aAxisUsageList + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + //iterate over the main scales first than secondary axis + size_t nC; + sal_Int32 nAxisIndex=0; + for( nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) + { + + // - first do autoscale for all x and z scales (because they are treated independent) + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_X = rAxisUsage.getCoordinateSystems(0,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Z = rAxisUsage.getCoordinateSystems(2,nAxisIndex); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + aVCooSysList_X[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,0,nAxisIndex); + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,2,nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aScaleAutomatism.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + { + ExplicitCategoriesProvider* pExplicitCategoriesProvider = aVCooSysList_X[nC]->getExplicitCategoriesProvider(); + + if( m_bChartTypeUsesShiftedXAxisTicksPerDefault || (aExplicitScale.AxisType==AxisType::CATEGORY && pExplicitCategoriesProvider && pExplicitCategoriesProvider->hasComplexCategories() ) ) + aExplicitIncrement.ShiftedPosition = true; + aVCooSysList_X[nC]->setExplicitScaleAndIncrement( 0, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->setExplicitScaleAndIncrement( 2, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + + // - second do autoscale for the dependent y scales (the coordinate systems are prepared with x and z scales already ) + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_X = rAxisUsage.getCoordinateSystems(0,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems(1,nAxisIndex); + ::std::vector< VCoordinateSystem* > aVCooSysList_Z = rAxisUsage.getCoordinateSystems(2,nAxisIndex); + + if(!aVCooSysList_Y.size()) + continue; + + for( nC=0; nC < aVCooSysList_Y.size(); nC++) + aVCooSysList_Y[nC]->prepareScaleAutomatismForDimensionAndIndex(rAxisUsage.aScaleAutomatism,1,nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aScaleAutomatism.calculateExplicitScaleAndIncrement( aExplicitScale, aExplicitIncrement ); + + for( nC=0; nC < aVCooSysList_X.size(); nC++) + aVCooSysList_X[nC]->setExplicitScaleAndIncrement( 0, nAxisIndex, aExplicitScale, aExplicitIncrement ); + for( nC=0; nC < aVCooSysList_Y.size(); nC++) + aVCooSysList_Y[nC]->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScale, aExplicitIncrement ); + for( nC=0; nC < aVCooSysList_Z.size(); nC++) + aVCooSysList_Z[nC]->setExplicitScaleAndIncrement( 2, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + } + AdaptScaleOfYAxisWithoutAttachedSeries( xChartModel ); +} + +void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries( const uno::Reference< frame::XModel >& xChartModel ) +{ + //issue #i80518# + + ::std::map< uno::Reference< XAxis >, AxisUsage >::iterator aAxisIter = m_aAxisUsageList.begin(); + const ::std::map< uno::Reference< XAxis >, AxisUsage >::const_iterator aAxisEndIter = m_aAxisUsageList.end(); + + for( sal_Int32 nAxisIndex=0; nAxisIndex<=m_nMaxAxisIndex; nAxisIndex++ ) + { + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList_Y = rAxisUsage.getCoordinateSystems( 1, nAxisIndex ); + if( !aVCooSysList_Y.size() ) + continue; + + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( xDiagram.is() ) + { + bool bSeriesAttachedToThisAxis = false; + sal_Int32 nAttachedAxisIndex = -1; + { + ::std::vector< Reference< XDataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); + ::std::vector< Reference< XDataSeries > >::const_iterator aIter = aSeriesVector.begin(); + for( ; aIter != aSeriesVector.end(); aIter++ ) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex( *aIter ); + if( nAxisIndex == nCurrentIndex ) + { + bSeriesAttachedToThisAxis = true; + break; + } + else if( nAttachedAxisIndex<0 || nAttachedAxisIndex>nCurrentIndex ) + nAttachedAxisIndex=nCurrentIndex; + } + } + + if( !bSeriesAttachedToThisAxis && nAttachedAxisIndex >= 0 ) + { + for( size_t nC = 0; nC < aVCooSysList_Y.size(); ++nC ) + { + aVCooSysList_Y[nC]->prepareScaleAutomatismForDimensionAndIndex( rAxisUsage.aScaleAutomatism, 1, nAttachedAxisIndex ); + + ExplicitScaleData aExplicitScaleSource = aVCooSysList_Y[nC]->getExplicitScale( 1,nAttachedAxisIndex ); + ExplicitIncrementData aExplicitIncrementSource = aVCooSysList_Y[nC]->getExplicitIncrement( 1,nAttachedAxisIndex ); + + ExplicitScaleData aExplicitScaleDest = aVCooSysList_Y[nC]->getExplicitScale( 1,nAxisIndex );; + ExplicitIncrementData aExplicitIncrementDest = aVCooSysList_Y[nC]->getExplicitIncrement( 1,nAxisIndex );; + + aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; + aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; + aExplicitScaleDest.Breaks = aExplicitScaleSource.Breaks; + aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; + + aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; + + ScaleData aScale( rAxisUsage.aScaleAutomatism.getScale() ); + if( !aScale.Minimum.hasValue() ) + { + bool bNewMinOK = true; + double fMax=0.0; + if( aScale.Maximum >>= fMax ) + bNewMinOK = (aExplicitScaleSource.Minimum <= fMax); + if( bNewMinOK ) + aExplicitScaleDest.Minimum = aExplicitScaleSource.Minimum; + } + else + aExplicitIncrementDest.BaseValue = aExplicitScaleDest.Minimum; + + if( !aScale.Maximum.hasValue() ) + { + bool bNewMaxOK = true; + double fMin=0.0; + if( aScale.Minimum >>= fMin ) + bNewMaxOK = (fMin <= aExplicitScaleSource.Maximum); + if( bNewMaxOK ) + aExplicitScaleDest.Maximum = aExplicitScaleSource.Maximum; + } + if( !aScale.Origin.hasValue() ) + aExplicitScaleDest.Origin = aExplicitScaleSource.Origin; + + if( !aScale.IncrementData.Distance.hasValue() ) + aExplicitIncrementDest.Distance = aExplicitIncrementSource.Distance; + + bool bAutoMinorInterval = true; + if( aScale.IncrementData.SubIncrements.getLength() ) + bAutoMinorInterval = !( aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ); + if( bAutoMinorInterval ) + { + if( aExplicitIncrementDest.SubIncrements.getLength() && aExplicitIncrementSource.SubIncrements.getLength() ) + aExplicitIncrementDest.SubIncrements[0].IntervalCount = + aExplicitIncrementSource.SubIncrements[0].IntervalCount; + } + + aVCooSysList_Y[nC]->setExplicitScaleAndIncrement( 1, nAxisIndex, aExplicitScaleDest, aExplicitIncrementDest ); + } + } + } + } + } + + if( AxisHelper::isAxisPositioningEnabled() ) + { + //correct origin for y main axis (the origin is where the other main axis crosses) + sal_Int32 nAxisIndex=0; + sal_Int32 nDimensionIndex=1; + for( aAxisIter = m_aAxisUsageList.begin(); aAxisIter != aAxisEndIter; aAxisIter++ ) + { + AxisUsage& rAxisUsage = (*aAxisIter).second; + ::std::vector< VCoordinateSystem* > aVCooSysList = rAxisUsage.getCoordinateSystems(nDimensionIndex,nAxisIndex); + size_t nC; + for( nC=0; nC < aVCooSysList.size(); nC++) + { + ExplicitScaleData aExplicitScale( aVCooSysList[nC]->getExplicitScale( nDimensionIndex, nAxisIndex ) ); + ExplicitIncrementData aExplicitIncrement( aVCooSysList[nC]->getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + + Reference< chart2::XCoordinateSystem > xCooSys( aVCooSysList[nC]->getModel() ); + Reference< XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) ); + Reference< beans::XPropertySet > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ), uno::UNO_QUERY ); + + ::com::sun::star::chart::ChartAxisPosition eCrossingMainAxisPos( ::com::sun::star::chart::ChartAxisPosition_ZERO ); + if( xCrossingMainAxis.is() ) + { + xCrossingMainAxis->getPropertyValue(C2U( "CrossoverPosition" )) >>= eCrossingMainAxisPos; + if( ::com::sun::star::chart::ChartAxisPosition_VALUE == eCrossingMainAxisPos ) + { + double fValue = 0.0; + xCrossingMainAxis->getPropertyValue(C2U( "CrossoverValue" )) >>= fValue; + aExplicitScale.Origin = fValue; + } + else if( ::com::sun::star::chart::ChartAxisPosition_ZERO == eCrossingMainAxisPos ) + aExplicitScale.Origin = 0.0; + else if( ::com::sun::star::chart::ChartAxisPosition_START == eCrossingMainAxisPos ) + aExplicitScale.Origin = aExplicitScale.Minimum; + else if( ::com::sun::star::chart::ChartAxisPosition_END == eCrossingMainAxisPos ) + aExplicitScale.Origin = aExplicitScale.Maximum; + } + + aVCooSysList[nC]->setExplicitScaleAndIncrement( nDimensionIndex, nAxisIndex, aExplicitScale, aExplicitIncrement ); + } + } + } +} + +drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() +{ + drawing::Direction3D aPreferredAspectRatio(1.0,1.0,1.0); + + sal_Int32 nPlotterCount=0; + //get a list of all preferred aspect ratios and combine them + //first with special demands wins (less or equal zero <-> arbitrary) + double fx, fy, fz; + fx = fy = fz = -1.0; + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = m_aSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = m_aSeriesPlotterList.end(); + for( aPlotterIter = m_aSeriesPlotterList.begin(), nPlotterCount=0 + ; aPlotterIter != aPlotterEnd; aPlotterIter++, nPlotterCount++ ) + { + drawing::Direction3D aSingleRatio( (*aPlotterIter)->getPreferredDiagramAspectRatio() ); + if( fx<0 && aSingleRatio.DirectionX>0 ) + fx = aSingleRatio.DirectionX; + + if( fy<0 && aSingleRatio.DirectionY>0 ) + { + if( fx>0 && aSingleRatio.DirectionX>0 ) + fy = fx*aSingleRatio.DirectionY/aSingleRatio.DirectionX; + else if( fz>0 && aSingleRatio.DirectionZ>0 ) + fy = fz*aSingleRatio.DirectionY/aSingleRatio.DirectionZ; + else + fy = aSingleRatio.DirectionY; + } + + if( fz<0 && aSingleRatio.DirectionZ>0 ) + { + if( fx>0 && aSingleRatio.DirectionX>0 ) + fz = fx*aSingleRatio.DirectionZ/aSingleRatio.DirectionX; + else if( fy>0 && aSingleRatio.DirectionY>0 ) + fz = fy*aSingleRatio.DirectionZ/aSingleRatio.DirectionY; + else + fz = aSingleRatio.DirectionZ; + } + + if( fx>0 && fy>0 && fz>0 ) + break; + } + aPreferredAspectRatio = drawing::Direction3D(fx, fy, fz); + return aPreferredAspectRatio; +} + +//----------------------------------------------------- + +namespace +{ + +bool lcl_resizeAfterCompleteCreation( const uno::Reference< XDiagram >& xDiagram ) +{ + //special treatment for pie charts + //the size is checked after complete creation to get the datalabels into the given space + + //todo: this is just a workaround at the moment for pie and donut labels + return DiagramHelper::isPieOrDonutChart( xDiagram ); +} + +void lcl_setDefaultWritingMode( ::boost::shared_ptr< DrawModelWrapper > pDrawModelWrapper, const Reference< frame::XModel >& xChartModel ) +{ + //get writing mode from parent document: + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + try + { + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + sal_Int16 nWritingMode=-1; + if ( xChild.is() ) + { + uno::Reference< beans::XPropertySet > xParentProps( xChild->getParent(), uno::UNO_QUERY ); + uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSupplier( xParentProps, uno::UNO_QUERY ); + if( xStyleFamiliesSupplier.is() ) + { + uno::Reference< container::XNameAccess > xStylesFamilies( xStyleFamiliesSupplier->getStyleFamilies() ); + if( xStylesFamilies.is() ) + { + if( !xStylesFamilies->hasByName( C2U("PageStyles") ) ) + { + //draw/impress is parent document + uno::Reference< lang::XMultiServiceFactory > xFatcory( xParentProps, uno::UNO_QUERY ); + if( xFatcory.is() ) + { + uno::Reference< beans::XPropertySet > xDrawDefaults( xFatcory->createInstance( C2U( "com.sun.star.drawing.Defaults" ) ), uno::UNO_QUERY ); + if( xDrawDefaults.is() ) + xDrawDefaults->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + } + else + { + uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( C2U("PageStyles") ), uno::UNO_QUERY ); + if( xPageStyles.is() ) + { + rtl::OUString aPageStyle; + + uno::Reference< text::XTextDocument > xTextDocument( xParentProps, uno::UNO_QUERY ); + if( xTextDocument.is() ) + { + //writer is parent document + //retrieve the current page style from the text cursor property PageStyleName + + uno::Reference< text::XTextEmbeddedObjectsSupplier > xTextEmbeddedObjectsSupplier( xTextDocument, uno::UNO_QUERY ); + if( xTextEmbeddedObjectsSupplier.is() ) + { + uno::Reference< container::XNameAccess > xEmbeddedObjects( xTextEmbeddedObjectsSupplier->getEmbeddedObjects() ); + if( xEmbeddedObjects.is() ) + { + uno::Sequence< rtl::OUString > aNames( xEmbeddedObjects->getElementNames() ); + + sal_Int32 nCount = aNames.getLength(); + for( sal_Int32 nN=0; nN<nCount; nN++ ) + { + uno::Reference< beans::XPropertySet > xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY ); + if( xEmbeddedProps.is() ) + { + static rtl::OUString aChartCLSID = rtl::OUString( SvGlobalName( SO3_SCH_CLASSID ).GetHexName()); + rtl::OUString aCLSID; + xEmbeddedProps->getPropertyValue( C2U("CLSID") ) >>= aCLSID; + if( aCLSID.equals(aChartCLSID) ) + { + uno::Reference< frame::XModel > xModel; + xEmbeddedProps->getPropertyValue( C2U("Model") ) >>= xModel; + if( xModel == xChartModel ) + { + uno::Reference< text::XTextContent > xEmbeddedObject( xEmbeddedProps, uno::UNO_QUERY ); + if( xEmbeddedObject.is() ) + { + uno::Reference< text::XTextRange > xAnchor( xEmbeddedObject->getAnchor() ); + if( xAnchor.is() ) + { + uno::Reference< beans::XPropertySet > xAnchorProps( xAnchor, uno::UNO_QUERY ); + if( xAnchorProps.is() ) + { + xAnchorProps->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + uno::Reference< text::XText > xText( xAnchor->getText() ); + if( xText.is() ) + { + uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); + if( xTextCursorProps.is() ) + xTextCursorProps->getPropertyValue( C2U("PageStyleName") ) >>= aPageStyle; + } + } + } + break; + } + } + } + } + } + } + if( !aPageStyle.getLength() ) + { + uno::Reference< text::XText > xText( xTextDocument->getText() ); + if( xText.is() ) + { + uno::Reference< beans::XPropertySet > xTextCursorProps( xText->createTextCursor(), uno::UNO_QUERY ); + if( xTextCursorProps.is() ) + xTextCursorProps->getPropertyValue( C2U("PageStyleName") ) >>= aPageStyle; + } + } + } + else + { + //Calc is parent document + xParentProps->getPropertyValue( C2U("PageStyle") ) >>= aPageStyle; + if(!aPageStyle.getLength()) + aPageStyle = C2U("Default"); + } + if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE ) + { + uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY ); + if( xPageStyle.is() ) + xPageStyle->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode; + } + } + } + } + } + } + if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) + { + if( pDrawModelWrapper.get() ) + pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SfxInt32Item(EE_PARA_WRITINGDIR, nWritingMode) ); + } + } + catch( uno::Exception& ex ) + { + ASSERT_EXCEPTION( ex ); + } + } +} + +sal_Int16 lcl_getDefaultWritingModeFromPool( ::boost::shared_ptr< DrawModelWrapper > pDrawModelWrapper ) +{ + sal_Int16 nWritingMode = text::WritingMode2::LR_TB; + if( pDrawModelWrapper.get() ) + { + const SfxPoolItem* pItem = &(pDrawModelWrapper->GetItemPool().GetDefaultItem( EE_PARA_WRITINGDIR )); + if( pItem ) + nWritingMode = static_cast< sal_Int16 >((static_cast< const SfxInt32Item * >( pItem ))->GetValue()); + } + return nWritingMode; +} + +} //end anonymous namespace + +//------------ create complete diagram shape (inclusive axis and series) +void ChartView::impl_createDiagramAndContent( SeriesPlotterContainer& rSeriesPlotterContainer + , const uno::Reference< drawing::XShapes>& xDiagramPlusAxes_Shapes + , const awt::Point& rAvailablePos + , const awt::Size& rAvailableSize + , const awt::Size& rPageSize ) +{ +// sal_Int32 nDiagramIndex = 0;//todo if more than one diagam is supported + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartModel ) ); + if( !xDiagram.is()) + return; + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if(!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + ::basegfx::B2IRectangle aAvailableOuterRect( BaseGFXHelper::makeRectangle(rAvailablePos,rAvailableSize) ); + + const std::vector< VCoordinateSystem* >& rVCooSysList( rSeriesPlotterContainer.getCooSysList() ); + const std::vector< VSeriesPlotter* >& rSeriesPlotterList( rSeriesPlotterContainer.getSeriesPlotterList() ); + + //create VAxis, so they can give necessary information for automatic scaling + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( m_xChartModel, uno::UNO_QUERY ); + size_t nC = 0; + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + if(3==nDimensionCount) + { + uno::Reference<beans::XPropertySet> xSceneProperties( xDiagram, uno::UNO_QUERY ); + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xSceneProperties ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xSceneProperties ) ); + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xSceneProperties ) ); + pVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); + } + pVCooSys->createVAxisList( xNumberFormatsSupplier + , rPageSize //font reference size + , BaseGFXHelper::B2IRectangleToAWTRectangle( aAvailableOuterRect ) //maximum space for labels + ); + } + + + // - prepare list of all axis and how they are used + rSeriesPlotterContainer.initAxisUsageList(); + rSeriesPlotterContainer.doAutoScaling( m_xChartModel ); + rSeriesPlotterContainer.setScalesFromCooSysToPlotter(); + rSeriesPlotterContainer.setNumberFormatsFromAxes(); + + //--------------------------------------------------------------------- + //create shapes + + //------------ create diagram shapes + //aspect ratio + drawing::Direction3D aPreferredAspectRatio( + rSeriesPlotterContainer.getPreferredAspectRatio() ); + + uno::Reference< drawing::XShapes > xSeriesTargetInFrontOfAxis(0); + uno::Reference< drawing::XShapes > xSeriesTargetBehindAxis(0); + VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount); + {//create diagram + aVDiagram.init(xDiagramPlusAxes_Shapes,xDiagramPlusAxes_Shapes,m_xShapeFactory); + aVDiagram.createShapes(rAvailablePos,rAvailableSize); + xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion(); + aVDiagram.reduceToMimimumSize(); + } + + uno::Reference< drawing::XShapes > xTextTargetShapes( ShapeFactory(m_xShapeFactory).createGroup2D(xDiagramPlusAxes_Shapes) ); + + // - create axis and grids for all coordinate systems + + //init all coordinate systems + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + pVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis,xTextTargetShapes,m_xShapeFactory,xSeriesTargetBehindAxis); + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + pVCooSys->initVAxisInList(); + } + + //calculate resulting size respecting axis label layout and fontscaling + + //use first coosys only so far; todo: calculate for more than one coosys if we have more in future + //todo: this is just a workaround at the moment for pie and donut labels + if( !lcl_resizeAfterCompleteCreation(xDiagram) && rVCooSysList.size() > 0 ) + { + uno::Reference< drawing::XShape > xBoundingShape( xDiagramPlusAxes_Shapes, uno::UNO_QUERY ); + + ::basegfx::B2IRectangle aFirstConsumedOuterRect( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + + VCoordinateSystem* pVCooSys = rVCooSysList[0]; + pVCooSys->createMaximumAxesLabels(); + + ::basegfx::B2IRectangle aConsumedOuterRect( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.adjustInnerSize( aConsumedOuterRect ) ); + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aNewInnerRect ) )); + + //redo autoscaling to get size and text dependent automatic main increment count + rSeriesPlotterContainer.doAutoScaling( m_xChartModel ); + rSeriesPlotterContainer.updateScalesAndIncrementsOnAxes(); + rSeriesPlotterContainer.setScalesFromCooSysToPlotter(); + + pVCooSys->createAxesLabels(); + + bool bLessSpaceConsumedThanExpected = false; + { + ::basegfx::B2IRectangle aOldRect( aConsumedOuterRect ); + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(xBoundingShape); + if( aConsumedOuterRect.getMinX() > aAvailableOuterRect.getMinX() + || aConsumedOuterRect.getMaxX() < aAvailableOuterRect.getMaxX() + || aConsumedOuterRect.getMinY() > aAvailableOuterRect.getMinY() + || aConsumedOuterRect.getMinY() < aAvailableOuterRect.getMaxY() ) + bLessSpaceConsumedThanExpected = true; + } + + if( bLessSpaceConsumedThanExpected ) + { + aVDiagram.adjustInnerSize( aConsumedOuterRect ); + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + pVCooSys->updatePositions(); + } + } + + //create axes and grids for the final size + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + pVCooSys->createAxesShapes(); + pVCooSys->createGridShapes(); + } + + // - create data series for all charttypes + m_bPointsWereSkipped = false; + ::std::vector< VSeriesPlotter* >::const_iterator aPlotterIter = rSeriesPlotterList.begin(); + const ::std::vector< VSeriesPlotter* >::const_iterator aPlotterEnd = rSeriesPlotterList.end(); + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + //------------ set transformation to plotter / create series + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + rtl::OUString aCID; //III + uno::Reference< drawing::XShapes > xSeriesTarget(0); + if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() ) + xSeriesTarget = xSeriesTargetInFrontOfAxis; + else + { + xSeriesTarget = xSeriesTargetBehindAxis; + DBG_ASSERT( !lcl_resizeAfterCompleteCreation(xDiagram), "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" ); + } + pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,m_xShapeFactory,aCID ); + pSeriesPlotter->setPageReferenceSize( rPageSize ); + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + if(2==nDimensionCount) + pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + //better performance for big data + awt::Size aCoordinateRegionResolution(1000,1000); + { + //calculate resolution for coordinate system + Sequence<sal_Int32> aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution ); + pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution ); + } + // + pSeriesPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); + } + + //recreate with corrected sizes if requested + if( lcl_resizeAfterCompleteCreation(xDiagram) ) + { + m_bPointsWereSkipped = false; + + uno::Reference< drawing::XShape > xBoundingShape( xDiagramPlusAxes_Shapes, uno::UNO_QUERY ); + ::basegfx::B2IRectangle aConsumedOuterRect( ShapeFactory::getRectangleOfShape(xBoundingShape) ); + + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.adjustInnerSize( aConsumedOuterRect ) ); + + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + pSeriesPlotter->releaseShapes(); + } + + //clear and recreate + ShapeFactory::removeSubShapes( xSeriesTargetInFrontOfAxis ); //xSeriesTargetBehindAxis is a sub shape of xSeriesTargetInFrontOfAxis and will be removed here + xSeriesTargetBehindAxis.clear(); + ShapeFactory::removeSubShapes( xTextTargetShapes ); + + //set new transformation + for( nC=0; nC < rVCooSysList.size(); nC++) + { + VCoordinateSystem* pVCooSys = rVCooSysList[nC]; + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aNewInnerRect ) )); + } + + // - create data series for all charttypes + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + //------------ set transformation to plotter / create series + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + VCoordinateSystem* pVCooSys = lcl_getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + if(2==nDimensionCount) + pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + pSeriesPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); + } + + /* + uno::Reference< drawing::XShape > xDiagramPlusAxes_KeepRatio( xDiagramPlusAxes_Shapes, uno::UNO_QUERY ); + + awt::Size aNewSize( rAvailableSize ); + awt::Point aNewPos( rAvailablePos ); + if( bKeepAspectRatio ) + { + awt::Size aCurrentSize( xDiagramPlusAxes_KeepRatio->getSize()); + + aNewSize = ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, aCurrentSize ); + aNewPos = ShapeFactory::calculateTopLeftPositionToCenterObject( + rAvailablePos, rAvailableSize, aNewSize ); + } + + xDiagramPlusAxes_KeepRatio->setPosition( aNewPos ); + xDiagramPlusAxes_KeepRatio->setSize( aNewSize ); + */ + for( aPlotterIter = rSeriesPlotterList.begin(); aPlotterIter != aPlotterEnd; aPlotterIter++ ) + { + VSeriesPlotter* pSeriesPlotter = *aPlotterIter; + pSeriesPlotter->rearrangeLabelToAvoidOverlapIfRequested( rPageSize ); + } + } +} + +//------------------------------------------------------------- +//------------------------------------------------------------- +//------------------------------------------------------------- + +sal_Bool ChartView::getExplicitValuesForAxis( + uno::Reference< XAxis > xAxis + , ExplicitScaleData& rExplicitScale + , ExplicitIncrementData& rExplicitIncrement ) +{ + impl_updateView(); + + if(!xAxis.is()) + return sal_False; + + uno::Reference< XCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis(xAxis,ChartModelHelper::findDiagram( m_xChartModel ) ) ); + const VCoordinateSystem* pVCooSys = findInCooSysList(m_aVCooSysList,xCooSys); + if(!pVCooSys) + return sal_False; + + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) + { + rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex); + rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex); + return sal_True; + } + return sal_False; +} + +SdrPage* ChartView::getSdrPage() +{ + SdrPage* pPage=0; + Reference< lang::XUnoTunnel> xUnoTunnel(m_xDrawPage,uno::UNO_QUERY); + if(xUnoTunnel.is()) + { + SvxDrawPage* pSvxDrawPage = reinterpret_cast<SvxDrawPage*>(xUnoTunnel->getSomething( + SvxDrawPage::getUnoTunnelId() )); + if(pSvxDrawPage) + { + pPage = pSvxDrawPage->GetSdrPage(); + } + } + return pPage; +} + +uno::Reference< drawing::XShape > ChartView::getShapeForCID( const rtl::OUString& rObjectCID ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); + if( pObj ) + return uno::Reference< drawing::XShape >( pObj->getUnoShape(), uno::UNO_QUERY); + return 0; +} + +awt::Rectangle ChartView::getRectangleOfObject( const rtl::OUString& rObjectCID, bool bSnapRect ) +{ + impl_updateView(); + + awt::Rectangle aRet; + uno::Reference< drawing::XShape > xShape( getShapeForCID(rObjectCID) ); + if(xShape.is()) + { + //special handling for axis for old api: + //same special handling for diagram + ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); + if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_DIAGRAM ) + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + SvxShape* pRoot = SvxShape::getImplementation( xShape ); + if( pRoot ) + { + SdrObject* pRootSdrObject = pRoot->GetSdrObject(); + if( pRootSdrObject ) + { + SdrObjList* pRootList = pRootSdrObject->GetSubList(); + if( pRootList ) + { + SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( C2U("MarkHandles"), pRootList ); + if( pShape ) + xShape = uno::Reference< drawing::XShape >( pShape->getUnoShape(), uno::UNO_QUERY); + } + } + } + } + + awt::Size aSize( xShape->getSize() ); + awt::Point aPoint( xShape->getPosition() ); + aRet = awt::Rectangle( aPoint.X, aPoint.Y, aSize.Width, aSize.Height ); + if( bSnapRect ) + { + //for rotated objects the shape size and position differs from the visible rectangle + SvxShape* pShape = SvxShape::getImplementation( xShape ); + if( pShape ) + { + SdrObject* pSdrObject = pShape->GetSdrObject(); + if( pSdrObject ) + { + Rectangle aSnapRect( pSdrObject->GetSnapRect() ); + aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight()); + } + } + } + } + return aRet; +} + +::boost::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() +{ + return m_pDrawModelWrapper; +} + +namespace +{ +sal_Int32 lcl_getDiagramTitleSpace() +{ + return 200; //=0,2 cm spacing +} +bool lcl_getPropertySwapXAndYAxis( const uno::Reference< XDiagram >& xDiagram ) +{ + bool bSwapXAndY = false; + + uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + if( xCooSysContainer.is() ) + { + uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + if( aCooSysList.getLength() ) + { + uno::Reference<beans::XPropertySet> xProp(aCooSysList[0], uno::UNO_QUERY ); + if( xProp.is()) try + { + xProp->getPropertyValue( C2U( "SwapXAndYAxis" ) ) >>= bSwapXAndY; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + return bSwapXAndY; +} + +} + +sal_Int32 lcl_getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , bool bSearchForParallelAxisIfNothingIsFound ) +{ + sal_Int32 nNumberFormatKey(0); + Reference< beans::XPropertySet > xProp( xAxis, uno::UNO_QUERY ); + if( xProp.is() && !( xProp->getPropertyValue( C2U( "NumberFormat" ) ) >>= nNumberFormatKey ) ) + { + bool bPercentFormatSet = false; + //check wether we have a percent scale -> use percent format + if( xNumberFormatsSupplier.is() ) + { + ScaleData aData = xAxis->getScaleData(); + if( aData.AxisType==AxisType::PERCENT ) + { + sal_Int32 nPercentFormat = ExplicitValueProvider::getPercentNumberFormat( xNumberFormatsSupplier ); + if( nPercentFormat != -1 ) + { + nNumberFormatKey = nPercentFormat; + bPercentFormatSet = true; + } + } + } + + if( !bPercentFormatSet ) + { + typedef ::std::map< sal_Int32, sal_Int32 > tNumberformatFrequency; + tNumberformatFrequency aKeyMap; + + bool bNumberFormatKeyFoundViaAttachedData = false; + sal_Int32 nAxisIndex = 0; + sal_Int32 nDimensionIndex = 1; + + try + { + Reference< XChartTypeContainer > xCTCnt( xCorrespondingCoordinateSystem, uno::UNO_QUERY_THROW ); + if( xCTCnt.is() ) + { + AxisHelper::getIndicesForAxis( xAxis, xCorrespondingCoordinateSystem, nDimensionIndex, nAxisIndex ); + ::rtl::OUString aRoleToMatch; + if( nDimensionIndex == 0 ) + aRoleToMatch = C2U("values-x"); + Sequence< Reference< XChartType > > aChartTypes( xCTCnt->getChartTypes()); + for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx ) + { + if( nDimensionIndex != 0 ) + aRoleToMatch = ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( aChartTypes[nCTIdx] ); + Reference< XDataSeriesContainer > xDSCnt( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW ); + Sequence< Reference< XDataSeries > > aDataSeriesSeq( xDSCnt->getDataSeries()); + for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aDataSeriesSeq.getLength(); ++nSeriesIdx ) + { + Reference< chart2::XDataSeries > xDataSeries(aDataSeriesSeq[nSeriesIdx]); + Reference< data::XDataSource > xSource( xDataSeries, uno::UNO_QUERY_THROW ); + + if( nDimensionIndex == 1 ) + { + //only take those series into accoutn that are attached to this axis + sal_Int32 nAttachedAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + if( nAttachedAxisIndex != nAxisIndex ) + continue; + } + + Sequence< Reference< data::XLabeledDataSequence > > aLabeledSeq( xSource->getDataSequences()); + for( sal_Int32 nLSeqIdx=0; nLSeqIdx<aLabeledSeq.getLength(); ++nLSeqIdx ) + { + if(!aLabeledSeq[nLSeqIdx].is()) + continue; + Reference< data::XDataSequence > xSeq( aLabeledSeq[nLSeqIdx]->getValues()); + if(!xSeq.is()) + continue; + Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); + ::rtl::OUString aRole; + bool bTakeIntoAccount = + ( xSeqProp.is() && (aRoleToMatch.getLength() > 0) && + (xSeqProp->getPropertyValue(C2U("Role")) >>= aRole ) && + aRole.equals( aRoleToMatch )); + + if( bTakeIntoAccount ) + { + sal_Int32 nKey = xSeq->getNumberFormatKeyByIndex( -1 ); + // initialize the value + if( aKeyMap.find( nKey ) == aKeyMap.end()) + aKeyMap[ nKey ] = 0; + // increase frequency + aKeyMap[ nKey ] = (aKeyMap[ nKey ] + 1); + } + } + } + } + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + if( ! aKeyMap.empty()) + { + sal_Int32 nMaxFreq = 0; + // find most frequent key + for( tNumberformatFrequency::const_iterator aIt = aKeyMap.begin(); + aIt != aKeyMap.end(); ++aIt ) + { + OSL_TRACE( "NumberFormatKey %d appears %d times", (*aIt).first, (*aIt).second ); + // all values must at least be 1 + if( (*aIt).second > nMaxFreq ) + { + nNumberFormatKey = (*aIt).first; + bNumberFormatKeyFoundViaAttachedData = true; + nMaxFreq = (*aIt).second; + } + } + } + + if( bSearchForParallelAxisIfNothingIsFound ) + { + //no format is set to this axis and no data is set to this axis + //--> try to obtain the format from the parallel y-axis + if( !bNumberFormatKeyFoundViaAttachedData && nDimensionIndex == 1 ) + { + sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1; + Reference< XAxis > xParallelAxis( AxisHelper::getAxis( 1, nParallelAxisIndex, xCorrespondingCoordinateSystem ) ); + nNumberFormatKey = lcl_getExplicitNumberFormatKeyForAxis( xParallelAxis, xCorrespondingCoordinateSystem, xNumberFormatsSupplier, false ); + } + } + } + } + return nNumberFormatKey; +} + +//static +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const Reference< chart2::XCoordinateSystem > & xCorrespondingCoordinateSystem + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + return lcl_getExplicitNumberFormatKeyForAxis( xAxis, xCorrespondingCoordinateSystem, xNumberFormatsSupplier + , true /*bSearchForParallelAxisIfNothingIsFound*/ ); +} + +//static +sal_Int32 ExplicitValueProvider::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + sal_Int32 nRet=-1; + Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() ); + if( xNumberFormats.is() ) + { + sal_Bool bCreate = sal_True; + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + Sequence<sal_Int32> aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT, + rLocaleDataWrapper.getLocale(), bCreate ); + if( aKeySeq.getLength() ) + { + nRet = aKeySeq[0]; + } + } + return nRet; +} + + +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, + const uno::Reference< XDataSeries >& xSeries, + sal_Int32 nPointIndex /*-1 for whole series*/, + const uno::Reference< XDiagram >& xDiagram + ) +{ + sal_Int32 nFormat=0; + if( !xSeriesOrPointProp.is() ) + return nFormat; + + rtl::OUString aPropName( C2U( "NumberFormat" ) ); + if( !(xSeriesOrPointProp->getPropertyValue(aPropName) >>= nFormat) ) + { + uno::Reference< chart2::XChartType > xChartType( DataSeriesHelper::getChartTypeOfSeries( xSeries, xDiagram ) ); + + bool bFormatFound = false; + if( ChartTypeHelper::shouldLabelNumberFormatKeyBeDetectedFromYAxis( xChartType ) ) + { + uno::Reference< beans::XPropertySet > xAttachedAxisProps( DiagramHelper::getAttachedAxis( xSeries, xDiagram ), uno::UNO_QUERY ); + if( xAttachedAxisProps.is() && ( xAttachedAxisProps->getPropertyValue( aPropName ) >>= nFormat ) ) + bFormatFound = true; + } + if( !bFormatFound ) + { + Reference< chart2::data::XDataSource > xSeriesSource( xSeries, uno::UNO_QUERY ); + OUString aRole( ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( xChartType ) ); + + Reference< data::XLabeledDataSequence > xLabeledSequence( + DataSeriesHelper::getDataSequenceByRole( xSeriesSource, aRole, false )); + if( xLabeledSequence.is() ) + { + Reference< data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + nFormat = xValues->getNumberFormatKeyByIndex( nPointIndex ); + } + } + } + if(nFormat<0) + nFormat=0; + return nFormat; +} + +sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, + const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + sal_Int32 nFormat=0; + if( !xSeriesOrPointProp.is() ) + return nFormat; + if( !(xSeriesOrPointProp->getPropertyValue(C2U( "PercentageNumberFormat" )) >>= nFormat) ) + { + nFormat = ExplicitValueProvider::getPercentNumberFormat( xNumberFormatsSupplier ); + } + if(nFormat<0) + nFormat=0; + return nFormat; +} + +//static +awt::Rectangle ExplicitValueProvider::calculateDiagramPositionAndSizeInclusiveTitle( + const Reference< frame::XModel >& xChartModel + , const Reference< uno::XInterface >& xChartView + , const awt::Rectangle& rExclusivePositionAndSize ) +{ + awt::Rectangle aRet(rExclusivePositionAndSize); + + //add axis title sizes to the diagram size + uno::Reference< chart2::XTitle > xTitle_Height( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xTitle_Width( TitleHelper::getTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Height( TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xChartModel ) ); + uno::Reference< chart2::XTitle > xSecondTitle_Width( TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xChartModel ) ); + if( xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() || xSecondTitle_Width.is() ) + { + ExplicitValueProvider* pExplicitValueProvider = ExplicitValueProvider::getExplicitValueProvider(xChartView); + if( pExplicitValueProvider ) + { + //detect wether x axis points into x direction or not + if( lcl_getPropertySwapXAndYAxis( ChartModelHelper::findDiagram( xChartModel ) ) ) + { + std::swap( xTitle_Height, xTitle_Width ); + std::swap( xSecondTitle_Height, xSecondTitle_Width ); + } + + sal_Int32 nTitleSpaceWidth = 0; + sal_Int32 nTitleSpaceHeight = 0; + sal_Int32 nSecondTitleSpaceWidth = 0; + sal_Int32 nSecondTitleSpaceHeight = 0; + + if( xTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Height, xChartModel ) ); + nTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nTitleSpaceHeight ) + nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle_Width, xChartModel ) ); + nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if(nTitleSpaceWidth) + nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Height.is() ) + { + rtl::OUString aCID_X( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Height, xChartModel ) ); + nSecondTitleSpaceHeight = pExplicitValueProvider->getRectangleOfObject( aCID_X, true ).Height; + if( nSecondTitleSpaceHeight ) + nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( xSecondTitle_Width.is() ) + { + rtl::OUString aCID_Y( ObjectIdentifier::createClassifiedIdentifierForObject( xSecondTitle_Width, xChartModel ) ); + nSecondTitleSpaceWidth += pExplicitValueProvider->getRectangleOfObject( aCID_Y, true ).Width; + if( nSecondTitleSpaceWidth ) + nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + + aRet.X -= nTitleSpaceWidth; + aRet.Y -= nSecondTitleSpaceHeight; + aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth; + aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight; + } + } + return aRet; +} + +double lcl_getPageLayoutDistancePercentage() +{ + return 0.02; +} + +bool getAvailablePosAndSizeForDiagram( + awt::Point& rOutPos, awt::Size& rOutAvailableDiagramSize + , const awt::Rectangle& rSpaceLeft + , const awt::Size & rPageSize + , const uno::Reference< XDiagram > & xDiagram + , VTitle* pXTitle, VTitle* pYTitle + , VTitle* pSecondXTitle, VTitle* pSecondYTitle ) +{ + //@todo: we need a size dependent on the axis labels + awt::Rectangle aRemainingSpace(rSpaceLeft); + { + sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); + sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); + aRemainingSpace.X+=nXDistance; + aRemainingSpace.Width-=2*nXDistance; + aRemainingSpace.Y+=nYDistance; + aRemainingSpace.Height-=2*nYDistance; + } + if(aRemainingSpace.Width <= 0 || aRemainingSpace.Height <= 0 ) + return false; + + uno::Reference< beans::XPropertySet > xProp(xDiagram, uno::UNO_QUERY); + + bool bMakeRoomForTitle = false; + + //size: + ::com::sun::star::chart2::RelativeSize aRelativeSize; + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativeSize" ) )>>=aRelativeSize) ) + { + rOutAvailableDiagramSize.Height = static_cast<sal_Int32>(aRelativeSize.Secondary*rPageSize.Height); + rOutAvailableDiagramSize.Width = static_cast<sal_Int32>(aRelativeSize.Primary*rPageSize.Width); + bMakeRoomForTitle = true; + } + else + rOutAvailableDiagramSize = awt::Size(aRemainingSpace.Width,aRemainingSpace.Height); + + //position: + chart2::RelativePosition aRelativePosition; + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativePosition" ) )>>=aRelativePosition) ) + { + //@todo decide wether x is primary or secondary + + //the coordinates re relative to the page + double fX = aRelativePosition.Primary*rPageSize.Width; + double fY = aRelativePosition.Secondary*rPageSize.Height; + + rOutPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)) + , rOutAvailableDiagramSize, aRelativePosition.Anchor ); + bMakeRoomForTitle = true; + } + else + rOutPos = awt::Point(aRemainingSpace.X,aRemainingSpace.Y); + + //ensure that the diagram does not lap out right side or out of bottom + { + if( rOutPos.Y + rOutAvailableDiagramSize.Height > rPageSize.Height ) + rOutAvailableDiagramSize.Height = rPageSize.Height - rOutPos.Y; + if( rOutPos.X + rOutAvailableDiagramSize.Width > rPageSize.Width ) + rOutAvailableDiagramSize.Width = rPageSize.Width - rOutPos.X; + } + + if( bMakeRoomForTitle ) + { + sal_Int32 nTitleSpaceWidth = 0; + sal_Int32 nTitleSpaceHeight = 0; + sal_Int32 nSecondTitleSpaceWidth = 0; + sal_Int32 nSecondTitleSpaceHeight = 0; + { + //todo detect wether x axis points into x direction or not + //detect wether x axis points into x direction or not + if( lcl_getPropertySwapXAndYAxis( xDiagram ) ) + { + std::swap( pXTitle, pYTitle ); + std::swap( pSecondXTitle, pSecondYTitle ); + } + + if( pXTitle ) + { + nTitleSpaceHeight = pXTitle->getFinalSize().Height; + if(nTitleSpaceHeight) + nTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( pYTitle ) + { + nTitleSpaceWidth = pYTitle->getFinalSize().Width; + if(nTitleSpaceWidth) + nTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + if( pSecondXTitle) + { + nSecondTitleSpaceHeight += pSecondXTitle->getFinalSize().Height; + if(nSecondTitleSpaceHeight) + nSecondTitleSpaceHeight+=lcl_getDiagramTitleSpace(); + } + if( pSecondYTitle) + { + nSecondTitleSpaceWidth += pSecondYTitle->getFinalSize().Width; + if(nSecondTitleSpaceWidth) + nSecondTitleSpaceWidth+=lcl_getDiagramTitleSpace(); + } + } + rOutAvailableDiagramSize.Height -= nTitleSpaceHeight + nSecondTitleSpaceHeight; + rOutAvailableDiagramSize.Width -= nTitleSpaceWidth + nSecondTitleSpaceWidth; + rOutPos.X += nTitleSpaceWidth; + rOutPos.Y += nSecondTitleSpaceHeight; + } + + return true; +} + +enum TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; + +void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment + , awt::Rectangle& rDiagramPlusAxesRect, const awt::Size & rPageSize ) +{ + if(!pVTitle) + return; + + awt::Point aNewPosition(0,0); + awt::Size aTitleSize = pVTitle->getFinalSize(); + sal_Int32 nYDistance = static_cast<sal_Int32>(rPageSize.Height*lcl_getPageLayoutDistancePercentage()); + sal_Int32 nXDistance = static_cast<sal_Int32>(rPageSize.Width*lcl_getPageLayoutDistancePercentage()); + switch( eAlignment ) + { + case ALIGN_TOP: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); + break; + case ALIGN_BOTTOM: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); + break; + case ALIGN_LEFT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case ALIGN_RIGHT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case ALIGN_Z: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); + break; + default: + break; + } + + pVTitle->changePosition( aNewPosition ); +} + +std::auto_ptr<VTitle> lcl_createTitle( TitleHelper::eTitleType eType + , const uno::Reference< drawing::XShapes>& xPageShapes + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + , const uno::Reference< frame::XModel >& xChartModel + , awt::Rectangle& rRemainingSpace + , const awt::Size & rPageSize + , TitleAlignment eAlignment + , bool& rbAutoPosition ) +{ + std::auto_ptr<VTitle> apVTitle; + + // #i109336# Improve auto positioning in chart + double fPercentage = lcl_getPageLayoutDistancePercentage(); + sal_Int32 nXDistance = static_cast< sal_Int32 >( rPageSize.Width * fPercentage ); + sal_Int32 nYDistance = static_cast< sal_Int32 >( rPageSize.Height * fPercentage ); + if ( eType == TitleHelper::MAIN_TITLE ) + { + sal_Int32 nYOffset = 135; // 1/100 mm + nYDistance += nYOffset; + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ) + { + sal_Int32 nYOffset = 420; // 1/100 mm + nYDistance = nYOffset; + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) + { + sal_Int32 nXOffset = 450; // 1/100 mm + nXDistance = nXOffset; + } + + uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, xChartModel ) ); + if(xTitle.is()) + { + rtl::OUString aCompleteString( TitleHelper::getCompleteString( xTitle ) ); + if ( aCompleteString.getLength() == 0 ) + return apVTitle;//don't create empty titles as the resulting diagram position is wrong then + + //create title + apVTitle = std::auto_ptr<VTitle>(new VTitle(xTitle)); + rtl::OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel ) ); + apVTitle->init(xPageShapes,xShapeFactory,aCID); + apVTitle->createShapes( awt::Point(0,0), rPageSize ); + awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); + awt::Size aTitleSize = apVTitle->getFinalSize(); + + //position + rbAutoPosition=true; + awt::Point aNewPosition(0,0); + chart2::RelativePosition aRelativePosition; + uno::Reference< beans::XPropertySet > xProp(xTitle, uno::UNO_QUERY); + if( xProp.is() && (xProp->getPropertyValue( C2U( "RelativePosition" ) )>>=aRelativePosition) ) + { + rbAutoPosition = false; + + //@todo decide wether x is primary or secondary + double fX = aRelativePosition.Primary*rPageSize.Width; + double fY = aRelativePosition.Secondary*rPageSize.Height; + + double fAnglePi = apVTitle->getRotationAnglePi(); + aNewPosition = RelativePositionHelper::getCenterOfAnchoredObject( + awt::Point(static_cast<sal_Int32>(fX),static_cast<sal_Int32>(fY)) + , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi ); + } + else //auto position + { + switch( eAlignment ) + { + case ALIGN_TOP: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); + break; + case ALIGN_BOTTOM: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); + break; + case ALIGN_LEFT: + aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + case ALIGN_RIGHT: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + default: + break; + + } + } + apVTitle->changePosition( aNewPosition ); + + //remaining space + switch( eAlignment ) + { + case ALIGN_TOP: + rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case ALIGN_BOTTOM: + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case ALIGN_LEFT: + rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + case ALIGN_RIGHT: + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + default: + break; + } + } + else + { + // #i109336# Improve auto positioning in chart + switch ( eAlignment ) + { + case ALIGN_TOP: + { + rRemainingSpace.Y += nYDistance; + rRemainingSpace.Height -= nYDistance; + } + break; + case ALIGN_BOTTOM: + { + rRemainingSpace.Height -= nYDistance; + } + break; + case ALIGN_LEFT: + { + rRemainingSpace.X += nXDistance; + rRemainingSpace.Width -= nXDistance; + } + break; + case ALIGN_RIGHT: + { + rRemainingSpace.Width -= nXDistance; + } + break; + default: + break; + } + } + return apVTitle; +} + +bool lcl_createLegend( const uno::Reference< XLegend > & xLegend + , const uno::Reference< drawing::XShapes>& xPageShapes + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + , const uno::Reference< uno::XComponentContext > & xContext + , awt::Rectangle & rRemainingSpace + , const awt::Size & rPageSize + , const uno::Reference< frame::XModel > & xModel + , const std::vector< LegendEntryProvider* >& rLegendEntryProviderList + , sal_Int16 nDefaultWritingMode ) +{ + if( VLegend::isVisible( xLegend )) + { + VLegend aVLegend( xLegend, xContext, rLegendEntryProviderList ); + aVLegend.init( xPageShapes, xShapeFactory, xModel ); + aVLegend.setDefaultWritingMode( nDefaultWritingMode ); + aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ), + rPageSize ); + aVLegend.changePosition( rRemainingSpace, rPageSize ); + return true; + } + return false; +} + +void formatPage( + const uno::Reference< frame::XModel > & xModel + , const awt::Size rPageSize + , const uno::Reference< drawing::XShapes >& xTarget + , const uno::Reference< lang::XMultiServiceFactory>& xShapeFactory + ) +{ + try + { + uno::Reference< XChartDocument > xChartDoc( xModel, uno::UNO_QUERY ); + OSL_ASSERT( xChartDoc.is()); + if( ! xChartDoc.is()) + return; + uno::Reference< beans::XPropertySet > xModelPage( xChartDoc->getPageBackground()); + if( ! xModelPage.is()) + return; + + + if( !xShapeFactory.is() ) + return; + + uno::Reference< beans::XPropertySet > xPageProp; + // create a shape for the background + { + uno::Reference< drawing::XShape > xShape( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xTarget.is() && + xShape.is()) + { + xTarget->add( xShape ); + xShape->setSize( rPageSize ); + xPageProp.set( xShape, uno::UNO_QUERY ); + if( xPageProp.is()) + { + xPageProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( drawing::LineStyle_NONE )); + } + } + } + + //format page + if( xPageProp.is()) + { + tPropertyNameValueMap aNameValueMap; + PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage ); + + rtl::OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, rtl::OUString() ) ); + aNameValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( aCID ) ) ); //CID rtl::OUString + + tNameSequence aNames; + tAnySequence aValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap ); + PropertyMapper::setMultiProperties( aNames, aValues, xPageProp ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +void lcl_removeEmptyGroupShapes( const Reference< drawing::XShapes>& xParent ) +{ + if(!xParent.is()) + return; + Reference< drawing::XShapeGroup > xParentGroup( xParent, uno::UNO_QUERY ); + if( !xParentGroup.is() ) + { + Reference< drawing::XDrawPage > xPage( xParent, uno::UNO_QUERY ); + if( !xPage.is() ) + return; + } + + //iterate from back! + for( sal_Int32 nN = xParent->getCount(); nN--; ) + { + uno::Any aAny = xParent->getByIndex( nN ); + Reference< drawing::XShapes> xShapes(0); + if( aAny >>= xShapes ) + lcl_removeEmptyGroupShapes( xShapes ); + if( xShapes.is() && xShapes->getCount()==0 ) + { + //remove empty group shape + Reference< drawing::XShapeGroup > xGroup( xShapes, uno::UNO_QUERY ); + Reference< drawing::XShape > xShape( xShapes, uno::UNO_QUERY ); + if( xGroup.is() ) + xParent->remove( xShape ); + } + } +} + +bool ChartView::impl_AddInDrawsAllByItself() +{ + bool bRet = false; + /* + uno::Reference< beans::XPropertySet > xProp( m_xChartModel, uno::UNO_QUERY ); + if( xProp.is()) try + { + uno::Reference< util::XRefreshable > xAddIn; + xProp->getPropertyValue( C2U( "AddIn" ) ) >>= xAddIn; + if( xAddIn.is() ) + { + rtl::OUString aBaseDiagram; + xProp->getPropertyValue( C2U( "BaseDiagram" ) ) >>= aBaseDiagram; + if(aBaseDiagram.getLength()) + bRet = true; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + */ + return bRet; +} + +void ChartView::impl_refreshAddIn() +{ + if( !m_bRefreshAddIn ) + return; + + uno::Reference< beans::XPropertySet > xProp( m_xChartModel, uno::UNO_QUERY ); + if( xProp.is()) try + { + uno::Reference< util::XRefreshable > xAddIn; + xProp->getPropertyValue( C2U( "AddIn" ) ) >>= xAddIn; + if( xAddIn.is() ) + { + sal_Bool bRefreshAddInAllowed = sal_True; + xProp->getPropertyValue( C2U( "RefreshAddInAllowed" ) ) >>= bRefreshAddInAllowed; + if( bRefreshAddInAllowed ) + xAddIn->refresh(); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void ChartView::createShapes() +{ +#if OSL_DEBUG_LEVEL > 0 + clock_t nStart = clock(); + OSL_TRACE( "\nPPPPPPPPP>>>>>>>>>>>> chart view :: createShapes()" ); +#endif + + //make sure add-in is refreshed after creating the shapes + const ::comphelper::ScopeGuard aGuard( boost::bind( &ChartView::impl_refreshAddIn, this ) ); + if( impl_AddInDrawsAllByItself() ) + return; + + impl_deleteCoordinateSystems(); + if( m_pDrawModelWrapper ) + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + // #i12587# support for shapes in chart + m_pDrawModelWrapper->getSdrModel().EnableUndo( FALSE ); + m_pDrawModelWrapper->clearMainDrawPage(); + // \-- + } + + lcl_setDefaultWritingMode( m_pDrawModelWrapper, m_xChartModel ); + + awt::Size aPageSize = ChartModelHelper::getPageSize( m_xChartModel ); + + uno::Reference<drawing::XShapes> xPageShapes( ShapeFactory(m_xShapeFactory) + .getOrCreateChartRootShape( m_xDrawPage ) ); + + SdrPage* pPage = ChartView::getSdrPage(); + if(pPage) //it is neccessary to use the implementation here as the uno page does not provide a propertyset + pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); + else + { + DBG_ERROR("could not set page size correctly"); + } + + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + + //------------ apply fill properties to page + // todo: it would be nicer to just pass the page m_xDrawPage and format it, + // but the draw page does not support XPropertySet + formatPage( m_xChartModel, aPageSize, xPageShapes, m_xShapeFactory ); + + //sal_Int32 nYDistance = static_cast<sal_Int32>(aPageSize.Height*lcl_getPageLayoutDistancePercentage()); + awt::Rectangle aRemainingSpace( 0, 0, aPageSize.Width, aPageSize.Height ); + + //create the group shape for diagram and axes first to have title and legends on top of it + uno::Reference< XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartModel ) ); + rtl::OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, rtl::OUString::valueOf( sal_Int32(0) ) ) );//todo: other index if more than one diagram is possible + uno::Reference< drawing::XShapes > xDiagramPlusAxesPlusMarkHandlesGroup_Shapes( ShapeFactory(m_xShapeFactory).createGroup2D(xPageShapes,aDiagramCID) ); + uno::Reference< drawing::XShape > xDiagramPlusAxes_MarkHandles( ShapeFactory(m_xShapeFactory).createInvisibleRectangle( + xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0) ) ); + ShapeFactory::setShapeName( xDiagramPlusAxes_MarkHandles, C2U("MarkHandles") ); + uno::Reference< drawing::XShapes > xDiagramPlusAxes_Shapes( ShapeFactory(m_xShapeFactory).createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes ) ); + + //------------ create some titles + std::auto_ptr<VTitle> apVTitle(0); + bool bAutoPositionDummy = true; + + //------------ create main title shape + lcl_createTitle( TitleHelper::MAIN_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_TOP, bAutoPositionDummy ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create sub title shape + lcl_createTitle( TitleHelper::SUB_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_TOP, bAutoPositionDummy ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + + //------------ prepare series to give input to the legend (create categories and symbols etc.) + SeriesPlotterContainer aSeriesPlotterContainer( m_aVCooSysList ); + aSeriesPlotterContainer.initializeCooSysAndSeriesPlotter( m_xChartModel ); + + //------------ create legend + lcl_createLegend( LegendHelper::getLegend( m_xChartModel ), xPageShapes, m_xShapeFactory, m_xCC + , aRemainingSpace, aPageSize, m_xChartModel, aSeriesPlotterContainer.getLegendEntryProviderList() + , lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); + + //------------ create x axis title + bool bAutoPosition_XTitle = true; + std::auto_ptr<VTitle> apVTitle_X; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) + apVTitle_X = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_BOTTOM, bAutoPosition_XTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create y axis title + bool bAutoPosition_YTitle = true; + std::auto_ptr<VTitle> apVTitle_Y; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) + apVTitle_Y = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_LEFT, bAutoPosition_YTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create z axis title + bool bAutoPosition_ZTitle = true; + std::auto_ptr<VTitle> apVTitle_Z; + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) + apVTitle_Z = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, ALIGN_RIGHT, bAutoPosition_ZTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + + //------------ create secondary x axis title + bool bAutoPosition_SecondXTitle = true; + std::auto_ptr<VTitle> apVTitle_SecondX; + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension, 0 ) ) + apVTitle_SecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, bIsVertical? ALIGN_RIGHT : ALIGN_TOP, bAutoPosition_SecondXTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create secondary y axis title + bool bAutoPosition_SecondYTitle = true; + std::auto_ptr<VTitle> apVTitle_SecondY; + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension, 1 ) ) + apVTitle_SecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xPageShapes, m_xShapeFactory, m_xChartModel + , aRemainingSpace, aPageSize, bIsVertical? ALIGN_TOP : ALIGN_RIGHT, bAutoPosition_SecondYTitle ); + if(aRemainingSpace.Width<=0||aRemainingSpace.Height<=0) + return; + + //------------ create complete diagram shape (inclusive axis and series) + awt::Point aAvailablePosDia; + awt::Size aAvailableSizeForDiagram; + if( getAvailablePosAndSizeForDiagram( aAvailablePosDia, aAvailableSizeForDiagram, aRemainingSpace, aPageSize, ChartModelHelper::findDiagram( m_xChartModel ) + , apVTitle_X.get(), apVTitle_Y.get(), apVTitle_SecondX.get(), apVTitle_SecondY.get() ) ) + { + impl_createDiagramAndContent( aSeriesPlotterContainer + , xDiagramPlusAxes_Shapes + , aAvailablePosDia ,aAvailableSizeForDiagram, aPageSize ); + + if(xDiagramPlusAxes_MarkHandles.is()) + { + xDiagramPlusAxes_MarkHandles->setPosition( aAvailablePosDia ); + xDiagramPlusAxes_MarkHandles->setSize( aAvailableSizeForDiagram ); + } + + //correct axis title position + awt::Rectangle aDiagramPlusAxesRect(aAvailablePosDia.X,aAvailablePosDia.Y,aAvailableSizeForDiagram.Width,aAvailableSizeForDiagram.Height); + if(bAutoPosition_XTitle) + changePositionOfAxisTitle( apVTitle_X.get(), ALIGN_BOTTOM, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_YTitle) + changePositionOfAxisTitle( apVTitle_Y.get(), ALIGN_LEFT, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_ZTitle) + changePositionOfAxisTitle( apVTitle_Z.get(), ALIGN_Z, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_SecondXTitle) + changePositionOfAxisTitle( apVTitle_SecondX.get(), bIsVertical? ALIGN_RIGHT : ALIGN_TOP, aDiagramPlusAxesRect, aPageSize ); + if(bAutoPosition_SecondYTitle) + changePositionOfAxisTitle( apVTitle_SecondY.get(), bIsVertical? ALIGN_TOP : ALIGN_RIGHT, aDiagramPlusAxesRect, aPageSize ); + } + + //cleanup: remove all empty group shapes to avoid grey border lines: + lcl_removeEmptyGroupShapes( xPageShapes ); + } + + // #i12587# support for shapes in chart + if ( m_pDrawModelWrapper ) + { + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + m_pDrawModelWrapper->getSdrModel().EnableUndo( TRUE ); + } + +#if OSL_DEBUG_LEVEL > 0 + clock_t nEnd = clock(); + double fDuration =(double(nEnd-nStart)*1000.0)/double(CLOCKS_PER_SEC); + + OSL_TRACE( "\nPPPPPPPPP<<<<<<<<<<<< chart view :: createShapes():: needed %f msec", fDuration ); +#endif +} + +//----------------------------------------------------------------- +// util::XEventListener (base of XCloseListener) +//----------------------------------------------------------------- +void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) + throw(uno::RuntimeException) +{ + impl_setChartModel( 0 ); +} + +void ChartView::impl_updateView() +{ + if( !m_xChartModel.is() || !m_pDrawModelWrapper ) + return; + + // #i12587# support for shapes in chart + if ( m_bSdrViewIsInEditMode ) + { + return; + } + + if( m_bViewDirty && !m_bInViewUpdate ) + { + m_bInViewUpdate = true; + //bool bOldRefreshAddIn = m_bRefreshAddIn; + //m_bRefreshAddIn = false; + try + { + impl_notifyModeChangeListener(C2U("invalid")); + + //prepare draw model + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper->lockControllers(); + // \-- + } + + //create chart view + { + /* + ::vos::OGuard aGuard( Application::GetSolarMutex()); + while( m_bViewDirty ) + { + createShapes(); + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + } + */ + + m_bViewDirty = false; + m_bViewUpdatePending = false; + createShapes(); + + if( m_bViewDirty ) + { + //avoid recursions due to add-in + m_bRefreshAddIn = false; + m_bViewDirty = false; + m_bViewUpdatePending = false; + //delete old chart view + createShapes(); + m_bRefreshAddIn = true; + } + } + + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + } + catch( uno::Exception& ex) + { + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + ASSERT_EXCEPTION( ex ); + } + + { + // /-- + ::vos::OGuard aSolarGuard( Application::GetSolarMutex()); + m_pDrawModelWrapper->unlockControllers(); + // \-- + } + + impl_notifyModeChangeListener(C2U("valid")); + + //m_bRefreshAddIn = bOldRefreshAddIn; + } +} + +// ____ XModifyListener ____ +void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ ) + throw (uno::RuntimeException) +{ + m_bViewDirty = sal_True; + if( m_bInViewUpdate ) + m_bViewUpdatePending = true; + + impl_notifyModeChangeListener(C2U("dirty")); +} + +//SfxListener +void ChartView::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + //#i77362 change notification for changes on additional shapes are missing + if( m_bInViewUpdate ) + return; + + // #i12587# support for shapes in chart + if ( m_bSdrViewIsInEditMode && m_xChartModel.is() ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupplier( m_xChartModel->getCurrentController(), uno::UNO_QUERY ); + if ( xSelectionSupplier.is() ) + { + ::rtl::OUString aSelObjCID; + uno::Any aSelObj( xSelectionSupplier->getSelection() ); + aSelObj >>= aSelObjCID; + if ( aSelObjCID.getLength() > 0 ) + { + return; + } + } + } + + const SdrHint* pSdrHint = dynamic_cast< const SdrHint* >(&rHint); + if( !pSdrHint ) + return; + + bool bShapeChanged = false; + switch( pSdrHint->GetKind() ) + { + case HINT_OBJCHG: + bShapeChanged = true; + break; + case HINT_OBJINSERTED: + bShapeChanged = true; + break; + case HINT_OBJREMOVED: + bShapeChanged = true; + break; + case HINT_MODELCLEARED: + bShapeChanged = true; + break; + case HINT_ENDEDIT: + bShapeChanged = true; + break; + default: + break; + } + + if(bShapeChanged) + { + //#i76053# do not send view modified notifications for changes on the hidden page which contains e.g. the symbols for the dialogs + if( ChartView::getSdrPage() != pSdrHint->GetPage() ) + bShapeChanged=false; + } + + if(!bShapeChanged) + return; + + Reference< util::XModifiable > xModifiable( m_xChartModel, uno::UNO_QUERY ); + if( xModifiable.is() ) + xModifiable->setModified( sal_True ); +} + +void ChartView::impl_notifyModeChangeListener( const rtl::OUString& rNewMode ) +{ + try + { + ::cppu::OInterfaceContainerHelper* pIC = m_aListenerContainer + .getContainer( ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0) ); + if( pIC ) + { + util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); + ::cppu::OInterfaceIteratorHelper aIt( *pIC ); + while( aIt.hasMoreElements() ) + (static_cast< util::XModeChangeListener*>(aIt.next()))->modeChanged( aEvent ); + } + } + catch( uno::Exception& ex) + { + ASSERT_EXCEPTION( ex ); + } +} + +// ____ XModeChangeBroadcaster ____ + +void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + m_aListenerContainer.addInterface( + ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0), xListener ); +} +void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) + throw (uno::RuntimeException) +{ + m_aListenerContainer.removeInterface( + ::getCppuType((const uno::Reference< util::XModeChangeListener >*)0), xListener ); +} +void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) + throw (lang::NoSupportException, uno::RuntimeException) +{ + +} +void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) + throw (lang::NoSupportException, uno::RuntimeException) +{ + +} + +// ____ XUpdatable ____ +void SAL_CALL ChartView::update() throw (uno::RuntimeException) +{ + impl_updateView(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo() + throw (uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); + return 0; +} + +void SAL_CALL ChartView::setPropertyValue( const ::rtl::OUString& rPropertyName + , const Any& rValue ) + throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException + , lang::WrappedTargetException, uno::RuntimeException) +{ + if( rPropertyName.equals(C2U("Resolution")) ) + { + awt::Size aNewResolution; + if( ! (rValue >>= aNewResolution) ) + throw lang::IllegalArgumentException( C2U("Property 'Resolution' requires value of type awt::Size"), 0, 0 ); + + if( m_aPageResolution.Width!=aNewResolution.Width || m_aPageResolution.Height!=aNewResolution.Height ) + { + //set modified only when the new resolution is higher and points were skipped before + bool bSetModified = m_bPointsWereSkipped && (m_aPageResolution.Width<aNewResolution.Width || m_aPageResolution.Height<aNewResolution.Height); + + m_aPageResolution = aNewResolution; + + if( bSetModified ) + this->modified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) ); + } + } + else if( rPropertyName.equals(C2U("ZoomFactors")) ) + { + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + uno::Sequence< beans::PropertyValue > aZoomFactors; + if( ! (rValue >>= aZoomFactors) ) + throw lang::IllegalArgumentException( C2U("Property 'ZoomFactors' requires value of type Sequence< PropertyValue >"), 0, 0 ); + + sal_Int32 nFilterArgs = aZoomFactors.getLength(); + beans::PropertyValue* pDataValues = aZoomFactors.getArray(); + while( nFilterArgs-- ) + { + if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXNumerator" ) ) ) + pDataValues->Value >>= m_nScaleXNumerator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleXDenominator" ) ) ) + pDataValues->Value >>= m_nScaleXDenominator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYNumerator" ) ) ) + pDataValues->Value >>= m_nScaleYNumerator; + else if( pDataValues->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ScaleYDenominator" ) ) ) + pDataValues->Value >>= m_nScaleYDenominator; + + pDataValues++; + } + } + else if( rPropertyName.equals(C2U("SdrViewIsInEditMode")) ) + { + //#i77362 change notification for changes on additional shapes are missing + if( ! (rValue >>= m_bSdrViewIsInEditMode) ) + throw lang::IllegalArgumentException( C2U("Property 'SdrViewIsInEditMode' requires value of type sal_Bool"), 0, 0 ); + } + else + throw beans::UnknownPropertyException( C2U("unknown property was tried to set to chart wizard"), 0 ); +} + +Any SAL_CALL ChartView::getPropertyValue( const ::rtl::OUString& rPropertyName ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + Any aRet; + if( rPropertyName.equals(C2U("Resolution")) ) + { + aRet = uno::makeAny( m_aPageResolution ); + } + else + throw beans::UnknownPropertyException( C2U("unknown property was tried to get from chart wizard"), 0 ); + return aRet; +} + +void SAL_CALL ChartView::addPropertyChangeListener( + const ::rtl::OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} +void SAL_CALL ChartView::removePropertyChangeListener( + const ::rtl::OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +void SAL_CALL ChartView::addVetoableChangeListener( const ::rtl::OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +void SAL_CALL ChartView::removeVetoableChangeListener( const ::rtl::OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) + throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OSL_ENSURE(false,"not implemented"); +} + +// ____ XMultiServiceFactory ____ + +Reference< uno::XInterface > ChartView::createInstance( const ::rtl::OUString& aServiceSpecifier ) + throw (uno::Exception, uno::RuntimeException) +{ + SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : NULL ); + if ( pModel ) + { + if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.DashTable" ) ) == 0 ) + { + if ( !m_xDashTable.is() ) + { + m_xDashTable = SvxUnoDashTable_createInstance( pModel ); + } + return m_xDashTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.GradientTable" ) ) == 0 ) + { + if ( !m_xGradientTable.is() ) + { + m_xGradientTable = SvxUnoGradientTable_createInstance( pModel ); + } + return m_xGradientTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.HatchTable" ) ) == 0 ) + { + if ( !m_xHatchTable.is() ) + { + m_xHatchTable = SvxUnoHatchTable_createInstance( pModel ); + } + return m_xHatchTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.BitmapTable" ) ) == 0 ) + { + if ( !m_xBitmapTable.is() ) + { + m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel ); + } + return m_xBitmapTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.TransparencyGradientTable" ) ) == 0 ) + { + if ( !m_xTransGradientTable.is() ) + { + m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel ); + } + return m_xTransGradientTable; + } + else if ( aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.MarkerTable" ) ) == 0 ) + { + if ( !m_xMarkerTable.is() ) + { + m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel ); + } + return m_xMarkerTable; + } + } + + return 0; +} + +Reference< uno::XInterface > ChartView::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments ) + throw (uno::Exception, uno::RuntimeException) +{ + OSL_ENSURE( Arguments.getLength(), "ChartView::createInstanceWithArguments: arguments are ignored" ); + (void) Arguments; // avoid warning + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< ::rtl::OUString > ChartView::getAvailableServiceNames() throw (uno::RuntimeException) +{ + uno::Sequence< ::rtl::OUString > aServiceNames( 6 ); + + aServiceNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.DashTable" ) ); + aServiceNames[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.GradientTable" ) ); + aServiceNames[2] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.HatchTable" ) ); + aServiceNames[3] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.BitmapTable" ) ); + aServiceNames[4] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.TransparencyGradientTable" ) ); + aServiceNames[5] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.MarkerTable" ) ); + + return aServiceNames; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/ChartView.hxx b/chart2/source/view/main/ChartView.hxx new file mode 100644 index 000000000000..f56da298c5df --- /dev/null +++ b/chart2/source/view/main/ChartView.hxx @@ -0,0 +1,255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CHARTVIEWIMPL_HXX +#define _CHARTVIEWIMPL_HXX + +#include "chartview/ExplicitValueProvider.hxx" +#include "ServiceMacros.hxx" +#include <cppuhelper/implbase9.hxx> +#include <cppuhelper/interfacecontainer.hxx> + +// header for class SfxListener +#include <svl/lstner.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/util/XModeChangeBroadcaster.hpp> +#include <com/sun/star/util/XUpdatable.hpp> + +#include <vector> +#include <boost/shared_ptr.hpp> + +class SdrPage; + +//............................................................................. +namespace chart +{ +//............................................................................. + +class VCoordinateSystem; +class DrawModelWrapper; +class SeriesPlotterContainer; + +//----------------------------------------------------------------------------- +/** The ChartView is responsible to manage the generation of Drawing Objects +for visualization on a given OutputDevice. The ChartModel is responsible to notify changes to the view. +The view than changes to state dirty. The view can be updated with call 'update'. + +The View is not responsible to handle single user events (that is instead done by the ChartWindow). +*/ + +class ChartView : public ::cppu::WeakImplHelper9< + ::com::sun::star::lang::XInitialization + , ::com::sun::star::lang::XServiceInfo + , ::com::sun::star::datatransfer::XTransferable + ,::com::sun::star::lang::XUnoTunnel + //::com::sun::star::lang::XComponent ??? + //::com::sun::star::uno::XWeak // implemented by WeakImplHelper(optional interface) + //::com::sun::star::uno::XInterface // implemented by WeakImplHelper(optional interface) + //::com::sun::star::lang::XTypeProvider // implemented by WeakImplHelper + ,::com::sun::star::util::XModifyListener + ,::com::sun::star::util::XModeChangeBroadcaster + ,::com::sun::star::util::XUpdatable + ,::com::sun::star::beans::XPropertySet + ,::com::sun::star::lang::XMultiServiceFactory + > + , public ExplicitValueProvider + , private SfxListener +{ +public: + ChartView(::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > const & xContext); + virtual ~ChartView(); + + // ___lang::XServiceInfo___ + APPHELPER_XSERVICEINFO_DECL() + APPHELPER_SERVICE_FACTORY_HELPER(ChartView) + + // ___lang::XInitialization___ + virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + + // ___ExplicitValueProvider___ + virtual sal_Bool getExplicitValuesForAxis( + ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XAxis > xAxis + , ::com::sun::star::chart2::ExplicitScaleData& rExplicitScale + , ::com::sun::star::chart2::ExplicitIncrementData& rExplicitIncrement ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > + getShapeForCID( const rtl::OUString& rObjectCID ); + + virtual ::com::sun::star::awt::Rectangle getRectangleOfObject( const rtl::OUString& rObjectCID, bool bSnapRect=false ); + + ::boost::shared_ptr< DrawModelWrapper > getDrawModelWrapper(); + + // ___XTransferable___ + virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) + throw (::com::sun::star::datatransfer::UnsupportedFlavorException + , ::com::sun::star::io::IOException + , ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) + throw (::com::sun::star::uno::RuntimeException); + + //------------------------------------------------------------------------------------- + // ::com::sun::star::util::XEventListener (base of XCloseListener and XModifyListener) + //------------------------------------------------------------------------------------- + virtual void SAL_CALL + disposing( const ::com::sun::star::lang::EventObject& Source ) + throw (::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XModifyListener + //----------------------------------------------------------------- + virtual void SAL_CALL modified( + const ::com::sun::star::lang::EventObject& aEvent ) + throw (::com::sun::star::uno::RuntimeException); + + //SfxListener + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XModeChangeBroadcaster + //----------------------------------------------------------------- + + virtual void SAL_CALL addModeChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModeChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeListener >& _rxListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addModeChangeApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeApproveListener >& _rxListener ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModeChangeApproveListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModeChangeApproveListener >& _rxListener ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::util::XUpdatable + //----------------------------------------------------------------- + virtual void SAL_CALL update() throw (::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::beans::XPropertySet + //----------------------------------------------------------------- + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + //----------------------------------------------------------------- + // ::com::sun::star::lang::XMultiServiceFactory + //----------------------------------------------------------------- + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( + const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) + throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames() throw (::com::sun::star::uno::RuntimeException); + + // for ExplicitValueProvider + // ____ XUnoTunnel ___ + virtual ::sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< ::sal_Int8 >& aIdentifier ) + throw (::com::sun::star::uno::RuntimeException); + +private: //methods + ChartView(); + + void createShapes(); + void getMetaFile( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >& xOutStream + , bool bUseHighContrast ); + SdrPage* getSdrPage(); + + void impl_setChartModel( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& xChartModel ); + void impl_deleteCoordinateSystems(); + void impl_notifyModeChangeListener( const rtl::OUString& rNewMode ); + + void impl_refreshAddIn(); + bool impl_AddInDrawsAllByItself(); + + void impl_updateView(); + + void impl_createDiagramAndContent( SeriesPlotterContainer& rSeriesPlotterContainer + , const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes>& xDiagramPlusAxes_Shapes + , const ::com::sun::star::awt::Point& rAvailablePos + , const ::com::sun::star::awt::Size& rAvailableSize + , const ::com::sun::star::awt::Size& rPageSize ); + + +private: //member + ::osl::Mutex m_aMutex; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> + m_xCC; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > + m_xChartModel; + + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory> + m_xShapeFactory; + ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XDrawPage> + m_xDrawPage; + + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xDashTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xGradientTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xHatchTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xBitmapTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xTransGradientTable; + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > m_xMarkerTable; + + ::boost::shared_ptr< DrawModelWrapper > m_pDrawModelWrapper; + + std::vector< VCoordinateSystem* > m_aVCooSysList; + + ::cppu::OMultiTypeInterfaceContainerHelper + m_aListenerContainer; + + bool volatile m_bViewDirty; //states wether the view needs to be rebuild + bool volatile m_bInViewUpdate; + bool volatile m_bViewUpdatePending; + bool volatile m_bRefreshAddIn; + + //better performance for big data + ::com::sun::star::awt::Size m_aPageResolution; + bool m_bPointsWereSkipped; + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + sal_Int32 m_nScaleXNumerator; + sal_Int32 m_nScaleXDenominator; + sal_Int32 m_nScaleYNumerator; + sal_Int32 m_nScaleYDenominator; + + sal_Bool m_bSdrViewIsInEditMode; +}; + +//............................................................................. +} //namespace chart +//............................................................................. + +#endif diff --git a/chart2/source/view/main/Clipping.cxx b/chart2/source/view/main/Clipping.cxx new file mode 100644 index 000000000000..e61096e5a0ba --- /dev/null +++ b/chart2/source/view/main/Clipping.cxx @@ -0,0 +1,304 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "Clipping.hxx" +#include "CommonConverters.hxx" +#include "BaseGFXHelper.hxx" + +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using ::basegfx::B2DRectangle; +using ::basegfx::B2DTuple; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +namespace{ +/** @descr This is a supporting function for lcl_clip2d. It computes a new parametric + value for an entering (dTE) or leaving (dTL) intersection point with one + of the edges bounding the clipping area. + For explanation of the parameters please refer to : + + Liang-Biarsky parametric line-clipping algorithm as described in: + Computer Graphics: principles and practice, 2nd ed., + James D. Foley et al., + Section 3.12.4 on page 117. +*/ +bool lcl_CLIPt(double fDenom,double fNum, double & fTE, double & fTL) +{ + double fT; + + if (fDenom > 0) // Intersection enters: PE + { + fT = fNum / fDenom; // Parametric value at the intersection. + if (fT > fTL) // fTE and fTL crossover + return false; // therefore reject the line. + else if (fT > fTE) // A new fTE has been found. + fTE = fT; + } + else if (fDenom < 0) // Intersection leaves: PL + { + fT = fNum / fDenom; // Parametric Value at the intersection. + if (fT < fTE) // fTE and fTL crossover + return false; // therefore reject the line. + else if (fT < fTL) // A new fTL has been found. + fTL = fT; + } + else if (fNum > 0) + return false; // Line lies on the outside of the edge. + + return true; +} + +/** @descr The line given by it's two endpoints rP0 and rP1 is clipped at the rectangle + rRectangle. If there is at least a part of it visible then TRUE is returned and + the endpoints of that part are stored in rP0 and rP1. The points rP0 and rP1 + may have the same coordinates. + @param rP0 Start point of the line to clip. Modified to contain a start point inside + the clipping area if possible. + @param rP1 End point of the line to clip. Modified to contain an end point inside + the clipping area if possible. + @param rRectangle Clipping area. + @return If the line lies completely or partly inside the clipping area then TRUE + is returned. If the line lies completely outside then FALSE is returned and rP0 and + rP1 are left unmodified. +*/ +bool lcl_clip2d(B2DTuple& rPoint0, B2DTuple& rPoint1, const B2DRectangle& rRectangle) +{ + //Direction vector of the line. + B2DTuple aDirection = rPoint1 - rPoint0; + + if( aDirection.getX()==0 && aDirection.getY()==0 && rRectangle.isInside(rPoint0) ) + { + // Degenerate case of a zero length line. + return true; + } + else + { + // Values of the line parameter where the line enters resp. leaves the rectangle. + double fTE = 0, + fTL = 1; + + // Test wether at least a part lies in the four half-planes with respect to + // the rectangles four edges. + if( lcl_CLIPt(aDirection.getX(), rRectangle.getMinX() - rPoint0.getX(), fTE, fTL) ) + if( lcl_CLIPt(-aDirection.getX(), rPoint0.getX() - rRectangle.getMaxX(), fTE, fTL) ) + if( lcl_CLIPt(aDirection.getY(), rRectangle.getMinY() - rPoint0.getY(), fTE, fTL) ) + if( lcl_CLIPt(-aDirection.getY(), rPoint0.getY() - rRectangle.getMaxY(), fTE, fTL) ) + { + // At least a part is visible. + if (fTL < 1) + { + // Compute the new end point. + rPoint1.setX( rPoint0.getX() + fTL * aDirection.getX() ); + rPoint1.setY( rPoint0.getY() + fTL * aDirection.getY() ); + } + if (fTE > 0) + { + // Compute the new starting point. + rPoint0.setX( rPoint0.getX() + fTE * aDirection.getX() ); + rPoint0.setY( rPoint0.getY() + fTE * aDirection.getY() ); + } + return true; + } + + // Line is not visible. + return false; + } +} + +bool lcl_clip2d_(drawing::Position3D& rPoint0, drawing::Position3D& rPoint1, const B2DRectangle& rRectangle) +{ + B2DTuple aP0(rPoint0.PositionX,rPoint0.PositionY); + B2DTuple aP1(rPoint1.PositionX,rPoint1.PositionY); + bool bRet = lcl_clip2d( aP0, aP1, rRectangle ); + + rPoint0.PositionX = aP0.getX(); + rPoint0.PositionY = aP0.getY(); + rPoint1.PositionX = aP1.getX(); + rPoint1.PositionY = aP1.getY(); + + return bRet; +} + +void lcl_addPointToPoly( drawing::PolyPolygonShape3D& rPoly + , const drawing::Position3D& rPos + , sal_Int32 nPolygonIndex + , std::vector< sal_Int32 >& rResultPointCount + , sal_Int32 nReservePointCount ) +{ + if(nPolygonIndex<0) + { + OSL_ENSURE( false, "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(nPolygonIndex >= rPoly.SequenceX.getLength() ) + { + rPoly.SequenceX.realloc(nPolygonIndex+1); + rPoly.SequenceY.realloc(nPolygonIndex+1); + rPoly.SequenceZ.realloc(nPolygonIndex+1); + rResultPointCount.resize(nPolygonIndex+1,0); + } + + drawing::DoubleSequence* pOuterSequenceX = &rPoly.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &rPoly.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &rPoly.SequenceZ.getArray()[nPolygonIndex]; + + sal_Int32 nNewResultPointCount = rResultPointCount[nPolygonIndex]+1; + sal_Int32 nSeqLength = pOuterSequenceX->getLength(); + + if( nSeqLength <= nNewResultPointCount ) + { + sal_Int32 nReallocLength = nReservePointCount; + if( nNewResultPointCount > nReallocLength ) + { + nReallocLength = nNewResultPointCount; + DBG_ERROR("this should not be the case to avoid performance problems"); + } + pOuterSequenceX->realloc(nReallocLength); + pOuterSequenceY->realloc(nReallocLength); + pOuterSequenceZ->realloc(nReallocLength); + } + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + pInnerSequenceX[nNewResultPointCount-1] = rPos.PositionX; + pInnerSequenceY[nNewResultPointCount-1] = rPos.PositionY; + pInnerSequenceZ[nNewResultPointCount-1] = rPos.PositionZ; + rResultPointCount[nPolygonIndex]=nNewResultPointCount; +} + +}//end anonymous namespace + +void Clipping::clipPolygonAtRectangle( const drawing::PolyPolygonShape3D& rPolygon + , const B2DRectangle& rRectangle + , drawing::PolyPolygonShape3D& aResult + , bool bSplitPiecesToDifferentPolygons ) +{ + aResult.SequenceX.realloc(0); + aResult.SequenceY.realloc(0); + aResult.SequenceZ.realloc(0); + + if(!rPolygon.SequenceX.getLength()) + return; + + //need clipping?: + { + ::basegfx::B3DRange a3DRange( BaseGFXHelper::getBoundVolume( rPolygon ) ); + ::basegfx::B2DRange a2DRange( a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY() ); + if( rRectangle.isInside( a2DRange ) ) + { + aResult = rPolygon; + return; + } + else + { + a2DRange.intersect( rRectangle ); + if( a2DRange.isEmpty() ) + return; + } + } + + // + std::vector< sal_Int32 > aResultPointCount;//per polygon index + + //apply clipping: + drawing::Position3D aFrom; + drawing::Position3D aTo; + + sal_Int32 nNewPolyIndex = 0; + sal_Int32 nOldPolyCount = rPolygon.SequenceX.getLength(); + for(sal_Int32 nOldPolyIndex=0; nOldPolyIndex<nOldPolyCount; nOldPolyIndex++, nNewPolyIndex++ ) + { + sal_Int32 nOldPointCount = rPolygon.SequenceX[nOldPolyIndex].getLength(); + + // set last point to a position outside the rectangle, such that the first + // time lcl_clip2d returns true, the comparison to last will always yield false + drawing::Position3D aLast(rRectangle.getMinX()-1.0,rRectangle.getMinY()-1.0, 0.0 ); + + for(sal_Int32 nOldPoint=1; nOldPoint<nOldPointCount; nOldPoint++) + { + aFrom = getPointFromPoly(rPolygon,nOldPoint-1,nOldPolyIndex); + aTo = getPointFromPoly(rPolygon,nOldPoint,nOldPolyIndex); + if( lcl_clip2d_(aFrom, aTo, rRectangle) ) + { + // compose an Polygon of as many consecutive points as possible + if(aFrom == aLast) + { + if( !(aTo==aFrom) ) + { + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + } + else + { + if( bSplitPiecesToDifferentPolygons && nOldPoint!=1 ) + { + if( nNewPolyIndex < aResult.SequenceX.getLength() + && aResultPointCount[nNewPolyIndex]>0 ) + nNewPolyIndex++; + } + lcl_addPointToPoly( aResult, aFrom, nNewPolyIndex, aResultPointCount, nOldPointCount ); + if( !(aTo==aFrom) ) + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + aLast = aTo; + } + } + } + //free unused space + for( sal_Int32 nPolygonIndex = aResultPointCount.size(); nPolygonIndex--; ) + { + drawing::DoubleSequence* pOuterSequenceX = &aResult.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &aResult.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &aResult.SequenceZ.getArray()[nPolygonIndex]; + + sal_Int32 nUsedPointCount = aResultPointCount[nPolygonIndex]; + pOuterSequenceX->realloc(nUsedPointCount); + pOuterSequenceY->realloc(nUsedPointCount); + pOuterSequenceZ->realloc(nUsedPointCount); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/DataPointSymbolSupplier.cxx b/chart2/source/view/main/DataPointSymbolSupplier.cxx new file mode 100644 index 000000000000..d59a011cd429 --- /dev/null +++ b/chart2/source/view/main/DataPointSymbolSupplier.cxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "chartview/DataPointSymbolSupplier.hxx" +#include "ShapeFactory.hxx" +#include "macros.hxx" + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +//using namespace ::com::sun::star::chart2; + +uno::Reference< drawing::XShapes > DataPointSymbolSupplier::create2DSymbolList( + uno::Reference< lang::XMultiServiceFactory > xShapeFactory + , const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Direction3D& rSize ) +{ + uno::Reference< drawing::XShape > xGroup( + xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GroupShape" ) ), uno::UNO_QUERY ); + if(xTarget.is()) + xTarget->add(xGroup); + uno::Reference< drawing::XShapes > xGroupShapes = + uno::Reference<drawing::XShapes>( xGroup, uno::UNO_QUERY ); + + ShapeFactory aShapeFactory(xShapeFactory); + drawing::Position3D aPos(0,0,0); + for(sal_Int32 nS=0;nS<ShapeFactory::getSymbolCount();nS++) + { + aShapeFactory.createSymbol2D( xGroupShapes, aPos, rSize, nS ); + } + return xGroupShapes; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/DrawModelWrapper.cxx b/chart2/source/view/main/DrawModelWrapper.cxx new file mode 100644 index 000000000000..577f450172b5 --- /dev/null +++ b/chart2/source/view/main/DrawModelWrapper.cxx @@ -0,0 +1,411 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "chartview/DrawModelWrapper.hxx" +#include "macros.hxx" +#include "ShapeFactory.hxx" +#include "ChartItemPool.hxx" +#include "ObjectIdentifier.hxx" +#include <svx/unomodel.hxx> +#include <svl/itempool.hxx> +// header for class SfxBoolItem +#include <svl/eitem.hxx> +// header for define EE_PARA_HYPHENATE +#include <editeng/eeitem.hxx> +// header for class Svx3DPercentDiagonalItem +#include <svx/svx3ditems.hxx> +// header for class SvtPathOptions +#include <unotools/pathoptions.hxx> +// header E3dObjFactory +#include <svx/objfac3d.hxx> +// header for class SdrObjList +#include <svx/svdpage.hxx> +// header for SvxUnoXDashTable_createInstance +#include <svx/XPropertyTable.hxx> +// header for class XDashList +#include <svx/xtable.hxx> +// header for class SdrOutliner +#include <svx/svdoutl.hxx> +// header for class LinguMgr +#include <editeng/unolingu.hxx> +// header for class Application +#include <vcl/svapp.hxx> +// header for class VirtualDevice +#include <vcl/virdev.hxx> + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> + +#include <sfx2/objsh.hxx> +#include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> + +using namespace ::com::sun::star; + +//............................................................................. +namespace +{ +// this code is copied from sfx2/source/doc/objembed.cxx +SfxObjectShell * lcl_GetParentObjectShell( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell* pResult = NULL; + + try + { + uno::Reference< container::XChild > xChildModel( xModel, uno::UNO_QUERY ); + if ( xChildModel.is() ) + { + uno::Reference< lang::XUnoTunnel > xParentTunnel( xChildModel->getParent(), uno::UNO_QUERY ); + if ( xParentTunnel.is() ) + { + SvGlobalName aSfxIdent( SFX_GLOBAL_CLASSID ); + pResult = reinterpret_cast< SfxObjectShell * >( + xParentTunnel->getSomething( uno::Sequence< sal_Int8 >( aSfxIdent.GetByteSequence() ) ) ); + } + } + } + catch( uno::Exception& ) + { + // TODO: error handling + } + + return pResult; +} + +// this code is copied from sfx2/source/doc/objembed.cxx. It is a workaround to +// get the reference device (e.g. printer) fromthe parent document +OutputDevice * lcl_GetParentRefDevice( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell * pParent = lcl_GetParentObjectShell( xModel ); + if ( pParent ) + return pParent->GetDocumentRefDev(); + return NULL; +} + +} // anonymous namespace + +//.. ........................................................................... +namespace chart +{ +//............................................................................. + +DrawModelWrapper::DrawModelWrapper( + uno::Reference<uno::XComponentContext> const & xContext ) + : SdrModel( SvtPathOptions().GetPalettePath() ) + , m_xMCF(0) + , m_pChartItemPool(0) + , m_xMainDrawPage(0) + , m_xHiddenDrawPage(0) + , m_apRefDevice(0) +{ + m_pChartItemPool = ChartItemPool::CreateChartItemPool(); + + m_xMCF = xContext->getServiceManager(); + + SetScaleUnit(MAP_100TH_MM); + SetScaleFraction(Fraction(1, 1)); + SetDefaultFontHeight(423); // 12pt + + SfxItemPool* pMasterPool = &GetItemPool(); + pMasterPool->SetDefaultMetric(SFX_MAPUNIT_100TH_MM); + pMasterPool->SetPoolDefaultItem(SfxBoolItem(EE_PARA_HYPHENATE, TRUE) ); + pMasterPool->SetPoolDefaultItem(Svx3DPercentDiagonalItem (5)); + + SfxItemPool* pPool = pMasterPool; + // append chart pool to end of pool chain + for (;;) + { + SfxItemPool* pSecondary = pPool->GetSecondaryPool(); + if (!pSecondary) + break; + + pPool = pSecondary; + } + pPool->SetSecondaryPool(m_pChartItemPool); + pMasterPool->FreezeIdRanges(); + + //this factory needs to be created before first use of 3D scenes once upon an office runtime + //@todo in future this should be done by drawing engine itself on demand + static bool b3dFactoryInitialized = false; + if(!b3dFactoryInitialized) + { + E3dObjFactory aObjFactory; + b3dFactoryInitialized = true; + } + + //Hyphenyation and spellchecking + SdrOutliner& rOutliner = GetDrawOutliner(); + try + { + uno::Reference< linguistic2::XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); + if( xHyphenator.is() ) + rOutliner.SetHyphenator( xHyphenator ); + + uno::Reference< linguistic2::XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); + if ( xSpellChecker.is() ) + rOutliner.SetSpeller( xSpellChecker ); + } + catch(...) + { + DBG_ERROR("Can't get Hyphenator or SpellChecker for chart"); + } + + //ref device for font rendering + OutputDevice* pDefaultDevice = rOutliner.GetRefDevice(); + if( !pDefaultDevice ) + pDefaultDevice = Application::GetDefaultDevice(); + m_apRefDevice = std::auto_ptr< OutputDevice >( new VirtualDevice( *pDefaultDevice ) ); + MapMode aMapMode = m_apRefDevice->GetMapMode(); + aMapMode.SetMapUnit(MAP_100TH_MM); + m_apRefDevice->SetMapMode(aMapMode); + SetRefDevice(m_apRefDevice.get()); + rOutliner.SetRefDevice(m_apRefDevice.get()); +} + +DrawModelWrapper::~DrawModelWrapper() +{ + //remove m_pChartItemPool from pool chain + if(m_pChartItemPool) + { + SfxItemPool* pPool = &GetItemPool(); + for (;;) + { + SfxItemPool* pSecondary = pPool->GetSecondaryPool(); + if(pSecondary == m_pChartItemPool) + { + pPool->SetSecondaryPool (NULL); + break; + } + pPool = pSecondary; + } + SfxItemPool::Free(m_pChartItemPool); + } +} + +uno::Reference< uno::XInterface > DrawModelWrapper +::createUnoModel() +{ + uno::Reference< lang::XComponent > xComponent = new SvxUnoDrawingModel( this ); //tell Andreas Schluens if SvxUnoDrawingModel is not needed anymore -> remove export from svx to avoid link problems in writer + return uno::Reference< uno::XInterface >::query( xComponent ); +} + +uno::Reference< frame::XModel > DrawModelWrapper::getUnoModel() +{ + uno::Reference< uno::XInterface > xI = this->SdrModel::getUnoModel(); + return uno::Reference<frame::XModel>::query( xI ); +} + +SdrModel& DrawModelWrapper::getSdrModel() +{ + return *this; +} + +uno::Reference< lang::XMultiServiceFactory > DrawModelWrapper::getShapeFactory() +{ + uno::Reference< lang::XMultiServiceFactory > xShapeFactory( this->getUnoModel(), uno::UNO_QUERY ); + return xShapeFactory; +} + +uno::Reference< drawing::XDrawPage > DrawModelWrapper::getMainDrawPage() +{ + //create draw page: + if( !m_xMainDrawPage.is() ) + { + uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSuplier( this->getUnoModel(), uno::UNO_QUERY ); + if( xDrawPagesSuplier.is() ) + { + uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSuplier->getDrawPages () ); + if( xDrawPages->getCount()>1 ) + { + uno::Any aPage = xDrawPages->getByIndex( 0 ) ; + aPage >>= m_xMainDrawPage; + } + if(!m_xMainDrawPage.is()) + { + m_xMainDrawPage = xDrawPages->insertNewByIndex( 0 ); + } + } + } + //ensure that additional shapes are in front of the chart objects so create the chart root before + ShapeFactory(this->getShapeFactory()).getOrCreateChartRootShape( m_xMainDrawPage ); + return m_xMainDrawPage; +} +uno::Reference< drawing::XDrawPage > DrawModelWrapper::getHiddenDrawPage() +{ + if( !m_xHiddenDrawPage.is() ) + { + uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSuplier( this->getUnoModel(), uno::UNO_QUERY ); + if( xDrawPagesSuplier.is() ) + { + uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSuplier->getDrawPages () ); + if( xDrawPages->getCount()>1 ) + { + uno::Any aPage = xDrawPages->getByIndex( 1 ) ; + aPage >>= m_xHiddenDrawPage; + } + + if(!m_xHiddenDrawPage.is()) + { + if( xDrawPages->getCount()==0 ) + m_xMainDrawPage = xDrawPages->insertNewByIndex( 0 ); + m_xHiddenDrawPage = xDrawPages->insertNewByIndex( 1 ); + } + } + } + return m_xHiddenDrawPage; +} +void DrawModelWrapper::clearMainDrawPage() +{ + //uno::Reference<drawing::XShapes> xChartRoot( m_xMainDrawPage, uno::UNO_QUERY ); + uno::Reference<drawing::XShapes> xChartRoot( ShapeFactory::getChartRootShape( m_xMainDrawPage ) ); + if( xChartRoot.is() ) + { + sal_Int32 nSubCount = xChartRoot->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = nSubCount; nS--; ) + { + if( xChartRoot->getByIndex( nS ) >>= xShape ) + xChartRoot->remove( xShape ); + } + } +} + +uno::Reference< drawing::XShapes > DrawModelWrapper::getChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + return ShapeFactory::getChartRootShape( xDrawPage ); +} + +void DrawModelWrapper::lockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( this->getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->lockControllers(); +} +void DrawModelWrapper::unlockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( this->getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->unlockControllers(); +} + +void DrawModelWrapper::attachParentReferenceDevice( const uno::Reference< frame::XModel > & xChartModel ) +{ + OutputDevice * pParentRefDev( lcl_GetParentRefDevice( xChartModel )); + if( pParentRefDev ) + { + SetRefDevice( pParentRefDev ); + } +} + +OutputDevice* DrawModelWrapper::getReferenceDevice() const +{ + return SdrModel::GetRefDevice(); +} + +SfxItemPool& DrawModelWrapper::GetItemPool() +{ + return this->SdrModel::GetItemPool(); +} +const SfxItemPool& DrawModelWrapper::GetItemPool() const +{ + return this->SdrModel::GetItemPool(); +} +XColorTable* DrawModelWrapper::GetColorTable() const +{ + return this->SdrModel::GetColorTable(); +} +XDashList* DrawModelWrapper::GetDashList() const +{ + return this->SdrModel::GetDashList(); +} +XLineEndList* DrawModelWrapper::GetLineEndList() const +{ + return this->SdrModel::GetLineEndList(); +} +XGradientList* DrawModelWrapper::GetGradientList() const +{ + return this->SdrModel::GetGradientList(); +} +XHatchList* DrawModelWrapper::GetHatchList() const +{ + return this->SdrModel::GetHatchList(); +} +XBitmapList* DrawModelWrapper::GetBitmapList() const +{ + return this->SdrModel::GetBitmapList(); +} + +SdrObject* DrawModelWrapper::getNamedSdrObject( const rtl::OUString& rName ) +{ + if(rName.getLength()==0) + return 0; + return getNamedSdrObject( rName, GetPage(0) ); +} + +//static +SdrObject* DrawModelWrapper::getNamedSdrObject( const String& rObjectCID, SdrObjList* pSearchList ) +{ + if(!pSearchList || rObjectCID.Len()==0) + return 0; + ULONG nCount = pSearchList->GetObjCount(); + for( ULONG nN=0; nN<nCount; nN++ ) + { + SdrObject* pObj = pSearchList->GetObj(nN); + if(!pObj) + continue; + if( ObjectIdentifier::areIdenticalObjects( rObjectCID, pObj->GetName() ) ) + return pObj; + pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, pObj->GetSubList() ); + if(pObj) + return pObj; + } + return 0; +} + +//static +bool DrawModelWrapper::removeShape( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY ); + if( xChild.is() ) + { + uno::Reference<drawing::XShapes> xShapes( xChild->getParent(), uno::UNO_QUERY ); + if( xShapes.is() ) + { + xShapes->remove(xShape); + return true; + } + } + return false; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/LabelPositionHelper.cxx b/chart2/source/view/main/LabelPositionHelper.cxx new file mode 100644 index 000000000000..24ec5a285468 --- /dev/null +++ b/chart2/source/view/main/LabelPositionHelper.cxx @@ -0,0 +1,488 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "LabelPositionHelper.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "macros.hxx" +#include "RelativeSizeHelper.hxx" +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LabelPositionHelper::LabelPositionHelper( + PlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const uno::Reference< drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ) + : m_pPosHelper(pPosHelper) + , m_nDimensionCount(nDimensionCount) + , m_xLogicTarget(xLogicTarget) + , m_pShapeFactory(pShapeFactory) +{ +} + +LabelPositionHelper::~LabelPositionHelper() +{ +} + +awt::Point LabelPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D ) const +{ + return PlottingPositionHelper::transformSceneToScreenPosition( + rScenePosition3D, m_xLogicTarget, m_pShapeFactory, m_nDimensionCount ); +} + +//static +void LabelPositionHelper::changeTextAdjustment( tAnySequence& rPropValues, const tNameSequence& rPropNames, LabelAlignment eAlignment) +{ + //HorizontalAdjustment + { + drawing::TextHorizontalAdjust eHorizontalAdjust = drawing::TextHorizontalAdjust_CENTER; + if( LABEL_ALIGN_RIGHT==eAlignment || LABEL_ALIGN_RIGHT_TOP==eAlignment || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_LEFT; + else if( LABEL_ALIGN_LEFT==eAlignment || LABEL_ALIGN_LEFT_TOP==eAlignment || LABEL_ALIGN_LEFT_BOTTOM==eAlignment ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_RIGHT; + uno::Any* pHorizontalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,C2U("TextHorizontalAdjust")); + if(pHorizontalAdjustAny) + *pHorizontalAdjustAny = uno::makeAny(eHorizontalAdjust); + } + + //VerticalAdjustment + { + drawing::TextVerticalAdjust eVerticalAdjust = drawing::TextVerticalAdjust_CENTER; + if( LABEL_ALIGN_TOP==eAlignment || LABEL_ALIGN_RIGHT_TOP==eAlignment || LABEL_ALIGN_LEFT_TOP==eAlignment ) + eVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM; + else if( LABEL_ALIGN_BOTTOM==eAlignment || LABEL_ALIGN_RIGHT_BOTTOM==eAlignment || LABEL_ALIGN_LEFT_BOTTOM==eAlignment ) + eVerticalAdjust = drawing::TextVerticalAdjust_TOP; + uno::Any* pVerticalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,C2U("TextVerticalAdjust")); + if(pVerticalAdjustAny) + *pVerticalAdjustAny = uno::makeAny(eVerticalAdjust); + } +} + +void lcl_doDynamicFontResize( uno::Any* pAOldAndNewFontHeightAny + , const awt::Size& rOldReferenceSize + , const awt::Size& rNewReferenceSize ) +{ + double fOldFontHeight = 0, fNewFontHeight; + if( pAOldAndNewFontHeightAny && ( *pAOldAndNewFontHeightAny >>= fOldFontHeight ) ) + { + fNewFontHeight = RelativeSizeHelper::calculate( fOldFontHeight, rOldReferenceSize, rNewReferenceSize ); + *pAOldAndNewFontHeightAny = uno::makeAny(fNewFontHeight); + } +} + +//static +void LabelPositionHelper::doDynamicFontResize( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , const uno::Reference< beans::XPropertySet >& xAxisModelProps + , const awt::Size& rNewReferenceSize + ) +{ + //------------------------- + //handle dynamic font resize: + awt::Size aOldReferenceSize; + if( xAxisModelProps->getPropertyValue( C2U("ReferencePageSize")) >>= aOldReferenceSize ) + { + uno::Any* pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeight") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeightAsian") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, C2U("CharHeightComplex") ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + } +} + +namespace +{ + +void lcl_correctRotation_Left( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on a left side of something with a right centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width *rtl::math::sin( beta ) + -aSize.Height *rtl::math::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *rtl::math::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - F_PI; + rfXCorrection = -aSize.Width *rtl::math::cos( beta ) + -aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *rtl::math::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *rtl::math::sin( beta ); + } + else + { + double beta = 2*F_PI - fAnglePi; + rfXCorrection = -aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*rtl::math::sin( beta )/2.0; + } +} + +void lcl_correctRotation_Right( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on a right side of something with a left centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = F_PI - fAnglePi; + rfXCorrection = aSize.Width *rtl::math::cos( beta ) + + aSize.Height*rtl::math::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *rtl::math::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Width *rtl::math::sin( beta ) + +aSize.Height*rtl::math::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *rtl::math::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *rtl::math::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( 2*F_PI - fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*rtl::math::sin( 2*F_PI - fAnglePi )/2.0; + } +} + +void lcl_correctRotation_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels on top of something with a bottom centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi - F_PI/2.0; + rfXCorrection = aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*rtl::math::sin( beta )/2.0; + rfYCorrection = -aSize.Width*rtl::math::cos( beta )/2.0 + - aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - F_PI; + rfXCorrection = -aSize.Height *rtl::math::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *rtl::math::cos( beta )/2.0; + rfYCorrection = -aSize.Width *rtl::math::sin( beta )/2.0 + -aSize.Height *rtl::math::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } +} + +void lcl_correctRotation_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize, bool bRotateAroundCenter ) +{ + //correct label positions for labels below something with a top centered alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *rtl::math::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *rtl::math::sin( beta )/2.0; + rfYCorrection = aSize.Width *rtl::math::cos( beta )/2.0 + +aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *rtl::math::sin( beta )/2.0; + rfYCorrection = aSize.Height*rtl::math::sin( beta ) + +aSize.Width*rtl::math::cos( beta )/2.0; + } + else + { + double beta = 2*F_PI - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*rtl::math::cos( beta )/2.0; + rfYCorrection = aSize.Width*rtl::math::sin( beta )/2.0; + } +} + +void lcl_correctRotation_Left_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the left top corner of something with a bottom right alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ) + -aSize.Width*rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = -aSize.Height*rtl::math::cos( beta ) + -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ); + } + else + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Left_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the left bottom corner of something with a top right alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ) + -aSize.Height*rtl::math::cos( beta );; + rfYCorrection = aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = -aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Width*rtl::math::cos( beta ) + +aSize.Height*rtl::math::sin( beta ); + } + else + { + rfYCorrection = -aSize.Width*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Right_Top( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the right top corner of something with a bottom left alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = aSize.Width*rtl::math::sin( beta ) + +aSize.Height*rtl::math::cos( beta ); + rfYCorrection = -aSize.Height*rtl::math::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Width*rtl::math::sin( beta ); + rfYCorrection = -aSize.Width*rtl::math::cos( beta ) + -aSize.Height*rtl::math::sin( beta ); + } + else + { + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi ); + } +} + +void lcl_correctRotation_Right_Bottom( double& rfXCorrection, double& rfYCorrection + , double fAnglePositiveDegree, const awt::Size& aSize ) +{ + //correct position for labels at the right bottom corner of something with a top left alignment + double fAnglePi = fAnglePositiveDegree*F_PI/180.0; + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = aSize.Width*rtl::math::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-F_PI/2.0; + rfXCorrection = aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Height*rtl::math::sin( beta ) + +aSize.Width*rtl::math::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*F_PI/2.0 - fAnglePi; + rfXCorrection = aSize.Height*rtl::math::cos( beta ) + +aSize.Width*rtl::math::sin( beta ); + rfYCorrection = aSize.Height*rtl::math::sin( beta ); + } + else + { + rfXCorrection = -aSize.Height*rtl::math::sin( fAnglePi ); + } +} + +}//end anonymous namespace + +//static +void LabelPositionHelper::correctPositionForRotation( const uno::Reference< drawing::XShape >& xShape2DText + , LabelAlignment eLabelAlignment, const double fRotationAngle, bool bRotateAroundCenter ) +{ + if( !xShape2DText.is() ) + return; + + awt::Point aOldPos = xShape2DText->getPosition(); + awt::Size aSize = xShape2DText->getSize(); + + double fYCorrection = 0.0; + double fXCorrection = 0.0; + + double fAnglePositiveDegree = fRotationAngle; + while(fAnglePositiveDegree<0.0) + fAnglePositiveDegree+=360.0; + + switch(eLabelAlignment) + { + case LABEL_ALIGN_LEFT: + lcl_correctRotation_Left( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_RIGHT: + lcl_correctRotation_Right( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_TOP: + lcl_correctRotation_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_BOTTOM: + lcl_correctRotation_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize, bRotateAroundCenter ); + break; + case LABEL_ALIGN_LEFT_TOP: + lcl_correctRotation_Left_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_LEFT_BOTTOM: + lcl_correctRotation_Left_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_RIGHT_TOP: + lcl_correctRotation_Right_Top( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + case LABEL_ALIGN_RIGHT_BOTTOM: + lcl_correctRotation_Right_Bottom( fXCorrection, fYCorrection, fAnglePositiveDegree, aSize ); + break; + default: //LABEL_ALIGN_CENTER + break; + } + + xShape2DText->setPosition( awt::Point( + static_cast<sal_Int32>(aOldPos.X + fXCorrection ) + , static_cast<sal_Int32>(aOldPos.Y + fYCorrection ) ) ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/Linear3DTransformation.cxx b/chart2/source/view/main/Linear3DTransformation.cxx new file mode 100644 index 000000000000..9292ee6eb757 --- /dev/null +++ b/chart2/source/view/main/Linear3DTransformation.cxx @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "Linear3DTransformation.hxx" +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::RuntimeException; + +namespace chart +{ + + Linear3DTransformation::Linear3DTransformation( const drawing::HomogenMatrix& rHomMatrix, bool bSwapXAndY ) + : m_Matrix(rHomMatrix) + , m_bSwapXAndY(bSwapXAndY) +{} + +Linear3DTransformation::~Linear3DTransformation() +{} + +// ____ XTransformation ____ +Sequence< double > SAL_CALL Linear3DTransformation::transform( + const Sequence< double >& rSourceValues ) + throw (RuntimeException, + lang::IllegalArgumentException) +{ + double fX = rSourceValues[0]; + double fY = rSourceValues[1]; + double fZ = rSourceValues[2]; + if(m_bSwapXAndY) + std::swap(fX,fY); + Sequence< double > aNewVec(3); + double fZwi; + + fZwi = m_Matrix.Line1.Column1 * fX + + m_Matrix.Line1.Column2 * fY + + m_Matrix.Line1.Column3 * fZ + + m_Matrix.Line1.Column4; + aNewVec[0] = fZwi; + + fZwi = m_Matrix.Line2.Column1 * fX + + m_Matrix.Line2.Column2 * fY + + m_Matrix.Line2.Column3 * fZ + + m_Matrix.Line2.Column4; + aNewVec[1] = fZwi; + + fZwi = m_Matrix.Line3.Column1 * fX + + m_Matrix.Line3.Column2 * fY + + m_Matrix.Line3.Column3 * fZ + + m_Matrix.Line3.Column4; + aNewVec[2] = fZwi; + + fZwi = m_Matrix.Line4.Column1 * fX + + m_Matrix.Line4.Column2 * fY + + m_Matrix.Line4.Column3 * fZ + + m_Matrix.Line4.Column4; + if(fZwi != 1.0 && fZwi != 0.0) + { + aNewVec[0] /= fZwi; + aNewVec[1] /= fZwi; + aNewVec[2] /= fZwi; + } + return aNewVec; +} + +sal_Int32 SAL_CALL Linear3DTransformation::getSourceDimension() + throw (RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL Linear3DTransformation::getTargetDimension() + throw (RuntimeException) +{ + return 3; +} + + +} // namespace chart diff --git a/chart2/source/view/main/NumberFormatterWrapper.cxx b/chart2/source/view/main/NumberFormatterWrapper.cxx new file mode 100644 index 000000000000..4e4cd342506c --- /dev/null +++ b/chart2/source/view/main/NumberFormatterWrapper.cxx @@ -0,0 +1,169 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "chartview/NumberFormatterWrapper.hxx" +#include "macros.hxx" +#include <comphelper/processfactory.hxx> +// header for class SvNumberFormatsSupplierObj +#include <svl/numuno.hxx> +// header for class SvNumberformat +#include <svl/zformat.hxx> +#include <tools/color.hxx> +#include <i18npool/mslangid.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/util/DateTime.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +FixedNumberFormatter::FixedNumberFormatter( + const uno::Reference< util::XNumberFormatsSupplier >& xSupplier + , sal_Int32 nNumberFormatKey ) + : m_aNumberFormatterWrapper(xSupplier) + , m_nNumberFormatKey( nNumberFormatKey ) +{ +} + +FixedNumberFormatter::~FixedNumberFormatter() +{ +} + +/* +sal_Int32 FixedNumberFormatter::getTextAndColor( double fUnscaledValueForText, rtl::OUString& rLabel ) const +{ + sal_Int32 nLabelColor = Color(COL_BLUE).GetColor(); //@todo get this from somewheres + rLabel = getFormattedString( fUnscaledValueForText, nLabelColor ); + return nLabelColor; +} +*/ + +rtl::OUString FixedNumberFormatter::getFormattedString( double fValue, sal_Int32& rLabelColor, bool& rbColorChanged ) const +{ + return m_aNumberFormatterWrapper.getFormattedString( + m_nNumberFormatKey, fValue, rLabelColor, rbColorChanged ); +} + +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- +//----------------------------------------------------------------------- + +NumberFormatterWrapper::NumberFormatterWrapper( const uno::Reference< util::XNumberFormatsSupplier >& xSupplier ) + : m_xNumberFormatsSupplier(xSupplier) + , m_pNumberFormatter(NULL) + +{ + uno::Reference<beans::XPropertySet> xProp(m_xNumberFormatsSupplier,uno::UNO_QUERY); + rtl::OUString sNullDate( RTL_CONSTASCII_USTRINGPARAM("NullDate")); + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(sNullDate) ) + m_aNullDate = xProp->getPropertyValue(sNullDate); + SvNumberFormatsSupplierObj* pSupplierObj = SvNumberFormatsSupplierObj::getImplementation( xSupplier ); + if( pSupplierObj ) + m_pNumberFormatter = pSupplierObj->GetNumberFormatter(); + DBG_ASSERT(m_pNumberFormatter,"need a numberformatter"); +} + +NumberFormatterWrapper::~NumberFormatterWrapper() +{ +} + +SvNumberFormatter* NumberFormatterWrapper::getSvNumberFormatter() const +{ + return m_pNumberFormatter; +} + +rtl::OUString NumberFormatterWrapper::getFormattedString( + sal_Int32 nNumberFormatKey, double fValue, sal_Int32& rLabelColor, bool& rbColorChanged ) const +{ + String aText; + Color* pTextColor = NULL; + if( !m_pNumberFormatter ) + { + DBG_ERROR("Need a NumberFormatter"); + return aText; + } + // i99104 handle null date correctly + USHORT nYear = 1899,nDay = 30,nMonth = 12; + if ( m_aNullDate.hasValue() ) + { + Date* pDate = m_pNumberFormatter->GetNullDate(); + if ( pDate ) + { + nYear = pDate->GetYear(); + nMonth = pDate->GetMonth(); + nDay = pDate->GetDay(); + } // if ( pDate ) + util::DateTime aNewNullDate; + m_aNullDate >>= aNewNullDate; + m_pNumberFormatter->ChangeNullDate(aNewNullDate.Day,aNewNullDate.Month,aNewNullDate.Year); + } + m_pNumberFormatter->GetOutputString( + fValue, nNumberFormatKey, aText, &pTextColor); + if ( m_aNullDate.hasValue() ) + { + m_pNumberFormatter->ChangeNullDate(nDay,nMonth,nYear); + } + rtl::OUString aRet( aText ); + + if(pTextColor) + { + rbColorChanged = true; + rLabelColor = pTextColor->GetColor(); + } + else + rbColorChanged = false; + + return aRet; +} + +// to get the language type use MsLangId::convertLocaleToLanguage( rNumberFormat.aLocale ) + +/* + uno::Reference< i18n::XNumberFormatCode > xNumberFormatCode( + m_xCC->getServiceManager()->createInstanceWithContext( C2U( + "com.sun.star.i18n.NumberFormatMapper" ), m_xCC ), uno::UNO_QUERY ); + + i18n::NumberFormatCode aNumberFormatCode = xNumberFormatCode->getDefault ( + i18n::KNumberFormatType::MEDIUM, + i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER, + aLocale ); + + uno::Sequence< i18n::NumberFormatCode > aListOfNumberFormatCode = xNumberFormatCode->getAllFormatCode( + i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER, + aLocale ); + + i18n::NumberFormatCode aNumberFormatCode0 = aListOfNumberFormatCode[0]; + i18n::NumberFormatCode aNumberFormatCode1 = aListOfNumberFormatCode[1]; +*/ + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PlotterBase.cxx b/chart2/source/view/main/PlotterBase.cxx new file mode 100644 index 000000000000..08f43dc7064d --- /dev/null +++ b/chart2/source/view/main/PlotterBase.cxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "PlotterBase.hxx" +#include "PlottingPositionHelper.hxx" +#include "ShapeFactory.hxx" +#include <rtl/math.hxx> +#include <com/sun/star/chart2/DataPointLabel.hpp> +#include <tools/debug.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +PlotterBase::PlotterBase( sal_Int32 nDimensionCount ) + : m_xLogicTarget(NULL) + , m_xFinalTarget(NULL) + , m_xShapeFactory(NULL) + , m_pShapeFactory(NULL) + , m_aCID() + , m_nDimension(nDimensionCount) + , m_pPosHelper(NULL) +{ +} + + void SAL_CALL PlotterBase +::initPlotter( const uno::Reference< drawing::XShapes >& xLogicTarget + , const uno::Reference< drawing::XShapes >& xFinalTarget + , const uno::Reference< lang::XMultiServiceFactory >& xShapeFactory + , const rtl::OUString& rCID ) + throw (uno::RuntimeException) +{ + DBG_ASSERT(xLogicTarget.is()&&xFinalTarget.is()&&xShapeFactory.is(),"no proper initialization parameters"); + //is only allowed to be called once + m_xLogicTarget = xLogicTarget; + m_xFinalTarget = xFinalTarget; + m_xShapeFactory = xShapeFactory; + m_pShapeFactory = new ShapeFactory(xShapeFactory); + m_aCID = rCID; +} + +PlotterBase::~PlotterBase() +{ + delete m_pShapeFactory; +} + +void SAL_CALL PlotterBase::setScales( const uno::Sequence< ExplicitScaleData >& rScales + , sal_Bool bSwapXAndYAxis ) + throw (uno::RuntimeException) +{ + DBG_ASSERT(m_nDimension<=rScales.getLength(),"Dimension of Plotter does not fit two dimension of given scale sequence"); + m_pPosHelper->setScales( rScales, bSwapXAndYAxis ); +} + + +void PlotterBase::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + DBG_ASSERT(m_nDimension==2,"Set this transformation only in case of 2D"); + if(m_nDimension!=2) + return; + m_pPosHelper->setTransformationSceneToScreen( rMatrix ); +} + +uno::Reference< drawing::XShapes > PlotterBase::createGroupShape( + const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString rName ) +{ + if(!m_xShapeFactory.is()) + return NULL; + + if(m_nDimension==2) + { + //create and add to target + return m_pShapeFactory->createGroup2D( xTarget, rName ); + } + else + { + //create and added to target + return m_pShapeFactory->createGroup3D( xTarget, rName ); + } +} + +bool PlotterBase::isValidPosition( const drawing::Position3D& rPos ) +{ + if( ::rtl::math::isNan(rPos.PositionX) ) + return false; + if( ::rtl::math::isNan(rPos.PositionY) ) + return false; + if( ::rtl::math::isNan(rPos.PositionZ) ) + return false; + if( ::rtl::math::isInf(rPos.PositionX) ) + return false; + if( ::rtl::math::isInf(rPos.PositionY) ) + return false; + if( ::rtl::math::isInf(rPos.PositionZ) ) + return false; + return true; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PlottingPositionHelper.cxx b/chart2/source/view/main/PlottingPositionHelper.cxx new file mode 100644 index 000000000000..deb390b70a79 --- /dev/null +++ b/chart2/source/view/main/PlottingPositionHelper.cxx @@ -0,0 +1,667 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include "ViewDefines.hxx" +#include "Linear3DTransformation.hxx" +#include "VPolarTransformation.hxx" + +#include "ShapeFactory.hxx" +#include "PropertyMapper.hxx" +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <com/sun/star/drawing/Position3D.hpp> +#include <com/sun/star/chart2/AxisType.hpp> + +#include <rtl/math.hxx> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PlottingPositionHelper::PlottingPositionHelper() + : m_aScales() + , m_aMatrixScreenToScene() + , m_xTransformationLogicToScene(NULL) + , m_bSwapXAndY( false ) + , m_nXResolution( 1000 ) + , m_nYResolution( 1000 ) + , m_nZResolution( 1000 ) + , m_bMaySkipPointsInRegressionCalculation( true ) +{ +} +PlottingPositionHelper::PlottingPositionHelper( const PlottingPositionHelper& rSource ) + : m_aScales( rSource.m_aScales ) + , m_aMatrixScreenToScene( rSource.m_aMatrixScreenToScene ) + , m_xTransformationLogicToScene( NULL ) //should be recalculated + , m_bSwapXAndY( rSource.m_bSwapXAndY ) + , m_nXResolution( rSource.m_nXResolution ) + , m_nYResolution( rSource.m_nYResolution ) + , m_nZResolution( rSource.m_nZResolution ) + , m_bMaySkipPointsInRegressionCalculation( rSource.m_bMaySkipPointsInRegressionCalculation ) +{ +} + +PlottingPositionHelper::~PlottingPositionHelper() +{ + +} + +PlottingPositionHelper* PlottingPositionHelper::clone() const +{ + PlottingPositionHelper* pRet = new PlottingPositionHelper(*this); + return pRet; +} + +PlottingPositionHelper* PlottingPositionHelper::createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale ) +{ + PlottingPositionHelper* pRet = this->clone(); + pRet->m_aScales[1]=rSecondaryScale; + return pRet; +} + +void PlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix); + m_xTransformationLogicToScene = NULL; +} + +void PlottingPositionHelper::setScales( const uno::Sequence< ExplicitScaleData >& rScales, sal_Bool bSwapXAndYAxis ) +{ + m_aScales = rScales; + m_bSwapXAndY = bSwapXAndYAxis; + m_xTransformationLogicToScene = NULL; +} +const uno::Sequence< ExplicitScaleData >& PlottingPositionHelper::getScales() const +{ + return m_aScales; +} + +uno::Reference< XTransformation > PlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + //this is a standard transformation for a cartesian coordinate system + + //transformation from 2) to 4) //@todo 2) and 4) need a ink to a document + + //we need to apply this transformation to each geometric object because of a bug/problem + //of the old drawing layer (the UNO_NAME_3D_EXTRUDE_DEPTH is an integer value instead of an double ) + if(!m_xTransformationLogicToScene.is()) + { + ::basegfx::B3DHomMatrix aMatrix; + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + AxisOrientation nXAxisOrientation = m_aScales[0].Orientation; + AxisOrientation nYAxisOrientation = m_aScales[1].Orientation; + AxisOrientation nZAxisOrientation = m_aScales[2].Orientation; + + //apply scaling + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + if(m_bSwapXAndY) + { + std::swap(MinX,MinY); + std::swap(MaxX,MaxY); + std::swap(nXAxisOrientation,nYAxisOrientation); + } + + double fWidthX = MaxX - MinX; + double fWidthY = MaxY - MinY; + double fWidthZ = MaxZ - MinZ; + + double fScaleDirectionX = AxisOrientation_MATHEMATICAL==nXAxisOrientation ? 1.0 : -1.0; + double fScaleDirectionY = AxisOrientation_MATHEMATICAL==nYAxisOrientation ? 1.0 : -1.0; + double fScaleDirectionZ = AxisOrientation_MATHEMATICAL==nZAxisOrientation ? -1.0 : 1.0; + + double fScaleX = fScaleDirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthX; + double fScaleY = fScaleDirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthY; + double fScaleZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ; + + aMatrix.scale(fScaleX, fScaleY, fScaleZ); + + if( AxisOrientation_MATHEMATICAL==nXAxisOrientation ) + aMatrix.translate(-MinX*fScaleX, 0.0, 0.0); + else + aMatrix.translate(-MaxX*fScaleX, 0.0, 0.0); + if( AxisOrientation_MATHEMATICAL==nYAxisOrientation ) + aMatrix.translate(0.0, -MinY*fScaleY, 0.0); + else + aMatrix.translate(0.0, -MaxY*fScaleY, 0.0); + if( AxisOrientation_MATHEMATICAL==nZAxisOrientation ) + aMatrix.translate(0.0, 0.0, -MaxZ*fScaleZ);//z direction in draw is reverse mathematical direction + else + aMatrix.translate(0.0, 0.0, -MinZ*fScaleZ); + + aMatrix = m_aMatrixScreenToScene*aMatrix; + + m_xTransformationLogicToScene = new Linear3DTransformation(B3DHomMatrixToHomogenMatrix( aMatrix ),m_bSwapXAndY); + } + return m_xTransformationLogicToScene; +} + +drawing::Position3D PlottingPositionHelper::transformLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + this->clipLogicValues( &fX,&fY,&fZ ); + this->doLogicScaling( &fX,&fY,&fZ ); + + return this->transformScaledLogicToScene( fX, fY, fZ, false ); +} + +drawing::Position3D PlottingPositionHelper::transformScaledLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + if( bClip ) + this->clipScaledLogicValues( &fX,&fY,&fZ ); + + drawing::Position3D aPos( fX, fY, fZ); + + uno::Reference< XTransformation > xTransformation = + this->getTransformationScaledLogicToScene(); + uno::Sequence< double > aSeq = + xTransformation->transform( Position3DToSequence(aPos) ); + return SequenceToPosition3D(aSeq); +} + +//static +awt::Point PlottingPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D + , const uno::Reference< drawing::XShapes >& xSceneTarget + , ShapeFactory* pShapeFactory + , sal_Int32 nDimensionCount ) +{ + //@todo would like to have a cheaper method to do this transformation + awt::Point aScreenPoint( static_cast<sal_Int32>(rScenePosition3D.PositionX), static_cast<sal_Int32>(rScenePosition3D.PositionY) ); + + //transformation from scene to screen (only neccessary for 3D): + if(3==nDimensionCount) + { + //create 3D anchor shape + tPropertyNameMap aDummyPropertyNameMap; + uno::Reference< drawing::XShape > xShape3DAnchor = pShapeFactory->createCube( xSceneTarget + , rScenePosition3D,drawing::Direction3D(1,1,1) + , 0, 0, aDummyPropertyNameMap); + //get 2D position from xShape3DAnchor + aScreenPoint = xShape3DAnchor->getPosition(); + xSceneTarget->remove(xShape3DAnchor); + } + return aScreenPoint; +} + +void PlottingPositionHelper::transformScaledLogicToScene( drawing::PolyPolygonShape3D& rPolygon ) const +{ + drawing::Position3D aScenePosition; + for( sal_Int32 nS = rPolygon.SequenceX.getLength(); nS--;) + { + drawing::DoubleSequence& xValues = rPolygon.SequenceX[nS]; + drawing::DoubleSequence& yValues = rPolygon.SequenceY[nS]; + drawing::DoubleSequence& zValues = rPolygon.SequenceZ[nS]; + for( sal_Int32 nP = xValues.getLength(); nP--; ) + { + double& fX = xValues[nP]; + double& fY = yValues[nP]; + double& fZ = zValues[nP]; + aScenePosition = this->transformScaledLogicToScene( fX,fY,fZ,true ); + fX = aScenePosition.PositionX; + fY = aScenePosition.PositionY; + fZ = aScenePosition.PositionZ; + } + } +} + + +void PlottingPositionHelper::clipScaledLogicValues( double* pX, double* pY, double* pZ ) const +{ + //get logic clip values: + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + //apply scaling + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + if(pX) + { + if( *pX < MinX ) + *pX = MinX; + else if( *pX > MaxX ) + *pX = MaxX; + } + if(pY) + { + if( *pY < MinY ) + *pY = MinY; + else if( *pY > MaxY ) + *pY = MaxY; + } + if(pZ) + { + if( *pZ < MinZ ) + *pZ = MinZ; + else if( *pZ > MaxZ ) + *pZ = MaxZ; + } +} + +basegfx::B2DRectangle PlottingPositionHelper::getScaledLogicClipDoubleRect() const +{ + //get logic clip values: + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + //apply scaling + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + basegfx::B2DRectangle aRet( MinX, MaxY, MaxX, MinY ); + return aRet; +} + +drawing::Direction3D PlottingPositionHelper::getScaledLogicWidth() const +{ + drawing::Direction3D aRet; + + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MinZ = getLogicMinZ(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MaxZ = getLogicMaxZ(); + + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + aRet.DirectionX = MaxX - MinX; + aRet.DirectionY = MaxY - MinY; + aRet.DirectionZ = MaxZ - MinZ; + return aRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +PolarPlottingPositionHelper::PolarPlottingPositionHelper( NormalAxis eNormalAxis ) + : m_fRadiusOffset(0.0) + , m_fAngleDegreeOffset(90.0) + , m_aUnitCartesianToScene() + , m_eNormalAxis(eNormalAxis) +{ + m_bMaySkipPointsInRegressionCalculation = false; +} + +PolarPlottingPositionHelper::PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource ) + : PlottingPositionHelper(rSource) + , m_fRadiusOffset( rSource.m_fRadiusOffset ) + , m_fAngleDegreeOffset( rSource.m_fAngleDegreeOffset ) + , m_aUnitCartesianToScene( rSource.m_aUnitCartesianToScene ) + , m_eNormalAxis( rSource.m_eNormalAxis ) +{ +} + +PolarPlottingPositionHelper::~PolarPlottingPositionHelper() +{ +} + +PlottingPositionHelper* PolarPlottingPositionHelper::clone() const +{ + PolarPlottingPositionHelper* pRet = new PolarPlottingPositionHelper(*this); + return pRet; +} + +void PolarPlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + PlottingPositionHelper::setTransformationSceneToScreen( rMatrix); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} +void PolarPlottingPositionHelper::setScales( const uno::Sequence< ExplicitScaleData >& rScales, sal_Bool bSwapXAndYAxis ) +{ + PlottingPositionHelper::setScales( rScales, bSwapXAndYAxis ); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} + +::basegfx::B3DHomMatrix PolarPlottingPositionHelper::impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const +{ + ::basegfx::B3DHomMatrix aRet; + + if( !m_aScales.getLength() ) + return aRet; + + double fTranslate =1.0; + double fScale =FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0; + + double fTranslateLogicZ =fTranslate; + double fScaleLogicZ =fScale; + { + double fScaleDirectionZ = AxisOrientation_MATHEMATICAL==m_aScales[2].Orientation ? 1.0 : -1.0; + double MinZ = getLogicMinZ(); + double MaxZ = getLogicMaxZ(); + doLogicScaling( 0, 0, &MinZ ); + doLogicScaling( 0, 0, &MaxZ ); + double fWidthZ = MaxZ - MinZ; + + if( AxisOrientation_MATHEMATICAL==m_aScales[2].Orientation ) + fTranslateLogicZ=MinZ; + else + fTranslateLogicZ=MaxZ; + fScaleLogicZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ; + } + + double fTranslateX = fTranslate; + double fTranslateY = fTranslate; + double fTranslateZ = fTranslate; + + double fScaleX = fScale; + double fScaleY = fScale; + double fScaleZ = fScale; + + switch(m_eNormalAxis) + { + case NormalAxis_X: + { + fTranslateX = fTranslateLogicZ; + fScaleX = fScaleLogicZ; + } + break; + case NormalAxis_Y: + { + fTranslateY = fTranslateLogicZ; + fScaleY = fScaleLogicZ; + } + break; + default: //NormalAxis_Z: + { + fTranslateZ = fTranslateLogicZ; + fScaleZ = fScaleLogicZ; + } + break; + } + + aRet.translate(fTranslateX, fTranslateY, fTranslateZ);//x first + aRet.scale(fScaleX, fScaleY, fScaleZ);//x first + + aRet = rMatrixScreenToScene * aRet; + return aRet; +} + +::basegfx::B3DHomMatrix PolarPlottingPositionHelper::getUnitCartesianToScene() const +{ + return m_aUnitCartesianToScene; +} + +uno::Reference< XTransformation > PolarPlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + if( !m_xTransformationLogicToScene.is() ) + m_xTransformationLogicToScene = new VPolarTransformation(*this); + return m_xTransformationLogicToScene; +} + +double PolarPlottingPositionHelper::getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const +{ + const ExplicitScaleData& rAngleScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0]; + if( AxisOrientation_MATHEMATICAL != rAngleScale.Orientation ) + { + double fHelp = fEndLogicValueOnAngleAxis; + fEndLogicValueOnAngleAxis = fStartLogicValueOnAngleAxis; + fStartLogicValueOnAngleAxis = fHelp; + } + + double fStartAngleDegree = this->transformToAngleDegree( fStartLogicValueOnAngleAxis ); + double fEndAngleDegree = this->transformToAngleDegree( fEndLogicValueOnAngleAxis ); + double fWidthAngleDegree = fEndAngleDegree - fStartAngleDegree; + + if( ::rtl::math::approxEqual( fStartAngleDegree, fEndAngleDegree ) + && !::rtl::math::approxEqual( fStartLogicValueOnAngleAxis, fEndLogicValueOnAngleAxis ) ) + fWidthAngleDegree = 360.0; + + while(fWidthAngleDegree<0.0) + fWidthAngleDegree+=360.0; + while(fWidthAngleDegree>360.0) + fWidthAngleDegree-=360.0; + + return fWidthAngleDegree; +} + +double PolarPlottingPositionHelper::transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling ) const +{ + double fRet=0.0; + + double fAxisAngleScaleDirection = 1.0; + { + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0]; + if(AxisOrientation_MATHEMATICAL != rScale.Orientation) + fAxisAngleScaleDirection *= -1.0; + } + + double MinAngleValue = 0.0; + double MaxAngleValue = 0.0; + { + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + double MinZ = getLogicMinZ(); + double MaxZ = getLogicMaxZ(); + + doLogicScaling( &MinX, &MinY, &MinZ ); + doLogicScaling( &MaxX, &MaxY, &MaxZ); + + MinAngleValue = m_bSwapXAndY ? MinY : MinX; + MaxAngleValue = m_bSwapXAndY ? MaxY : MaxX; + } + + double fScaledLogicAngleValue = 0.0; + if(bDoScaling) + { + double fX = m_bSwapXAndY ? getLogicMaxX() : fLogicValueOnAngleAxis; + double fY = m_bSwapXAndY ? fLogicValueOnAngleAxis : getLogicMaxY(); + double fZ = getLogicMaxZ(); + clipLogicValues( &fX, &fY, &fZ ); + doLogicScaling( &fX, &fY, &fZ ); + fScaledLogicAngleValue = m_bSwapXAndY ? fY : fX; + } + else + fScaledLogicAngleValue = fLogicValueOnAngleAxis; + + fRet = m_fAngleDegreeOffset + + fAxisAngleScaleDirection*(fScaledLogicAngleValue-MinAngleValue)*360.0 + /fabs(MaxAngleValue-MinAngleValue); + while(fRet>360.0) + fRet-=360.0; + while(fRet<0) + fRet+=360.0; + return fRet; +} + +double PolarPlottingPositionHelper::transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling ) const +{ + double fNormalRadius = 0.0; + { + double fScaledLogicRadiusValue = 0.0; + double fX = m_bSwapXAndY ? fLogicValueOnRadiusAxis: getLogicMaxX(); + double fY = m_bSwapXAndY ? getLogicMaxY() : fLogicValueOnRadiusAxis; + if(bDoScaling) + doLogicScaling( &fX, &fY, 0 ); + + fScaledLogicRadiusValue = m_bSwapXAndY ? fX : fY; + + bool bMinIsInnerRadius = true; + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if(AxisOrientation_MATHEMATICAL != rScale.Orientation) + bMinIsInnerRadius = false; + + double fInnerScaledLogicRadius=0.0; + double fOuterScaledLogicRadius=0.0; + { + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + doLogicScaling( &MinX, &MinY, 0 ); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + doLogicScaling( &MaxX, &MaxY, 0 ); + + double fMin = m_bSwapXAndY ? MinX : MinY; + double fMax = m_bSwapXAndY ? MaxX : MaxY; + + fInnerScaledLogicRadius = bMinIsInnerRadius ? fMin : fMax; + fOuterScaledLogicRadius = bMinIsInnerRadius ? fMax : fMin; + } + + if( bMinIsInnerRadius ) + fInnerScaledLogicRadius -= fabs(m_fRadiusOffset); + else + fInnerScaledLogicRadius += fabs(m_fRadiusOffset); + fNormalRadius = (fScaledLogicRadiusValue-fInnerScaledLogicRadius)/(fOuterScaledLogicRadius-fInnerScaledLogicRadius); + } + return fNormalRadius; +} + +drawing::Position3D PolarPlottingPositionHelper::transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + this->clipLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return this->transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, true ); +} + +drawing::Position3D PolarPlottingPositionHelper::transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + this->clipScaledLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return this->transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, false ); +} +drawing::Position3D PolarPlottingPositionHelper::transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius + , double fLogicZ, bool /* bDoScaling */ ) const +{ + double fAnglePi = fUnitAngleDegree*F_PI/180.0; + + double fX=fUnitRadius*rtl::math::cos(fAnglePi); + double fY=fUnitRadius*rtl::math::sin(fAnglePi); + double fZ=fLogicZ; + + switch(m_eNormalAxis) + { + case NormalAxis_X: + std::swap(fX,fZ); + break; + case NormalAxis_Y: + std::swap(fY,fZ); + fZ*=-1; + break; + default: //NormalAxis_Z + break; + } + + //!! applying matrix to vector does ignore translation, so it is important to use a B3DPoint here instead of B3DVector + ::basegfx::B3DPoint aPoint(fX,fY,fZ); + ::basegfx::B3DPoint aRet = m_aUnitCartesianToScene * aPoint; + return B3DPointToPosition3D(aRet); +} + +drawing::Position3D PolarPlottingPositionHelper::transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling ) const +{ + double fUnitAngleDegree = this->transformToAngleDegree(fLogicValueOnAngleAxis,bDoScaling); + double fUnitRadius = this->transformToRadius(fLogicValueOnRadiusAxis,bDoScaling); + + return transformUnitCircleToScene( fUnitAngleDegree, fUnitRadius, fLogicZ, bDoScaling ); +} + +#ifdef NOTYET +double PolarPlottingPositionHelper::getInnerLogicRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return rScale.Minimum; + else + return rScale.Maximum; +} +#endif + +double PolarPlottingPositionHelper::getOuterLogicRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return rScale.Maximum; + else + return rScale.Minimum; +} + +bool PlottingPositionHelper::isPercentY() const +{ + return m_aScales[1].AxisType==AxisType::PERCENT; +} + +double PlottingPositionHelper::getBaseValueY() const +{ + return m_aScales[1].Origin; +} + +/* +// ____ XTransformation ____ +uno::Sequence< double > SAL_CALL PolarPlottingPositionHelper::transform( + const uno::Sequence< double >& rSourceValues ) + throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + uno::Sequence< double > aSourceValues(3); + return aSourceValues; +} + +sal_Int32 SAL_CALL PolarPlottingPositionHelper::getSourceDimension() throw (uno::RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL PolarPlottingPositionHelper::getTargetDimension() throw (uno::RuntimeException) +{ + return 3; +} +*/ + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PolarLabelPositionHelper.cxx b/chart2/source/view/main/PolarLabelPositionHelper.cxx new file mode 100644 index 000000000000..8e5402b48d63 --- /dev/null +++ b/chart2/source/view/main/PolarLabelPositionHelper.cxx @@ -0,0 +1,188 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "PolarLabelPositionHelper.hxx" +#include "PlottingPositionHelper.hxx" +#include "CommonConverters.hxx" +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/vector/b2ivector.hxx> + +#include <com/sun/star/chart/DataLabelPlacement.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PolarLabelPositionHelper::PolarLabelPositionHelper( + PolarPlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const uno::Reference< drawing::XShapes >& xLogicTarget + , ShapeFactory* pShapeFactory ) + : LabelPositionHelper( pPosHelper, nDimensionCount, xLogicTarget, pShapeFactory ) + , m_pPosHelper(pPosHelper) +{ +} + +PolarLabelPositionHelper::~PolarLabelPositionHelper() +{ +} + +awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForLogicValues( + LabelAlignment& rAlignment + , double fLogicValueOnAngleAxis + , double fLogicValueOnRadiusAxis + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const +{ + double fUnitCircleAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicValueOnAngleAxis ); + double fUnitCircleRadius = m_pPosHelper->transformToRadius( fLogicValueOnRadiusAxis ); + + return getLabelScreenPositionAndAlignmentForUnitCircleValues( + rAlignment, ::com::sun::star::chart::DataLabelPlacement::OUTSIDE + , fUnitCircleAngleDegree, 0.0 + , fUnitCircleRadius, fUnitCircleRadius, fLogicZ, nScreenValueOffsetInRadiusDirection ); +} + +awt::Point PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const +{ + bool bCenter = (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::OUTSIDE) + && (nLabelPlacement != ::com::sun::star::chart::DataLabelPlacement::INSIDE); + + double fAngleDegree = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0; + double fRadius = 0.0; + if( !bCenter ) //e.g. for pure pie chart(one ring only) or for angle axis of polyar coordinate system + fRadius = fUnitCircleOuterRadius; + else + fRadius = fUnitCircleInnerRadius + (fUnitCircleOuterRadius-fUnitCircleInnerRadius)/2.0 ; + + awt::Point aRet( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ+0.5 ) ) ); + + if(3==m_nDimensionCount && nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE) + { + //check wether the upper or the downer edge is more distant from the center + //take the farest point to put the label to + + awt::Point aP0( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ ) ) ); + awt::Point aP1(aRet); + awt::Point aP2( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ-0.5 ) ) ); + + ::basegfx::B2DVector aV0( aP0.X, aP0.Y ); + ::basegfx::B2DVector aV1( aP1.X, aP1.Y ); + ::basegfx::B2DVector aV2( aP2.X, aP2.Y ); + + double fL1 = ::basegfx::B2DVector(aV1-aV0).getLength(); + double fL2 = ::basegfx::B2DVector(aV2-aV0).getLength(); + + if(fL2>fL1) + aRet = aP2; + + //calculate new angle for alignment + double fDX = aRet.X-aP0.X; + double fDY = aRet.Y-aP0.Y; + fDY*=-1.0;//drawing layer has inverse y values + if( fDX != 0.0 ) + { + fAngleDegree = atan(fDY/fDX)*180.0/F_PI; + if(fDX<0.0) + fAngleDegree+=180.0; + } + else + { + if(fDY>0.0) + fAngleDegree = 90.0; + else + fAngleDegree = 270.0; + } + } + //------------------------------ + //set LabelAlignment + if( !bCenter ) + { + while(fAngleDegree>360.0) + fAngleDegree-=360.0; + while(fAngleDegree<0.0) + fAngleDegree+=360.0; + + bool bOutside = nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE; + + if(fAngleDegree==0.0) + rAlignment = LABEL_ALIGN_CENTER; + else if(fAngleDegree<=22.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + else if(fAngleDegree<67.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_TOP : LABEL_ALIGN_LEFT_BOTTOM; + else if(fAngleDegree<112.5) + rAlignment = bOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + else if(fAngleDegree<=157.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_TOP : LABEL_ALIGN_RIGHT_BOTTOM; + else if(fAngleDegree<=202.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + else if(fAngleDegree<247.5) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_BOTTOM : LABEL_ALIGN_RIGHT_TOP; + else if(fAngleDegree<292.5) + rAlignment = bOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + else if(fAngleDegree<337.5) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_BOTTOM : LABEL_ALIGN_LEFT_TOP; + else + rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + } + else + { + rAlignment = LABEL_ALIGN_CENTER; + } + + //add a scaling independent Offset if requested + if( nScreenValueOffsetInRadiusDirection != 0) + { + awt::Point aOrigin( this->transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+0.5 ) ) ); + basegfx::B2IVector aDirection( aRet.X- aOrigin.X, aRet.Y- aOrigin.Y ); + aDirection.setLength(nScreenValueOffsetInRadiusDirection); + aRet.X += aDirection.getX(); + aRet.Y += aDirection.getY(); + } + + return aRet; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/PropertyMapper.cxx b/chart2/source/view/main/PropertyMapper.cxx new file mode 100644 index 000000000000..1979582763fa --- /dev/null +++ b/chart2/source/view/main/PropertyMapper.cxx @@ -0,0 +1,539 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "PropertyMapper.hxx" +#include "ContainerHelper.hxx" +#include "macros.hxx" + +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +namespace +{ + +void lcl_overwriteOrAppendValues( + tPropertyNameValueMap &rMap, const tPropertyNameValueMap& rOverwriteMap ) +{ + tPropertyNameValueMap::const_iterator aIt( rOverwriteMap.begin() ); + tPropertyNameValueMap::const_iterator aEnd( rOverwriteMap.end() ); + + for( ; aIt != aEnd; ++aIt ) + rMap[ aIt->first ] = aIt->second; +} + +} // anonymous namespace + +//static +void PropertyMapper::setMappedProperties( + const uno::Reference< beans::XPropertySet >& xTarget + , const uno::Reference< beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap + , tPropertyNameValueMap* pOverwriteMap ) +{ + if( !xTarget.is() || !xSource.is() ) + return; + + tNameSequence aNames; + tAnySequence aValues; + getMultiPropertyLists(aNames, aValues, xSource, rMap ); + if(pOverwriteMap && (aNames.getLength() == aValues.getLength())) + { + tPropertyNameValueMap aNewMap; + for( sal_Int32 nI=0; nI<aNames.getLength(); ++nI ) + aNewMap[ aNames[nI] ] = aValues[nI]; + lcl_overwriteOrAppendValues( aNewMap, *pOverwriteMap ); + aNames = ContainerHelper::MapKeysToSequence( aNewMap ); + aValues = ContainerHelper::MapValuesToSequence( aNewMap ); + } + + PropertyMapper::setMultiProperties( aNames, aValues, xTarget ); +} + +void PropertyMapper::getValueMap( + tPropertyNameValueMap& rValueMap + , const tPropertyNameMap& rNameMap + , const uno::Reference< beans::XPropertySet >& xSourceProp + ) +{ + tPropertyNameMap::const_iterator aIt( rNameMap.begin() ); + tPropertyNameMap::const_iterator aEnd( rNameMap.end() ); + + for( ; aIt != aEnd; ++aIt ) + { + rtl::OUString aTarget = aIt->first; + rtl::OUString aSource = aIt->second; + try + { + uno::Any aAny( xSourceProp->getPropertyValue(aSource) ); + if( aAny.hasValue() ) + rValueMap.insert( tPropertyNameValueMap::value_type( aTarget, aAny ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +void PropertyMapper::getMultiPropertyLists( + tNameSequence& rNames + , tAnySequence& rValues + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rNameMap + ) +{ + tPropertyNameValueMap aValueMap; + getValueMap( aValueMap, rNameMap, xSourceProp ); + getMultiPropertyListsFromValueMap( rNames, rValues, aValueMap ); +} + +void PropertyMapper::getMultiPropertyListsFromValueMap( + tNameSequence& rNames + , tAnySequence& rValues + , const tPropertyNameValueMap& rValueMap + ) +{ + sal_Int32 nPropertyCount = rValueMap.size(); + rNames.realloc(nPropertyCount); + rValues.realloc(nPropertyCount); + + //fill sequences + tPropertyNameValueMap::const_iterator aValueIt( rValueMap.begin() ); + tPropertyNameValueMap::const_iterator aValueEnd( rValueMap.end() ); + sal_Int32 nN=0; + for( ; aValueIt != aValueEnd; ++aValueIt ) + { + const uno::Any& rAny = aValueIt->second; + if( rAny.hasValue() ) + { + //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer) + rNames[nN] = aValueIt->first; + rValues[nN] = rAny; + ++nN; + } + } + //reduce to real property count + rNames.realloc(nN); + rValues.realloc(nN); +} + +uno::Any* PropertyMapper::getValuePointer( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , const rtl::OUString& rPropName ) +{ + sal_Int32 nCount = rPropNames.getLength(); + for( sal_Int32 nN = 0; nN < nCount; nN++ ) + { + if(rPropNames[nN].equals(rPropName)) + return &rPropValues[nN]; + } + return NULL; +} + +uno::Any* PropertyMapper::getValuePointerForLimitedSpace( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , bool bLimitedHeight) +{ + return PropertyMapper::getValuePointer( rPropValues, rPropNames + , bLimitedHeight ? C2U("TextMaximumFrameHeight") : C2U("TextMaximumFrameWidth") ); +} + +/* +//set some properties from service style::CharacterProperties: +//-------- tabpage: Zeichen ----------- +//Schriftart z.B. Albany UNO_NAME_EDIT_CHAR_FONTNAME == UNO_NAME_EDIT_CHAR_FONTSTYLENAME //UNO_NAME_CHAR_FONT +//Schriftschnitt z.B. kursiv UNO_NAME_EDIT_CHAR_POSTURE UNO_NAME_CHAR_POSTURE awt::FontSlant NONE OBLIQUE ITALIC DONTKNOW REVERSE_OBLIQUE REVERSE_ITALIC +//Schriftgrad (Punktgrösse z.B. 12) UNO_NAME_EDIT_CHAR_HEIGHT == UNO_NAME_CHAR_HEIGHT + //? UNO_NAME_EDIT_CHAR_WEIGHT == UNO_NAME_CHAR_WEIGHT +//Sprache UNO_NAME_EDIT_CHAR_LOCALE lang::Locale + +//-------- tabpage: Schrifteffekt ----------- +//Unterstreichung UNO_NAME_CHAR_UNDERLINE sal_Int16 awt::FontUnderline_NONE _SINGLE _DOUBLE _DOTTED _DONTKNOW _DASH ... +//Unterstreichung-farbe ??? 'CharUnderlineColor' + CharUnderlineHasColor +//Durchstreichung z.B. doppelt "CharStrikeout" sal_Int16 awt::FontStrikeout_NONE _SINGLE _DOUBLE ... +//wortweise-Durchstreichung ja/nein "CharWordMode" bool +//Schriftfarbe UNO_NAME_EDIT_CHAR_COLOR sal_Int32 UNO_NAME_CHAR_COLOR +//ReliefArt ohne/erhaben/tief "CharRelief" sal_Int16 text::FontRelief_NONE FontRelief_EMBOSSED FontRelief_ENGRAVED +//Kontur "CharContoured" bool +//Schatten UNO_NAME_CHAR_SHADOWED bool +*/ + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForCharacterProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForCharacterProperties = + tMakePropertyNameMap +// ( C2U( "CharBackColor" ), C2U("TextBackgroundColor") ) +// ( C2U( "CharCaseMap" ), C2U("CaseMapping") ) + ( C2U( "CharColor" ), C2U("CharColor") ) + ( C2U( "CharContoured" ), C2U("CharContoured") ) +/////// ( C2U( "CharCrossedOut" ), C2U("CharCrossedOut") ) //setting this explicitly somehow conflicts with CharStrikeout + ( C2U( "CharEmphasis" ), C2U("CharEmphasis") )//the service style::CharacterProperties describes a property called 'CharEmphasize' wich is nowhere implemented +// ( C2U( "CharEscapement" ), C2U("CharEscapement") ) //#i98344# @future: add these to properties again, if the user interface offers the possibility to change them; then make sure that older wrong files are corrected on import +// ( C2U( "CharEscapementHeight" ), C2U("CharEscapementHeight") ) //#i98344# @future: add these to properties again, if the user interface offers the possibility to change them; then make sure that older wrong files are corrected on import +// ( C2U( "CharFlash" ), C2U("Flashing") ) + + ( C2U( "CharFontFamily" ), C2U("CharFontFamily") ) + ( C2U( "CharFontFamilyAsian" ), C2U("CharFontFamilyAsian") ) + ( C2U( "CharFontFamilyComplex" ), C2U("CharFontFamilyComplex") ) + ( C2U( "CharFontCharSet" ), C2U("CharFontCharSet") ) + ( C2U( "CharFontCharSetAsian" ), C2U("CharFontCharSetAsian") ) + ( C2U( "CharFontCharSetComplex" ), C2U("CharFontCharSetComplex") ) + ( C2U( "CharFontName" ), C2U("CharFontName") ) + ( C2U( "CharFontNameAsian" ), C2U("CharFontNameAsian") ) + ( C2U( "CharFontNameComplex" ), C2U("CharFontNameComplex") ) + ( C2U( "CharFontPitch" ), C2U("CharFontPitch") ) + ( C2U( "CharFontPitchAsian" ), C2U("CharFontPitchAsian") ) + ( C2U( "CharFontPitchComplex" ), C2U("CharFontPitchComplex") ) + ( C2U( "CharFontStyleName" ), C2U("CharFontStyleName") ) + ( C2U( "CharFontStyleNameAsian" ), C2U("CharFontStyleNameAsian") ) + ( C2U( "CharFontStyleNameComplex" ),C2U("CharFontStyleNameComplex") ) + + ( C2U( "CharHeight" ), C2U("CharHeight") ) + ( C2U( "CharHeightAsian" ), C2U("CharHeightAsian") ) + ( C2U( "CharHeightComplex" ), C2U("CharHeightComplex") ) + ( C2U( "CharKerning" ), C2U("CharKerning") ) + ( C2U( "CharLocale" ), C2U("CharLocale") ) + ( C2U( "CharLocaleAsian" ), C2U("CharLocaleAsian") ) + ( C2U( "CharLocaleComplex" ), C2U("CharLocaleComplex") ) +// ( C2U( "CharNoHyphenation" ), C2U("InhibitHyphenation") ) + ( C2U( "CharPosture" ), C2U("CharPosture") ) + ( C2U( "CharPostureAsian" ), C2U("CharPostureAsian") ) + ( C2U( "CharPostureComplex" ), C2U("CharPostureComplex") ) + ( C2U( "CharRelief" ), C2U("CharRelief") ) +// ( C2U( "CharRotation" ), C2U("Rotation") ) --> additional feature ... +// ( C2U( "CharScaleWidth" ), C2U("CharScaleWidth") ) + ( C2U( "CharShadowed" ), C2U("CharShadowed") ) + ( C2U( "CharStrikeout" ), C2U("CharStrikeout") ) + ( C2U( "CharUnderline" ), C2U("CharUnderline") ) + ( C2U( "CharUnderlineColor" ), C2U("CharUnderlineColor") ) + ( C2U( "CharUnderlineHasColor" ), C2U("CharUnderlineHasColor") ) + ( C2U( "CharWeight" ), C2U("CharWeight") ) + ( C2U( "CharWeightAsian" ), C2U("CharWeightAsian") ) + ( C2U( "CharWeightComplex" ), C2U("CharWeightComplex") ) + ( C2U( "CharWordMode" ), C2U("CharWordMode") ) + + ( C2U( "WritingMode" ), C2U("WritingMode") ) + +// ( C2U( "RubyText" ), C2U("RubyText") ) +// ( C2U( "RubyAdjust" ), C2U("RubyAdjust") ) +// ( C2U( "RubyCharStyleName" ), C2U("RubyStyleName") ) +// ( C2U( "RubyIsAbove" ), C2U("RubyIsAbove") ) + ( C2U( "ParaIsCharacterDistance" ), C2U("ParaIsCharacterDistance") ) + ; + return m_aShapePropertyMapForCharacterProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForParagraphProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForParagraphProperties = + tMakePropertyNameMap + ( C2U( "ParaAdjust" ), C2U("ParaAdjust") ) + ( C2U( "ParaBottomMargin" ), C2U("ParaBottomMargin") ) + ( C2U( "ParaIsHyphenation" ), C2U("ParaIsHyphenation") ) + ( C2U( "ParaLastLineAdjust" ), C2U("ParaLastLineAdjust") ) + ( C2U( "ParaLeftMargin" ), C2U("ParaLeftMargin") ) + ( C2U( "ParaRightMargin" ), C2U("ParaRightMargin") ) + ( C2U( "ParaTopMargin" ), C2U("ParaTopMargin") ) + ; + return m_aShapePropertyMapForParagraphProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForFillProperties = + tMakePropertyNameMap + ( C2U( "FillBackground" ), C2U( "FillBackground" ) ) + ( C2U( "FillBitmapName" ), C2U( "FillBitmapName" ) ) + ( C2U( "FillColor" ), C2U( "FillColor" ) ) + ( C2U( "FillGradientName" ), C2U( "FillGradientName" ) ) + ( C2U( "FillGradientStepCount" ), C2U( "FillGradientStepCount" ) ) + ( C2U( "FillHatchName" ), C2U( "FillHatchName" ) ) + ( C2U( "FillStyle" ), C2U( "FillStyle" ) ) + ( C2U( "FillTransparence" ), C2U( "FillTransparence" ) ) + ( C2U( "FillTransparenceGradientName" ), C2U("FillTransparenceGradientName") ) + //bitmap properties + ( C2U( "FillBitmapMode" ), C2U( "FillBitmapMode" ) ) + ( C2U( "FillBitmapSizeX" ), C2U( "FillBitmapSizeX" ) ) + ( C2U( "FillBitmapSizeY" ), C2U( "FillBitmapSizeY" ) ) + ( C2U( "FillBitmapLogicalSize" ), C2U( "FillBitmapLogicalSize" ) ) + ( C2U( "FillBitmapOffsetX" ), C2U( "FillBitmapOffsetX" ) ) + ( C2U( "FillBitmapOffsetY" ), C2U( "FillBitmapOffsetY" ) ) + ( C2U( "FillBitmapRectanglePoint" ),C2U( "FillBitmapRectanglePoint" ) ) + ( C2U( "FillBitmapPositionOffsetX" ),C2U( "FillBitmapPositionOffsetX" ) ) + ( C2U( "FillBitmapPositionOffsetY" ),C2U( "FillBitmapPositionOffsetY" ) ) + ; + return m_aShapePropertyMapForFillProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForLineProperties = + tMakePropertyNameMap + ( C2U( "LineColor" ), C2U( "LineColor" ) ) + ( C2U( "LineDashName" ), C2U( "LineDashName" ) ) + ( C2U( "LineJoint" ), C2U( "LineJoint" ) ) + ( C2U( "LineStyle" ), C2U( "LineStyle" ) ) + ( C2U( "LineTransparence" ), C2U( "LineTransparence" ) ) + ( C2U( "LineWidth" ), C2U( "LineWidth" ) ) + ; + return m_aShapePropertyMapForLineProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFillAndLineProperties() +{ + static tMakePropertyNameMap m_aShapePropertyMapForFillAndLineProperties = + tMakePropertyNameMap + ( PropertyMapper::getPropertyNameMapForFillProperties() ) + ( PropertyMapper::getPropertyNameMapForLineProperties() ) + ; + + return m_aShapePropertyMapForFillAndLineProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForTextShapeProperties() +{ + static tMakePropertyNameMap m_aShapePropertyMapForTextShapeProperties = + tMakePropertyNameMap + ( PropertyMapper::getPropertyNameMapForCharacterProperties() ) + ( PropertyMapper::getPropertyNameMapForFillProperties() ) + ( PropertyMapper::getPropertyNameMapForLineProperties() ) +// ( PropertyMapper::getPropertyNameMapForParagraphProperties() ) + // some text properties +// ( C2U( "TextHorizontalAdjust" ), C2U( "TextHorizontalAdjust" ) ) +// ( C2U( "TextVerticalAdjust" ), C2U( "TextVerticalAdjust" ) ) +// ( C2U( "TextAutoGrowHeight" ), C2U( "TextAutoGrowHeight" ) ) +// ( C2U( "TextAutoGrowWidth" ), C2U( "TextAutoGrowWidth" ) ) +// ( C2U( "TextLeftDistance" ), C2U( "TextLeftDistance" ) ) +// ( C2U( "TextRightDistance" ), C2U( "TextRightDistance" ) ) +// ( C2U( "TextUpperDistance" ), C2U( "TextUpperDistance" ) ) +// ( C2U( "TextLowerDistance" ), C2U( "TextLowerDistance" ) ) + ; + + return m_aShapePropertyMapForTextShapeProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForLineSeriesProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForLineSeriesProperties = + tMakePropertyNameMap + ( C2U( "LineColor" ), C2U("Color") ) + ( C2U( "LineDashName" ), C2U("LineDashName") ) +// ( C2U( "LineJoint" ), C2U("LineJoint") ) + ( C2U( "LineStyle" ), C2U("LineStyle") ) + ( C2U( "LineTransparence" ), C2U("Transparency") ) + ( C2U( "LineWidth" ), C2U("LineWidth") ) + + ; + return m_aShapePropertyMapForLineSeriesProperties; +} + +//static +const tMakePropertyNameMap& PropertyMapper::getPropertyNameMapForFilledSeriesProperties() +{ + //shape property -- chart model object property + static tMakePropertyNameMap m_aShapePropertyMapForFilledSeriesProperties = + tMakePropertyNameMap + ( C2U( "FillBackground"), C2U("FillBackground") ) + ( C2U( "FillBitmapName" ), C2U("FillBitmapName") ) + ( C2U( "FillColor" ), C2U("Color") ) + ( C2U( "FillGradientName" ), C2U("GradientName") ) + ( C2U( "FillGradientStepCount" ), C2U( "GradientStepCount" ) ) + ( C2U( "FillHatchName" ), C2U("HatchName") ) + ( C2U( "FillStyle" ), C2U("FillStyle") ) + ( C2U( "FillTransparence" ), C2U("Transparency") ) + ( C2U( "FillTransparenceGradientName" ), C2U("TransparencyGradientName") ) + //bitmap properties + ( C2U( "FillBitmapMode" ), C2U( "FillBitmapMode" ) ) + ( C2U( "FillBitmapSizeX" ), C2U( "FillBitmapSizeX" ) ) + ( C2U( "FillBitmapSizeY" ), C2U( "FillBitmapSizeY" ) ) + ( C2U( "FillBitmapLogicalSize" ), C2U( "FillBitmapLogicalSize" ) ) + ( C2U( "FillBitmapOffsetX" ), C2U( "FillBitmapOffsetX" ) ) + ( C2U( "FillBitmapOffsetY" ), C2U( "FillBitmapOffsetY" ) ) + ( C2U( "FillBitmapRectanglePoint" ),C2U( "FillBitmapRectanglePoint" ) ) + ( C2U( "FillBitmapPositionOffsetX" ),C2U( "FillBitmapPositionOffsetX" ) ) + ( C2U( "FillBitmapPositionOffsetY" ),C2U( "FillBitmapPositionOffsetY" ) ) + //line properties + ( C2U( "LineColor" ), C2U("BorderColor") ) + ( C2U( "LineDashName" ), C2U("BorderDashName") ) +// ( C2U( "LineJoint" ), C2U("LineJoint") ) + ( C2U( "LineStyle" ), C2U("BorderStyle") ) + ( C2U( "LineTransparence" ), C2U("BorderTransparency") ) + ( C2U( "LineWidth" ), C2U("BorderWidth") ) + ; + return m_aShapePropertyMapForFilledSeriesProperties; +} + +// static +void PropertyMapper::setMultiProperties( + const tNameSequence& rNames + , const tAnySequence& rValues + , const ::com::sun::star::uno::Reference< + ::com::sun::star::beans::XPropertySet >& xTarget ) +{ + bool bSuccess = false; + try + { + uno::Reference< beans::XMultiPropertySet > xShapeMultiProp( xTarget, uno::UNO_QUERY ); + if( xShapeMultiProp.is() ) + { + xShapeMultiProp->setPropertyValues( rNames, rValues ); + bSuccess = true; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); //if this occurs more often think of removing the XMultiPropertySet completly for better performance + } + + if(!bSuccess) + try + { + sal_Int32 nCount = std::max( rNames.getLength(), rValues.getLength() ); + rtl::OUString aPropName; + uno::Any aValue; + for( sal_Int32 nN = 0; nN < nCount; nN++ ) + { + aPropName = rNames[nN]; + aValue = rValues[nN]; + + try + { + xTarget->setPropertyValue( aPropName, aValue ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void PropertyMapper::getTextLabelMultiPropertyLists( + const uno::Reference< beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues + , bool bName + , sal_Int32 nLimitedSpace + , bool bLimitedHeight ) +{ + //fill character properties into the ValueMap + tPropertyNameValueMap aValueMap; + PropertyMapper::getValueMap( aValueMap + , PropertyMapper::getPropertyNameMapForCharacterProperties() + , xSourceProp ); + + //some more shape properties apart from character properties, position-matrix and label string + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("LineStyle"), uno::makeAny(drawing::LineStyle_NONE) ) ); // drawing::LineStyle + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny(drawing::TextHorizontalAdjust_CENTER) ) ); // drawing::TextHorizontalAdjust - needs to be overwritten + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny(drawing::TextVerticalAdjust_CENTER) ) ); //drawing::TextVerticalAdjust - needs to be overwritten + //aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextWritingMode"), uno::makeAny(eWritingMode) ) ); //text::WritingMode + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny(sal_True) ) ); // sal_Bool + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny(sal_True) ) ); // sal_Bool + if( bName ) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( rtl::OUString() ) ) ); //CID rtl::OUString - needs to be overwritten for each point + + if( nLimitedSpace > 0 ) + { + if(bLimitedHeight) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameHeight"), uno::makeAny(nLimitedSpace) ) ); //sal_Int32 + else + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameWidth"), uno::makeAny(nLimitedSpace) ) ); //sal_Int32 + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("ParaIsHyphenation"), uno::makeAny(sal_True) ) ); + } + + /* + //@todo ?: add paragraph properties: + //(uno::makeAny(eParaAdjust)) //ParaAdjust - style::ParagraphAdjust + //(uno::makeAny( (sal_Bool)rAxisLabelProperties.bLineBreakAllowed )) //ParaIsHyphenation - sal_Bool + style::ParagraphAdjust eParaAdjust( style::ParagraphAdjust_LEFT ); + if( eHorizontalAdjust == drawing::TextHorizontalAdjust_RIGHT ) + eParaAdjust = style::ParagraphAdjust_RIGHT; + */ + + PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap ); +} + +void PropertyMapper::getPreparedTextShapePropertyLists( + const uno::Reference< beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues ) +{ + //fill character, line and fill properties into the ValueMap + tPropertyNameValueMap aValueMap; + PropertyMapper::getValueMap( aValueMap + , PropertyMapper::getPropertyNameMapForTextShapeProperties() + , xSourceProp ); + + // auto-grow makes sure the shape has the correct size after setting text + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny( drawing::TextHorizontalAdjust_CENTER ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny( drawing::TextVerticalAdjust_CENTER ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny( true ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny( true ))); + + // set some distance to the border, in case it is shown + const sal_Int32 nWidthDist = 250; + const sal_Int32 nHeightDist = 125; + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextLeftDistance"), uno::makeAny( nWidthDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextRightDistance"), uno::makeAny( nWidthDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextUpperDistance"), uno::makeAny( nHeightDist ))); + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextLowerDistance"), uno::makeAny( nHeightDist ))); + + // use a line-joint showing the border of thick lines like two rectangles + // filled in between. + aValueMap[C2U("LineJoint")] <<= drawing::LineJoint_ROUND; + + PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx new file mode 100644 index 000000000000..721cabd15d83 --- /dev/null +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -0,0 +1,2111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "ShapeFactory.hxx" +#include "ViewDefines.hxx" +#include "Stripe.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include <comphelper/InlineContainer.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 <tools/color.hxx> +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <svx/svdocirc.hxx> +#include <svx/svdopath.hxx> + +#ifndef _BGFX_VECTOR_B2DPOINT_HXX +#include <basegfx/point/b2dpoint.hxx> +#endif +#include <basegfx/matrix/b3dhommatrix.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// set a name/CID at a shape (is used for selection handling) +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +//static +void ShapeFactory::setShapeName( const uno::Reference< drawing::XShape >& xShape + , const rtl::OUString& rName ) +{ + if(!xShape.is()) + return; + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) + , uno::makeAny( rName ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +//----------------------------------------------------------------------------- + +//static +rtl::OUString ShapeFactory::getShapeName( const uno::Reference< drawing::XShape >& xShape ) +{ + rtl::OUString aRet; + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( C2U( UNO_NAME_MISC_OBJ_NAME ) ) >>= aRet; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return aRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::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( ShapeFactory::getShapeName( xShape ).equals(C2U("com.sun.star.chart2.shapes")) ) + { + xRet = uno::Reference< drawing::XShapes >( xShape, uno::UNO_QUERY ); + break; + } + } + } + } + return xRet; +} + +//----------------------------------------------------------------------------- + +uno::Reference< drawing::XShapes > ShapeFactory::getOrCreateChartRootShape( + const uno::Reference< drawing::XDrawPage>& xDrawPage ) +{ + uno::Reference< drawing::XShapes > xRet( ShapeFactory::getChartRootShape( xDrawPage ) ); + if( !xRet.is() ) + { + //create the root shape + xRet = this->createGroup2D( + uno::Reference<drawing::XShapes>( xDrawPage, uno::UNO_QUERY ) + , C2U("com.sun.star.chart2.shapes") ); + } + return xRet; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// diverse PolyPolygon create methods +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Any createPolyPolygon_Cube( + const drawing::Direction3D& rSize, double fRoundedEdge, bool bRounded = true ) +{ + DBG_ASSERT(fRoundedEdge>=0, "fRoundedEdge needs to be >= 0"); + + // always use extra points, so set percent diagonal to 0.4 which is 0% in the UI (old Chart comment) + if( fRoundedEdge == 0.0 && bRounded) + fRoundedEdge = 0.4 / 200.0; + else if(!bRounded) + fRoundedEdge = 0.0; + + //fWidthH stands for Half Width + const double fWidthH = rSize.DirectionX >=0.0? rSize.DirectionX/2.0 : -rSize.DirectionX/2.0; + const double fHeight = rSize.DirectionY; +// const double fDepth = rSize.DirectionZ >=0.0? rSize.DirectionZ : -rSize.DirectionZ ; + + const double fHeightSign = fHeight >= 0.0 ? 1.0 : -1.0; + + const double fOffset = (fWidthH * fRoundedEdge) * 1.05; // increase by 5% for safety + const bool bRoundEdges = fRoundedEdge && fOffset < fWidthH && 2.0 * fOffset < fHeightSign*fHeight; + const sal_Int32 nPointCount = bRoundEdges ? 13 : 5; + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + //*pInnerSequenceZ++ = -fDepth/2.0; + + if(nPointCount == 5) + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + } + else + { + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight; + *pInnerSequenceY++ = fHeight - fHeightSign*fOffset; + *pInnerSequenceY++ = fHeightSign*fOffset; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceY++ = 0.0; + + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH; + *pInnerSequenceX++ = fWidthH - fOffset; + *pInnerSequenceX++ = -fWidthH + fOffset; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH; + *pInnerSequenceX++ = -fWidthH + fOffset; + } + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cylinder( + double fHeight + , double fRadius + , sal_Int32& nVerticalSegmentCount ) +{ + //fHeight may be negative + DBG_ASSERT(fRadius>0, "The radius of a cylinder needs to be > 0"); + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + nVerticalSegmentCount=1; + + aPP.SequenceX.realloc(3); + aPP.SequenceY.realloc(3); + aPP.SequenceZ.realloc(3); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fY1 = 0.0; + double fY2 = fHeight; + + if( fHeight<0.0 ) + ::std::swap(fY1,fY2); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY1; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = fRadius; + *pInnerSequenceY++ = fY2; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = fY2; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any createPolyPolygon_Cone( double fHeight, double fRadius, double fTopHeight + , sal_Int32& nVerticalSegmentCount ) +{ + DBG_ASSERT(fRadius>0, "The radius of a cone needs to be > 0"); + + //for stacked charts we need cones without top -> fTopHeight != 0 resp. bTopless == true + //fTopHeight indicates the high of the cutted top only (not the full height) + bool bTopless = !::rtl::math::approxEqual( fHeight, fHeight + fTopHeight ); + + double r1= 0.0, r2 = fRadius; + if(bTopless) + // #i63212# fHeight may be negative, fTopHeight is always positive -> use fabs(fHeight) + r1 = fRadius * (fTopHeight)/(fabs(fHeight)+fTopHeight); + + nVerticalSegmentCount=1; + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(2); + aPP.SequenceY.realloc(2); + aPP.SequenceZ.realloc(2); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + double fX1 = 0.0; + double fX2 = r2; + double fX3 = r1; + + double fY1 = 0.0; + double fY2 = 0.0; + double fY3 = fHeight; + + if( fHeight<0.0 ) + { + ::std::swap(fX1,fX3); + ::std::swap(fY1,fY3); + } + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY1; + *pInnerSequenceX++ = fX1; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + //---------------------------- + + pOuterSequenceX++;pOuterSequenceY++;pOuterSequenceZ++; + pOuterSequenceX->realloc(2); + pOuterSequenceY->realloc(2); + pOuterSequenceZ->realloc(2); + + pInnerSequenceX = pOuterSequenceX->getArray(); + pInnerSequenceY = pOuterSequenceY->getArray(); + pInnerSequenceZ = pOuterSequenceZ->getArray(); + + //---------------------------- + for(sal_Int32 nN = 2; nN--;) + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceY++ = fY2; + *pInnerSequenceX++ = fX2; + + *pInnerSequenceY++ = fY3; + *pInnerSequenceX++ = fX3; + //---------------------------- + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// methods for 3D shape creation +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +uno::Reference<drawing::XShape> + ShapeFactory::createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + if( bRounded ) + { + try + { + if( xSourceProp.is() ) + { + drawing::LineStyle aLineStyle; + xSourceProp->getPropertyValue( C2U( "BorderStyle" ) ) >>= aLineStyle; + if( aLineStyle == drawing::LineStyle_SOLID ) + bRounded = false; + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + uno::Reference<drawing::XShape> xShape = impl_createCube( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree, bRounded ); + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createCube( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + double fDepth = rSize.DirectionZ; + if(fDepth<0) + fDepth*=-1.0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = bRounded ? 3 : 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , createPolyPolygon_Cube( rSize, double(nPercentDiagonal)/200.0,bRounded) ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + aM.translate(rPosition.PositionX + , rPosition.PositionY + , rPosition.PositionZ - (fDepth/2.0)); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( + xTarget, rPosition, rSize, 0.0, nRotateZAngleHundredthDegree, true ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createPyramid( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, bool bRotateZ + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap ) +{ + if( !xTarget.is() ) + return 0; + + Reference< drawing::XShapes > xGroup( ShapeFactory::createGroup3D( xTarget, rtl::OUString() ) ); + + sal_Bool bDoubleSided = false; + short nRotatedTexture = 0; + + const double fWidth = rSize.DirectionX; + const double fDepth = rSize.DirectionZ; + const double fHeight = rSize.DirectionY; + + drawing::Position3D aBottomP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth/2.0 ); + if(bRotateZ) + aBottomP1.PositionY -= fWidth/2.0; + else + aBottomP1.PositionX -= fWidth/2.0; + drawing::Position3D aBottomP2( aBottomP1 ); + if(bRotateZ) + aBottomP2.PositionY += fWidth; + else + aBottomP2.PositionX += fWidth; + drawing::Position3D aBottomP3( aBottomP2 ); + drawing::Position3D aBottomP4( aBottomP1 ); + aBottomP3.PositionZ += fDepth; + aBottomP4.PositionZ += fDepth; + + const double fTopFactor = (fTopHeight)/(fabs(fHeight)+fTopHeight); + drawing::Position3D aTopP1( rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ - fDepth*fTopFactor/2.0 ); + if(bRotateZ) + { + aTopP1.PositionY -= fWidth*fTopFactor/2.0; + aTopP1.PositionX += fHeight; + } + else + { + aTopP1.PositionX -= fWidth*fTopFactor/2.0; + aTopP1.PositionY += fHeight; + } + drawing::Position3D aTopP2( aTopP1 ); + if(bRotateZ) + aTopP2.PositionY += fWidth*fTopFactor; + else + aTopP2.PositionX += fWidth*fTopFactor; + drawing::Position3D aTopP3( aTopP2 ); + drawing::Position3D aTopP4( aTopP1 ); + aTopP3.PositionZ += fDepth*fTopFactor; + aTopP4.PositionZ += fDepth*fTopFactor; + + Stripe aStripeBottom( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + + drawing::Position3D aNormalsBottomP1( aBottomP1 ); + drawing::Position3D aNormalsBottomP2( aBottomP2 ); + drawing::Position3D aNormalsBottomP3( aBottomP3 ); + drawing::Position3D aNormalsBottomP4( aBottomP4 ); + drawing::Position3D aNormalsTopP1( aBottomP1 ); + drawing::Position3D aNormalsTopP2( aBottomP2 ); + drawing::Position3D aNormalsTopP3( aBottomP3 ); + drawing::Position3D aNormalsTopP4( aBottomP4 ); + if( bRotateZ ) + { + aNormalsTopP1.PositionX += fHeight; + aNormalsTopP2.PositionX += fHeight; + aNormalsTopP3.PositionX += fHeight; + aNormalsTopP4.PositionX += fHeight; + } + else + { + aNormalsTopP1.PositionY += fHeight; + aNormalsTopP2.PositionY += fHeight; + aNormalsTopP3.PositionY += fHeight; + aNormalsTopP4.PositionY += fHeight; + } + + bool bInvertPolygon = false; + bool bInvertNormals = false; + + if(bRotateZ) + { + //bars + if(fHeight>=0.0) + { + nRotatedTexture = 2; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP1, aBottomP4, aBottomP3, aBottomP2 ); + } + else + { + bInvertPolygon = true; + nRotatedTexture = 1; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + } + else + { + //columns + if(fHeight>=0.0) + { + bInvertPolygon = true; + nRotatedTexture = 2; + aStripeBottom = Stripe( aBottomP2, aBottomP3, aBottomP4, aBottomP1 ); + } + else + { + nRotatedTexture = 3; + bInvertNormals = true; + aStripeBottom = Stripe( aBottomP4, aBottomP3, aBottomP2, aBottomP1 ); + } + } + aStripeBottom.InvertNormal(true); + + Stripe aStripe1( aTopP2, aTopP1, aBottomP1, aBottomP2 ); + Stripe aStripe2( aTopP3, aTopP2, aBottomP2, aBottomP3 ); + Stripe aStripe3( aTopP4, aTopP3, aBottomP3, aBottomP4 ); + Stripe aStripe4( aTopP1, aTopP4, aBottomP4, aBottomP1 ); + + if( bInvertPolygon ) + { + aStripe1 = Stripe( aBottomP1, aTopP1, aTopP2, aBottomP2 ); + aStripe2 = Stripe( aBottomP2, aTopP2, aTopP3, aBottomP3 ); + aStripe3 = Stripe( aBottomP3, aTopP3, aTopP4, aBottomP4 ); + aStripe4 = Stripe( aBottomP4, aTopP4, aTopP1, aBottomP1 ); + } + + Stripe aNormalsStripe1( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP2, aNormalsTopP2 ); + Stripe aNormalsStripe2( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP3, aNormalsTopP3 ); + Stripe aNormalsStripe3( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP4, aNormalsTopP4 ); + Stripe aNormalsStripe4( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP1, aNormalsTopP1 ); + + if( bInvertNormals ) + { + aNormalsStripe1 = Stripe( aNormalsTopP2, aNormalsBottomP2, aNormalsBottomP1, aNormalsTopP1 ); + aNormalsStripe2 = Stripe( aNormalsTopP3, aNormalsBottomP3, aNormalsBottomP2, aNormalsTopP2 ); + aNormalsStripe3 = Stripe( aNormalsTopP4, aNormalsBottomP4, aNormalsBottomP3, aNormalsTopP3 ); + aNormalsStripe4 = Stripe( aNormalsTopP1, aNormalsBottomP1, aNormalsBottomP4, aNormalsTopP4 ); + } + + aStripe1.SetManualNormal( aNormalsStripe1.getNormal() ); + aStripe2.SetManualNormal( aNormalsStripe2.getNormal() ); + aStripe3.SetManualNormal( aNormalsStripe3.getNormal() ); + aStripe4.SetManualNormal( aNormalsStripe4.getNormal() ); + + const bool bFlatNormals = false; + ShapeFactory::createStripe( xGroup, aStripe1, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe2, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe3, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripe4, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + ShapeFactory::createStripe( xGroup, aStripeBottom, xSourceProp, rPropertyNameMap, bDoubleSided, nRotatedTexture, bFlatNormals ); + + return Reference< drawing::XShape >( xGroup, uno::UNO_QUERY ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::createCone( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); +} + +uno::Reference<drawing::XShape> + ShapeFactory::impl_createConeOrCylinder( + const uno::Reference<drawing::XShapes>& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , bool bCylinder ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DLatheObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + double fWidth = rSize.DirectionX/2.0; //The depth will be corrrected within Matrix + double fRadius = fWidth; //!!!!!!!! problem in drawing layer: rotation object calculates wrong needed size -> wrong camera (it's a problem with bounding boxes) + double fHeight = rSize.DirectionY; + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //PercentDiagonal + sal_Int16 nPercentDiagonal = 5; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + sal_Int32 nVerticalSegmentCount = 0; + uno::Any aPPolygon = bCylinder ? createPolyPolygon_Cylinder( + fHeight, fRadius, nVerticalSegmentCount) + : createPolyPolygon_Cone( + fHeight, fRadius, fTopHeight, nVerticalSegmentCount); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ), aPPolygon ); + + //Matrix for position + { + ::basegfx::B3DHomMatrix aM; + if(nRotateZAngleHundredthDegree!=0) + aM.rotate(0.0,0.0,-nRotateZAngleHundredthDegree/18000.00*F_PI); + //stretch the symmetric objects to given depth + aM.scale(1.0,1.0,rSize.DirectionZ/rSize.DirectionX); + aM.translate(rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + + //Segments + xProp->setPropertyValue( C2U( UNO_NAME_3D_HORZ_SEGS ) + , uno::makeAny(CHART_3DOBJECT_SEGMENTCOUNT) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_VERT_SEGS ) + , uno::makeAny((sal_Int32)nVerticalSegmentCount) );//depends on point count of the used polygon + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +void appendAndCloseBezierCoords( drawing::PolyPolygonBezierCoords& rReturn, const drawing::PolyPolygonBezierCoords& rAdd, sal_Bool bAppendInverse ) +{ + if(!rAdd.Coordinates.getLength()) + return; + sal_Int32 nAddCount = rAdd.Coordinates[0].getLength(); + if(!nAddCount) + return; + + sal_Int32 nOldCount = rReturn.Coordinates[0].getLength(); + + rReturn.Coordinates[0].realloc(nOldCount+nAddCount+1); + rReturn.Flags[0].realloc(nOldCount+nAddCount+1); + + for(sal_Int32 nN=0;nN<nAddCount; nN++ ) + { + sal_Int32 nAdd = bAppendInverse ? (nAddCount-1-nN) : nN; + rReturn.Coordinates[0][nOldCount+nN] = rAdd.Coordinates[0][nAdd]; + rReturn.Flags[0][nOldCount+nN] = rAdd.Flags[0][nAdd]; + } + + //close + rReturn.Coordinates[0][nOldCount+nAddCount] = rReturn.Coordinates[0][0]; + rReturn.Flags[0][nOldCount+nAddCount] = rReturn.Flags[0][0]; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getCircularArcBezierCoords( + double fStartAngleRadian, double fWidthAngleRadian, double fUnitRadius + , const ::basegfx::B2DHomMatrix& rTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + //at least one polygon is created using two normal and two control points + //if the angle is larger it is separated into multiple sub angles + + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + sal_Int32 nSegmentCount = static_cast< sal_Int32 >( fWidthAngleRadian/fAngleSubdivisionRadian ); + if( fWidthAngleRadian > fAngleSubdivisionRadian*nSegmentCount ) + nSegmentCount++; + + double fFirstSegmentAngle = fAngleSubdivisionRadian; + double fLastSegmentAngle = fAngleSubdivisionRadian; + if(nSegmentCount==1) + { + fFirstSegmentAngle = fWidthAngleRadian; + fLastSegmentAngle = 0.0; + } + else + { + double fFirstAngleOnSubDevision = (static_cast<sal_Int32>(fStartAngleRadian/fAngleSubdivisionRadian)+1)*fAngleSubdivisionRadian; + if( !::rtl::math::approxEqual( fStartAngleRadian, fFirstAngleOnSubDevision ) ) + fFirstSegmentAngle = fFirstAngleOnSubDevision-fStartAngleRadian; + + if(nSegmentCount>1) + { + fLastSegmentAngle = fWidthAngleRadian-fFirstSegmentAngle-fAngleSubdivisionRadian*(nSegmentCount-2); + if( fLastSegmentAngle<0 ) + nSegmentCount--; + if( fLastSegmentAngle>fAngleSubdivisionRadian ) + { + fLastSegmentAngle-=fAngleSubdivisionRadian; + nSegmentCount++; + } + } + } + + sal_Int32 nPointCount = 1 + 3*nSegmentCount; //first point of next segment equals last point of former segment + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PointSequence aPoints(nPointCount); + drawing::FlagSequence aFlags(nPointCount); + + // + + //!! applying matrix to vector does ignore translation, so it is important to use a B2DPoint here instead of B2DVector + ::basegfx::B2DPoint P0,P1,P2,P3; + ::basegfx::B2DPoint POrigin = rTransformationFromUnitCircle * ::basegfx::B2DPoint(0.0, 0.0); + + sal_Int32 nPoint=0; + double fCurrentRotateAngle = fStartAngleRadian; + for(sal_Int32 nSegment=0; nSegment<nSegmentCount; nSegment++) + { + double fCurrentSegmentAngle = fAngleSubdivisionRadian; + if(nSegment==0)//first segment gets only a smaller peace until the next subdevision + fCurrentSegmentAngle = fFirstSegmentAngle; + else if(nSegment==(nSegmentCount-1)) //the last segment gets the rest angle that does not fit into equal pieces + fCurrentSegmentAngle = fLastSegmentAngle; + + //first create untransformed points for a unit circle arc: + const double fCos = cos(fCurrentSegmentAngle/2.0); + const double fSin = sin(fCurrentSegmentAngle/2.0); + P0.setX(fCos); + P3.setX(fCos); + P0.setY(-fSin); + P3.setY(-P0.getY()); + + P1.setX((4.0-fCos)/3.0); + P2.setX(P1.getX()); + P1.setY((1.0-fCos)*(fCos-3.0)/(3.0*fSin)); + P2.setY(-P1.getY()); + //transform thus startangle equals NULL + ::basegfx::B2DHomMatrix aStart; + aStart.rotate(fCurrentSegmentAngle/2.0 + fCurrentRotateAngle ); + fCurrentRotateAngle+=fCurrentSegmentAngle; + + aStart.scale( fUnitRadius, fUnitRadius ); + + //apply given transformation to get final points + P0 = rTransformationFromUnitCircle*(aStart*P0); + P1 = rTransformationFromUnitCircle*(aStart*P1); + P2 = rTransformationFromUnitCircle*(aStart*P2); + P3 = rTransformationFromUnitCircle*(aStart*P3); + + aPoints[nPoint].X = static_cast< sal_Int32 >( P0.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P0.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P1.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P1.getY()); + aFlags[nPoint++] = drawing::PolygonFlags_CONTROL; + + aPoints[nPoint].X = static_cast< sal_Int32 >( P2.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P2.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_CONTROL; + + if(nSegment==(nSegmentCount-1)) + { + aPoints[nPoint].X = static_cast< sal_Int32 >( P3.getX()); + aPoints[nPoint].Y = static_cast< sal_Int32 >( P3.getY()); + aFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + } + } + + aReturn.Coordinates[0] = aPoints; + aReturn.Flags[0] = aFlags; + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +drawing::PolyPolygonBezierCoords getRingBezierCoords( + double fUnitCircleInnerRadius + , double fUnitCircleOuterRadius + , double fStartAngleRadian, double fWidthAngleRadian + , ::basegfx::B2DHomMatrix aTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + drawing::PolyPolygonBezierCoords aReturn = drawing::PolyPolygonBezierCoords(); + + aReturn.Coordinates = drawing::PointSequenceSequence(1); + aReturn.Flags = drawing::FlagSequenceSequence(1); + + drawing::PolyPolygonBezierCoords aOuterArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleOuterRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + aReturn.Coordinates[0] = aOuterArc.Coordinates[0]; + aReturn.Flags[0] = aOuterArc.Flags[0]; + + drawing::PolyPolygonBezierCoords aInnerArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleInnerRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + appendAndCloseBezierCoords( aReturn, aInnerArc, sal_True ); + + //fill rMarkHandlePoints + /* + { + rMarkHandlePoints.realloc(1); + rMarkHandlePoints[0].realloc(6); + sal_Int32 nHandleCount=0; + sal_Int32 nOuterArcCount = aOuterArc.Coordinates[0].getLength(); + if(nOuterArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][0]; + if(nOuterArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aOuterArc.Coordinates[0][nOuterArcCount-1]; + sal_Int32 nInnerArcCount = aInnerArc.Coordinates[0].getLength(); + if(nInnerArcCount>0) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][0]; + if(nInnerArcCount>1) + rMarkHandlePoints[0][nHandleCount++]=aInnerArc.Coordinates[0][nInnerArcCount-1]; + rMarkHandlePoints[0].realloc(nHandleCount); + } + */ + + return aReturn; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment2D( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( + C2U("com.sun.star.drawing.ClosedBezierShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/10.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + xProp->setPropertyValue( C2U( "PolyPolygonBezier" ), uno::makeAny( aCoords ) ); + + //add shape for markhandles + /* + drawing::PointSequenceSequence aMarkHandlePoints(1); to be filled within getRingBezierCoords + if( xGroup.is() ) + { + VLineProperties aHandleLineProperties; + aHandleLineProperties.LineStyle = uno::makeAny( drawing::LineStyle_NONE ); + uno::Reference< drawing::XShape > xHandleShape = + this->createLine2D( xGroup, aMarkHandlePoints, &aHandleLineProperties ); + this->setShapeName( xHandleShape, C2U("HandlesOnly") ); + } + */ + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createPieSegment( + const uno::Reference< drawing::XShapes >& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + while(fUnitCircleWidthAngleDegree>360) + fUnitCircleWidthAngleDegree -= 360.0; + while(fUnitCircleWidthAngleDegree<0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); //need to add the shape before setting of properties + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = F_PI/32.0; + + drawing::PolyPolygonBezierCoords aCoords = getRingBezierCoords( + fUnitCircleInnerRadius, fUnitCircleOuterRadius + , fUnitCircleStartAngleDegree*F_PI/180.0, fUnitCircleWidthAngleDegree*F_PI/180.0 + , aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + drawing::PolyPolygonShape3D aPoly( BezierToPoly(aCoords) ); + ShapeFactory::closePolygon( aPoly ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( aPoly ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //Reduced lines + xProp->setPropertyValue( C2U( UNO_NAME_3D_REDUCED_LINE_GEOMETRY ) + , uno::makeAny((sal_Bool)sal_True) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + + //TextureProjectionMode + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_X ) + , uno::makeAny( drawing::TextureProjectionMode_PARALLEL ) ); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTURE_PROJ_Y ) + , uno::makeAny( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------ + +uno::Reference< drawing::XShape > + ShapeFactory::createStripe( const uno::Reference< drawing::XShapes >& xTarget + , const Stripe& rStripe + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , sal_Bool bDoubleSided + , short nRotatedTexture + , bool bFlatNormals ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , rStripe.getPolyPolygonShape3D() ); + + //TexturePolygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_TEXTUREPOLYGON3D ) + , rStripe.getTexturePolygon( nRotatedTexture ) ); + + //Normals Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALSPOLYGON3D ) + , rStripe.getNormalsPolygon() ); + //NormalsKind + if(bFlatNormals) + xProp->setPropertyValue( C2U( UNO_NAME_3D_NORMALS_KIND ) + , uno::makeAny( drawing::NormalsKind_FLAT ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)false) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny(bDoubleSided) ); + + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( xProp, xSourceProp, rPropertyNameMap ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon + , double fDepth ) +{ + if( !xTarget.is() ) + return 0; + + if( !rPolyPolygon.SequenceX.getLength()) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DExtrudeObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //depth + xProp->setPropertyValue( C2U( UNO_NAME_3D_EXTRUDE_DEPTH ) + , uno::makeAny((sal_Int32)fDepth) ); + + //PercentDiagonal + sal_Int16 nPercentDiagonal = 0; + xProp->setPropertyValue( C2U( UNO_NAME_3D_PERCENT_DIAGONAL ) + , uno::makeAny( nPercentDiagonal ) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPolyPolygon ) ); + + //DoubleSided + xProp->setPropertyValue( C2U( UNO_NAME_3D_DOUBLE_SIDED ) + , uno::makeAny( (sal_Bool)true) ); + + //the z component of the polygon is now ignored by the drawing layer, + //so we nned to translate the object via transformation matrix + + //Matrix for position + if( rPolyPolygon.SequenceZ.getLength()&& rPolyPolygon.SequenceZ[0].getLength() ) + { + ::basegfx::B3DHomMatrix aM; + aM.translate( 0 + , 0 + , rPolyPolygon.SequenceZ[0][0] ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(aHM) ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createArea2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPolyPolygon ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //UNO_NAME_POLYGON "Polygon" drawing::PointSequence* + drawing::PointSequenceSequence aPoints( PolyToPointSequence(rPolyPolygon) ); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //ZOrder + //an area should always be behind other shapes + xProp->setPropertyValue( C2U( UNO_NAME_MISC_OBJ_ZORDER ) + , uno::makeAny( sal_Int32(0) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +enum SymbolType { SYMBOL_SQUARE=0 + , SYMBOL_DIAMOND + , SYMBOL_ARROW_DOWN + , SYMBOL_ARROW_UP + , SYMBOL_ARROW_RIGHT + , SYMBOL_ARROW_LEFT + , SYMBOL_BOWTIE + , SYMBOL_SANDGLASS + , SYMBOL_COUNT + }; + +sal_Int32 ShapeFactory::getSymbolCount() +{ + return SYMBOL_COUNT; +} + +drawing::PolyPolygonShape3D createPolyPolygon_Symbol( const drawing::Position3D& rPos + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol ) +{ + if(nStandardSymbol<0) + nStandardSymbol*=-1; + nStandardSymbol = nStandardSymbol%ShapeFactory::getSymbolCount(); + SymbolType eSymbolType=static_cast<SymbolType>(nStandardSymbol); + + const double& fX = rPos.PositionX; + const double& fY = rPos.PositionY; + + const double fWidthH = rSize.DirectionX/2.0; //fWidthH stands for Half Width + const double fHeightH = rSize.DirectionY/2.0; //fHeightH stands for Half Height + + sal_Int32 nPointCount = 4; //all arrow symbols only need 4 points + switch( eSymbolType ) + { + case SYMBOL_SQUARE: + case SYMBOL_DIAMOND: + case SYMBOL_BOWTIE: + case SYMBOL_SANDGLASS: + nPointCount = 5; + break; + default: + break; + } + + //-------------------------------------- + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(nPointCount); + pOuterSequenceY->realloc(nPointCount); + pOuterSequenceZ->realloc(nPointCount); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + for(sal_Int32 nN = nPointCount; nN--;) + *pInnerSequenceZ++ = 0.0; + + switch(eSymbolType) + { + case SYMBOL_ARROW_UP: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_ARROW_DOWN: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_RIGHT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_ARROW_LEFT: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + case SYMBOL_BOWTIE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + case SYMBOL_SANDGLASS: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + break; + } + case SYMBOL_DIAMOND: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY; + + *pInnerSequenceX++ = fX; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY; + break; + } + default: //case SYMBOL_SQUARE: + { + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY+fHeightH; + + *pInnerSequenceX++ = fX+fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + + *pInnerSequenceX++ = fX-fWidthH; + *pInnerSequenceY++ = fY-fHeightH; + break; + } + } + //return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); + return aPP; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createSymbol2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor + , sal_Int32 nFillColor ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::PointSequenceSequence aPoints( PolyToPointSequence( + createPolyPolygon_Symbol( rPosition, rSize, nStandardSymbol ) )); + + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( aPoints ) ); + + //LineColor + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , uno::makeAny( nBorderColor ) ); + + //FillColor + xProp->setPropertyValue( C2U( UNO_NAME_FILLCOLOR ) + , uno::makeAny( nFillColor ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createGraphic2D( + const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , const uno::Reference< graphic::XGraphic >& xGraphic ) +{ + if( !xTarget.is() || !xGraphic.is() ) + return 0; + + // @todo: change this to a rectangle shape with a fill bitmap for + // performance reasons (ask AW, said CL) + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GraphicObjectShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + // assume position is upper left corner. Transform to center. + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->setPropertyValue( C2U("Graphic"), uno::makeAny( xGraphic )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup2D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create and add to target + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.GroupShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + {//workaround + //need this null size as otherwise empty group shapes where painted with a gray border + xShape->setSize(awt::Size(0,0)); + } + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShapes > + ShapeFactory::createGroup3D( const uno::Reference< drawing::XShapes >& xTarget + , ::rtl::OUString aName ) +{ + if( !xTarget.is() ) + return 0; + try + { + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DSceneObject" ) ), uno::UNO_QUERY ); + + xTarget->add(xShape); + + //it is necessary to set the transform matrix to initialize the scene properly (bug #106316#) + //otherwise all objects which are placed into this Group will not be visible + //the following should be unnecessary after a the bug is fixed + { + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + ::basegfx::B3DHomMatrix aM; + xProp->setPropertyValue( C2U( UNO_NAME_3D_TRANSFORM_MATRIX ) + , uno::makeAny(B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + //set name + if(aName.getLength()) + setShapeName( xShape , aName ); + + //return + uno::Reference< drawing::XShapes > xShapes = + uno::Reference<drawing::XShapes>( xShape, uno::UNO_QUERY ); + return xShapes; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createCircle2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize ) +{ + if( !xTarget.is() ) + return 0; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.EllipseShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + try + { + drawing::Position3D aCenterPosition( + rPosition.PositionX - (rSize.DirectionX / 2.0), + rPosition.PositionY - (rSize.DirectionY / 2.0), + rPosition.PositionZ ); + xShape->setPosition( Position3DToAWTPoint( aCenterPosition )); + xShape->setSize( Direction3DToAWTSize( rSize )); + } + catch( const uno::Exception & e ) + { + ASSERT_EXCEPTION( e ); + } + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + drawing::CircleKind eKind = drawing::CircleKind_FULL; + xProp->setPropertyValue( C2U( UNO_NAME_CIRCKIND ) + , uno::makeAny( eKind ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine3D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PolyPolygonShape3D& rPoints + , const VLineProperties& rLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.SequenceX.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.Shape3DPolygonObject") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_3D_POLYPOLYGON3D ) + , uno::makeAny( rPoints ) ); + + //LineOnly + xProp->setPropertyValue( C2U( UNO_NAME_3D_LINEONLY ) + , uno::makeAny( (sal_Bool)true ) ); + + //Transparency + if(rLineProperties.Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , rLineProperties.Transparence ); + + //LineStyle + if(rLineProperties.LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , rLineProperties.LineStyle ); + + //LineWidth + if(rLineProperties.Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , rLineProperties.Width ); + + //LineColor + if(rLineProperties.Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , rLineProperties.Color ); + //, uno::makeAny( sal_Int32( Color(COL_RED).GetColor()) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createLine2D( const uno::Reference< drawing::XShapes >& xTarget + , const drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return 0; + + if(!rPoints.getLength()) + return NULL; + + //create shape + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + //"com.sun.star.drawing.LineShape") ), uno::UNO_QUERY ); + "com.sun.star.drawing.PolyLineShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyLinePathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonPathShape") ), uno::UNO_QUERY ); + //"com.sun.star.drawing.PolyPolygonShape") ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set properties + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xProp.is(), "created shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + //Polygon + xProp->setPropertyValue( C2U( UNO_NAME_POLYPOLYGON ) + , uno::makeAny( rPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINETRANSPARENCE ) + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINESTYLE ) + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINEWIDTH ) + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xProp->setPropertyValue( C2U( UNO_NAME_LINECOLOR ) + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xProp->setPropertyValue( C2U( "LineDashName" ) + , pLineProperties->DashName ); + } + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +uno::Any ShapeFactory::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; +} + +void ShapeFactory::makeShapeInvisible( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + DBG_ASSERT(xShapeProp.is(), "created shape offers no XPropertySet"); + if( xShapeProp.is()) + { + try + { + xShapeProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( drawing::LineStyle_NONE )); + xShapeProp->setPropertyValue( C2U("FillStyle"), uno::makeAny( drawing::FillStyle_NONE )); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +uno::Reference< drawing::XShape > ShapeFactory::createInvisibleRectangle( + const uno::Reference< drawing::XShapes >& xTarget + , const awt::Size& rSize ) +{ + try + { + if(!xTarget.is()) + return 0; + + uno::Reference< drawing::XShape > xShape( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + if( xTarget.is() && xShape.is()) + { + xTarget->add( xShape ); + ShapeFactory::makeShapeInvisible( xShape ); + xShape->setSize( rSize ); + } + return xShape; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return 0; +} + +uno::Reference< drawing::XShape > + ShapeFactory::createText( const uno::Reference< drawing::XShapes >& xTarget + , const ::rtl::OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const uno::Any& rATransformation ) +{ + if( !xTarget.is() ) + return 0; + + if(!rText.getLength()) + return 0; + + //create shape and add to page + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.TextShape" ) ), uno::UNO_QUERY ); + xTarget->add(xShape); + + //set text + uno::Reference< text::XTextRange > xTextRange( xShape, uno::UNO_QUERY ); + if( xTextRange.is() ) + xTextRange->setString( rText ); + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + if( xProp.is() ) + { + //set properties + PropertyMapper::setMultiProperties( rPropNames, rPropValues, xProp ); + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + try + { + xProp->setPropertyValue( C2U( "Transformation" ), rATransformation ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + return xShape; +} + +//static +rtl::OUString ShapeFactory::getStackedString( const rtl::OUString& rString, bool bStacked ) +{ + sal_Int32 nLen = rString.getLength(); + if(!bStacked || !nLen) + return rString; + + rtl::OUStringBuffer aStackStr; + rtl::OUStringBuffer aSource(rString); + + //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( sal_Unicode('\r') ); + aStackStr.append( aSource.charAt( nPosSrc ) ); + } + return aStackStr.makeStringAndClear(); +} + +//static +bool ShapeFactory::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; +} + +//static +bool ShapeFactory::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)); +} + +//static +void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) +{ + DBG_ASSERT( rPoly.SequenceX.getLength() <= 1, "ShapeFactory::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 ); +} + +//static +awt::Size ShapeFactory::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; +} + +//static +awt::Point ShapeFactory::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; +} + +//static +::basegfx::B2IRectangle ShapeFactory::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; + +} + +//static +awt::Size ShapeFactory::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 ShapeFactory::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 ); + } + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/Stripe.cxx b/chart2/source/view/main/Stripe.cxx new file mode 100644 index 000000000000..2df78e2a8e91 --- /dev/null +++ b/chart2/source/view/main/Stripe.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "Stripe.hxx" +#include "CommonConverters.hxx" +#include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/DoubleSequence.hpp> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> + +using namespace ::com::sun::star; + +//............................................................................. +namespace chart +{ +//............................................................................. + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Direction3D& rDirectionToPoint2 + , const drawing::Direction3D& rDirectionToPoint4 ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint1+rDirectionToPoint2) + , m_aPoint3(m_aPoint2+rDirectionToPoint4) + , m_aPoint4(rPoint1+rDirectionToPoint4) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ +} + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Position3D& rPoint2 + , double fDepth ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint2) + , m_aPoint3(rPoint2) + , m_aPoint4(rPoint1) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ + m_aPoint3.PositionZ += fDepth; + m_aPoint4.PositionZ += fDepth; +} + +Stripe::Stripe( const drawing::Position3D& rPoint1 + , const drawing::Position3D& rPoint2 + , const drawing::Position3D& rPoint3 + , const drawing::Position3D& rPoint4 ) + : m_aPoint1(rPoint1) + , m_aPoint2(rPoint2) + , m_aPoint3(rPoint3) + , m_aPoint4(rPoint4) + , m_bInvertNormal(false) + , m_bManualNormalSet(false) +{ +} + +void Stripe::SetManualNormal( const drawing::Direction3D& rNormal ) +{ + m_aManualNormal = rNormal; + m_bManualNormalSet = true; +} + +void Stripe::InvertNormal( bool bInvertNormal ) +{ + m_bInvertNormal = bInvertNormal; +} + +uno::Any Stripe::getPolyPolygonShape3D() const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + *pInnerSequenceX++ = m_aPoint1.PositionX; + *pInnerSequenceY++ = m_aPoint1.PositionY; + *pInnerSequenceZ++ = m_aPoint1.PositionZ; + + *pInnerSequenceX++ = m_aPoint2.PositionX; + *pInnerSequenceY++ = m_aPoint2.PositionY; + *pInnerSequenceZ++ = m_aPoint2.PositionZ; + + *pInnerSequenceX++ = m_aPoint3.PositionX; + *pInnerSequenceY++ = m_aPoint3.PositionY; + *pInnerSequenceZ++ = m_aPoint3.PositionZ; + + *pInnerSequenceX++ = m_aPoint4.PositionX; + *pInnerSequenceY++ = m_aPoint4.PositionY; + *pInnerSequenceZ++ = m_aPoint4.PositionZ; + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +drawing::Direction3D Stripe::getNormal() const +{ + drawing::Direction3D aRet(1.0,0.0,0.0); + + if( m_bManualNormalSet ) + aRet = m_aManualNormal; + else + { + ::basegfx::B3DPolygon aPolygon3D; + aPolygon3D.append(Position3DToB3DPoint( m_aPoint1 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint2 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint3 )); + aPolygon3D.append(Position3DToB3DPoint( m_aPoint4 )); + ::basegfx::B3DVector aNormal(::basegfx::tools::getNormal(aPolygon3D)); + aRet = B3DVectorToDirection3D(aNormal); + } + + if( m_bInvertNormal ) + { + aRet.DirectionX *= -1.0; + aRet.DirectionY *= -1.0; + aRet.DirectionZ *= -1.0; + } + return aRet; +} + +uno::Any Stripe::getNormalsPolygon() const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + drawing::Direction3D aNormal( getNormal() ); + + for(sal_Int32 nN=4; --nN; ) + { + *pInnerSequenceX++ = aNormal.DirectionX; + *pInnerSequenceY++ = aNormal.DirectionY; + *pInnerSequenceZ++ = aNormal.DirectionZ; + } + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +uno::Any Stripe::getTexturePolygon( short nRotatedTexture ) const +{ + drawing::PolyPolygonShape3D aPP; + + aPP.SequenceX.realloc(1); + aPP.SequenceY.realloc(1); + aPP.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPP.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPP.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPP.SequenceZ.getArray(); + + pOuterSequenceX->realloc(4); + pOuterSequenceY->realloc(4); + pOuterSequenceZ->realloc(4); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + if( nRotatedTexture==0 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==1 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==2 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==3 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==4 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==5 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==6 ) + { + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + } + else if( nRotatedTexture==7 ) + { + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 1.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 0.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + + *pInnerSequenceX++ = 1.0; + *pInnerSequenceY++ = 0.0; + *pInnerSequenceZ++ = 0.0; + } + + return uno::Any( &aPP, ::getCppuType((const drawing::PolyPolygonShape3D*)0) ); +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx new file mode 100644 index 000000000000..8bb6a11b4baf --- /dev/null +++ b/chart2/source/view/main/VDataSeries.cxx @@ -0,0 +1,986 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "VDataSeries.hxx" +#include "ObjectIdentifier.hxx" +#include "macros.hxx" +#include "CommonConverters.hxx" +#include "LabelPositionHelper.hxx" +#include "ChartTypeHelper.hxx" +#include "ContainerHelper.hxx" +#include "DataSeriesHelper.hxx" +#include "RegressionCurveHelper.hxx" + +#include <com/sun/star/chart/MissingValueTreatment.hpp> +#include <com/sun/star/chart2/Symbol.hpp> + +//#include "CommonConverters.hxx" +#include <rtl/math.hxx> +#include <tools/debug.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/chart2/data/XDataSource.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +void VDataSequence::init( const uno::Reference< data::XDataSequence >& xModel ) +{ + Model = xModel; + Doubles = DataSequenceToDoubleSequence( xModel ); +} + +bool VDataSequence::is() const +{ + return Model.is(); +} +void VDataSequence::clear() +{ + Model = NULL; + Doubles.realloc(0); +} + +double VDataSequence::getValue( sal_Int32 index ) const +{ + if( 0<=index && index<Doubles.getLength() ) + return Doubles[index]; + else + { + double fNan; + ::rtl::math::setNan( & fNan ); + return fNan; + } +} + +sal_Int32 VDataSequence::detectNumberFormatKey( sal_Int32 index ) const +{ + sal_Int32 nNumberFormatKey = -1; + + // -1 is allowed and means a key for the whole sequence + if( -1<=index && index<Doubles.getLength() && + Model.is()) + { + nNumberFormatKey = Model->getNumberFormatKeyByIndex( index ); + } + + return nNumberFormatKey; +} + +sal_Int32 VDataSequence::getLength() const +{ + return Doubles.getLength(); +} + +namespace +{ +struct lcl_LessXOfPoint +{ + inline bool operator() ( const std::vector< double >& first, + const std::vector< double >& second ) + { + if( first.size() > 0 && second.size() > 0 ) + { + return first[0]<second[0]; + } + return false; + } +}; + +void lcl_clearIfNoValuesButTextIsContained( VDataSequence& rData, const uno::Reference<data::XDataSequence>& xDataSequence ) +{ + //#i71686#, #i101968#, #i102428# + sal_Int32 nCount = rData.Doubles.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + if( !::rtl::math::isNan( rData.Doubles[i] ) ) + return; + } + //no double value is countained + //is there any text? + uno::Sequence< rtl::OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) ); + sal_Int32 nTextCount = aStrings.getLength(); + for( sal_Int32 j = 0; j < nTextCount; ++j ) + { + if( aStrings[j].getLength() ) + { + rData.clear(); + return; + } + } + //no content at all +} + +void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment ) +{ + if( nMissingValueTreatment == ::com::sun::star::chart::MissingValueTreatment::USE_ZERO + && (::rtl::math::isNan(rfValue) || ::rtl::math::isInf(rfValue)) ) + rfValue = 0.0; +} + +} + +VDataSeries::VDataSeries( const uno::Reference< XDataSeries >& xDataSeries ) + : m_nPolygonIndex(0) + , m_fLogicMinX(0.0) + , m_fLogicMaxX(0.0) + , m_fLogicZPos(0.0) + , m_xGroupShape(NULL) + , m_xLabelsGroupShape(NULL) + , m_xErrorBarsGroupShape(NULL) + , m_xFrontSubGroupShape(NULL) + , m_xBackSubGroupShape(NULL) + , m_xDataSeries(xDataSeries) + , m_aDataSequences() + , m_nPointCount(0) + + , m_aValues_X() + , m_aValues_Y() + , m_aValues_Z() + , m_aValues_Y_Min() + , m_aValues_Y_Max() + , m_aValues_Y_First() + , m_aValues_Y_Last() + , m_aValues_Bubble_Size() + , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y) + + , m_fYMeanValue(1.0) + + , m_aAttributedDataPointIndexList() + + , m_eStackingDirection(StackingDirection_NO_STACKING) + , m_nAxisIndex(0) + , m_bConnectBars(sal_False) + , m_bGroupBarsPerAxis(sal_True) + , m_nStartingAngle(90) + + , m_aSeriesParticle() + , m_aCID() + , m_aPointCID_Stub() + , m_aLabelCID_Stub() + + , m_nGlobalSeriesIndex(0) + + , m_apLabel_Series(NULL) + , m_apLabelPropNames_Series(NULL) + , m_apLabelPropValues_Series(NULL) + , m_apSymbolProperties_Series(NULL) + + , m_apLabel_AttributedPoint(NULL) + , m_apLabelPropNames_AttributedPoint(NULL) + , m_apLabelPropValues_AttributedPoint(NULL) + , m_apSymbolProperties_AttributedPoint(NULL) + , m_apSymbolProperties_InvisibleSymbolForSelection(NULL) + , m_nCurrentAttributedPoint(-1) + , m_nMissingValueTreatment(::com::sun::star::chart::MissingValueTreatment::LEAVE_GAP) + , m_bAllowPercentValueInDataLabel(false) +{ + ::rtl::math::setNan( & m_fYMeanValue ); + + uno::Reference<data::XDataSource> xDataSource = + uno::Reference<data::XDataSource>( xDataSeries, uno::UNO_QUERY ); + + m_aDataSequences = xDataSource->getDataSequences(); + + for(sal_Int32 nN = m_aDataSequences.getLength();nN--;) + { + if(!m_aDataSequences[nN].is()) + continue; + uno::Reference<data::XDataSequence> xDataSequence( m_aDataSequences[nN]->getValues()); + uno::Reference<beans::XPropertySet> xProp(xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + uno::Any aARole = xProp->getPropertyValue( C2U( "Role" ) ); + rtl::OUString aRole; + aARole >>= aRole; + + if( aRole.equals(C2U("values-x")) ) + { + m_aValues_X.init( xDataSequence ); + lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence ); + } + else if( aRole.equals(C2U("values-y")) ) + m_aValues_Y.init( xDataSequence ); + else if( aRole.equals(C2U("values-min")) ) + m_aValues_Y_Min.init( xDataSequence ); + else if( aRole.equals(C2U("values-max")) ) + m_aValues_Y_Max.init( xDataSequence ); + else if( aRole.equals(C2U("values-first")) ) + m_aValues_Y_First.init( xDataSequence ); + else if( aRole.equals(C2U("values-last")) ) + m_aValues_Y_Last.init( xDataSequence ); + else if( aRole.equals(C2U("values-size")) ) + m_aValues_Bubble_Size.init( xDataSequence ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + } + + //determine the point count + m_nPointCount = m_aValues_Y.getLength(); + { + if( m_nPointCount < m_aValues_Bubble_Size.getLength() ) + m_nPointCount = m_aValues_Bubble_Size.getLength(); + if( m_nPointCount < m_aValues_Y_Min.getLength() ) + m_nPointCount = m_aValues_Y_Min.getLength(); + if( m_nPointCount < m_aValues_Y_Max.getLength() ) + m_nPointCount = m_aValues_Y_Max.getLength(); + if( m_nPointCount < m_aValues_Y_First.getLength() ) + m_nPointCount = m_aValues_Y_First.getLength(); + if( m_nPointCount < m_aValues_Y_Last.getLength() ) + m_nPointCount = m_aValues_Y_Last.getLength(); + } + + uno::Reference<beans::XPropertySet> xProp(xDataSeries, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + //get AttributedDataPoints + xProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= m_aAttributedDataPointIndexList; + + xProp->getPropertyValue( C2U( "StackingDirection" ) ) >>= m_eStackingDirection; + + xProp->getPropertyValue( C2U( "AttachedAxisIndex" ) ) >>= m_nAxisIndex; + if(m_nAxisIndex<0) + m_nAxisIndex=0; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } +} + +VDataSeries::~VDataSeries() +{ +} + +void VDataSeries::doSortByXValues() +{ + if( m_aValues_X.is() && m_aValues_X.Doubles.getLength() ) + { + //prepare a vector vor sorting + std::vector< ::std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of athe point + double fNan; + ::rtl::math::setNan( & fNan ); + sal_Int32 nPointIndex = 0; + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + std::vector< double > aSinglePoint; + aSinglePoint.push_back( (nPointIndex < m_aValues_X.Doubles.getLength()) ? m_aValues_X.Doubles[nPointIndex] : fNan ); + aSinglePoint.push_back( (nPointIndex < m_aValues_Y.Doubles.getLength()) ? m_aValues_Y.Doubles[nPointIndex] : fNan ); + aTmp.push_back( aSinglePoint ); + } + + //do sort + std::sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() ); + + //fill the sorted points back to the mambers + m_aValues_X.Doubles.realloc( m_nPointCount ); + m_aValues_Y.Doubles.realloc( m_nPointCount ); + + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + m_aValues_X.Doubles[nPointIndex]=aTmp[nPointIndex][0]; + m_aValues_Y.Doubles[nPointIndex]=aTmp[nPointIndex][1]; + } + } +} + +uno::Reference< XDataSeries > VDataSeries::getModel() const +{ + return m_xDataSeries; +} + +void VDataSeries::releaseShapes() +{ + m_xGroupShape.set(0); + m_xLabelsGroupShape.set(0); + m_xErrorBarsGroupShape.set(0); + m_xFrontSubGroupShape.set(0); + m_xBackSubGroupShape.set(0); + + m_aPolyPolygonShape3D.SequenceX.realloc(0); + m_aPolyPolygonShape3D.SequenceY.realloc(0); + m_aPolyPolygonShape3D.SequenceZ.realloc(0); + m_nPolygonIndex = 0; +} + +void VDataSeries::setCategoryXAxis() +{ + m_aValues_X.clear(); + m_bAllowPercentValueInDataLabel = true; +} + +void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex ) +{ + m_nGlobalSeriesIndex = nGlobalSeriesIndex; +} + +void VDataSeries::setParticle( const rtl::OUString& rSeriesParticle ) +{ + m_aSeriesParticle = rSeriesParticle; + + //get CID + m_aCID = ObjectIdentifier::createClassifiedIdentifierForParticle( m_aSeriesParticle ); + m_aPointCID_Stub = ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT, m_aSeriesParticle ); + + m_aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABEL, ::rtl::OUString(), getLabelsCID() ); +} +rtl::OUString VDataSeries::getSeriesParticle() const +{ + return m_aSeriesParticle; +} +rtl::OUString VDataSeries::getCID() const +{ + return m_aCID; +} +rtl::OUString VDataSeries::getPointCID_Stub() const +{ + return m_aPointCID_Stub; +} +rtl::OUString VDataSeries::getErrorBarsCID() const +{ + rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_ERRORS ) ); + aChildParticle+=(C2U("=")); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +rtl::OUString VDataSeries::getLabelsCID() const +{ + rtl::OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) ); + aChildParticle+=(C2U("=")); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +rtl::OUString VDataSeries::getLabelCID_Stub() const +{ + return m_aLabelCID_Stub; +} +rtl::OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const +{ + rtl::OUString aRet; + aRet = ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine ); + return aRet; +} + +rtl::OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const +{ + rtl::OUString aRet; + aRet = ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex ); + return aRet; +} +void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize ) +{ + m_aReferenceSize = rPageRefSize; +} + +StackingDirection VDataSeries::getStackingDirection() const +{ + return m_eStackingDirection; +} +sal_Int32 VDataSeries::getAttachedAxisIndex() const +{ + return m_nAxisIndex; +} +void VDataSeries::setConnectBars( sal_Bool bConnectBars ) +{ + m_bConnectBars = bConnectBars; +} +sal_Bool VDataSeries::getConnectBars() const +{ + return m_bConnectBars; +} +void VDataSeries::setGroupBarsPerAxis( sal_Bool bGroupBarsPerAxis ) +{ + m_bGroupBarsPerAxis = bGroupBarsPerAxis; +} +sal_Bool VDataSeries::getGroupBarsPerAxis() const +{ + return m_bGroupBarsPerAxis; +} + +void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle ) +{ + m_nStartingAngle = nStartingAngle; +} +sal_Int32 VDataSeries::getStartingAngle() const +{ + return m_nStartingAngle; +} + +void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex ) +{ + if( nAttachedAxisIndex < 0 ) + nAttachedAxisIndex = 0; + m_nAxisIndex = nAttachedAxisIndex; +} + +sal_Int32 VDataSeries::getTotalPointCount() const +{ + return m_nPointCount; +} + +double VDataSeries::getXValue( sal_Int32 index ) const +{ + double fRet = 0.0; + if(m_aValues_X.is()) + { + if( 0<=index && index<m_aValues_X.getLength() ) + fRet = m_aValues_X.Doubles[index]; + else + ::rtl::math::setNan( &fRet ); + } + else + { + // #i70133# always return correct X position - needed for short data series + if( 0<=index /*&& index < m_nPointCount*/ ) + fRet = index+1;//first category (index 0) matches with real number 1.0 + else + ::rtl::math::setNan( &fRet ); + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +double VDataSeries::getYValue( sal_Int32 index ) const +{ + double fRet = 0.0; + if(m_aValues_Y.is()) + { + if( 0<=index && index<m_aValues_Y.getLength() ) + fRet = m_aValues_Y.Doubles[index]; + else + ::rtl::math::setNan( &fRet ); + } + else + { + // #i70133# always return correct X position - needed for short data series + if( 0<=index /*&& index < m_nPointCount*/ ) + fRet = index+1;//first category (index 0) matches with real number 1.0 + else + ::rtl::math::setNan( &fRet ); + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +double VDataSeries::getY_Min( sal_Int32 index ) const +{ + return m_aValues_Y_Min.getValue( index ); +} +double VDataSeries::getY_Max( sal_Int32 index ) const +{ + return m_aValues_Y_Max.getValue( index ); +} +double VDataSeries::getY_First( sal_Int32 index ) const +{ + return m_aValues_Y_First.getValue( index ); +} +double VDataSeries::getY_Last( sal_Int32 index ) const +{ + return m_aValues_Y_Last.getValue( index ); +} +double VDataSeries::getBubble_Size( sal_Int32 index ) const +{ + return m_aValues_Bubble_Size.getValue( index ); +} + +bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + rtl::OUString aPropName( bForPercentage ? C2U( "PercentageNumberFormat" ) : C2U( "NumberFormat" ) ); + bool bHasNumberFormat = false; + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex )); + sal_Int32 nNumberFormat = -1; + if( xPointProp.is() && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat) ) + bHasNumberFormat = true; + return bHasNumberFormat; +} +sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + rtl::OUString aPropName( bForPercentage ? C2U( "PercentageNumberFormat" ) : C2U( "NumberFormat" ) ); + sal_Int32 nNumberFormat = -1; + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( nPointIndex )); + if( xPointProp.is() ) + xPointProp->getPropertyValue(aPropName) >>= nNumberFormat; + return nNumberFormat; +} +void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( const rtl::OUString& rRole ) +{ + if( rRole.equals(C2U("values-y")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y; + else if( rRole.equals(C2U("values-size")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size; + else if( rRole.equals(C2U("values-min")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min; + else if( rRole.equals(C2U("values-max")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max; + else if( rRole.equals(C2U("values-first")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First; + else if( rRole.equals(C2U("values-last")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last; + else if( rRole.equals(C2U("values-x")) ) + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X; +} +bool VDataSeries::shouldLabelNumberFormatKeyBeDetectedFromYAxis() const +{ + if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_Bubble_Size ) + return false; + else if( m_pValueSequenceForDataLabelNumberFormatDetection == &m_aValues_X ) + return false; + return true; +} +sal_Int32 VDataSeries::detectNumberFormatKey( sal_Int32 index ) const +{ + sal_Int32 nRet = 0; + if( m_pValueSequenceForDataLabelNumberFormatDetection ) + nRet = m_pValueSequenceForDataLabelNumberFormatDetection->detectNumberFormatKey( index ); + return nRet; +} + +sal_Int32 VDataSeries::getLabelPlacement( sal_Int32 nPointIndex, const uno::Reference< chart2::XChartType >& xChartType, sal_Int32 nDimensionCount, sal_Bool bSwapXAndY ) const +{ + sal_Int32 nLabelPlacement=0; + try + { + uno::Reference< beans::XPropertySet > xPointProps( this->getPropertiesOfPoint( nPointIndex ) ); + if( xPointProps.is() ) + xPointProps->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement; + + //ensure that the set label placement is supported by this charttype + + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, nDimensionCount, bSwapXAndY, m_xDataSeries ) ); + + for( sal_Int32 nN = 0; nN < aAvailablePlacements.getLength(); nN++ ) + if( aAvailablePlacements[nN] == nLabelPlacement ) + return nLabelPlacement; //ok + + //otherwise use the first supported one + if( aAvailablePlacements.getLength() ) + { + nLabelPlacement = aAvailablePlacements[0]; + return nLabelPlacement; + } + + DBG_ERROR("no label placement supported"); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + return nLabelPlacement; +} + +double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMin=0.0; + ::rtl::math::setInf(&fMin, false); + + if( !m_aValues_Y.is() && + (m_aValues_Y_Min.is() || m_aValues_Y_Max.is() + || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) ) + { + double fY_Min = getY_Min( index ); + double fY_Max = getY_Max( index ); + double fY_First = getY_First( index ); + double fY_Last = getY_Last( index ); + + if(fMin>fY_First) + fMin=fY_First; + if(fMin>fY_Last) + fMin=fY_Last; + if(fMin>fY_Min) + fMin=fY_Min; + if(fMin>fY_Max) + fMin=fY_Max; + } + else + { + double fY = getYValue( index ); + if(fMin>fY) + fMin=fY; + } + + if( ::rtl::math::isInf(fMin) ) + ::rtl::math::setNan(&fMin); + + return fMin; +} + +double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMax=0.0; + ::rtl::math::setInf(&fMax, true); + + if( !m_aValues_Y.is() && + (m_aValues_Y_Min.is() || m_aValues_Y_Max.is() + || m_aValues_Y_First.is() || m_aValues_Y_Last.is() ) ) + { + double fY_Min = getY_Min( index ); + double fY_Max = getY_Max( index ); + double fY_First = getY_First( index ); + double fY_Last = getY_Last( index ); + + if(fMax<fY_First) + fMax=fY_First; + if(fMax<fY_Last) + fMax=fY_Last; + if(fMax<fY_Min) + fMax=fY_Min; + if(fMax<fY_Max) + fMax=fY_Max; + } + else + { + double fY = getYValue( index ); + if(fMax<fY) + fMax=fY; + } + + if( ::rtl::math::isInf(fMax) ) + ::rtl::math::setNan(&fMax); + + return fMax; +} + +uno::Sequence< double > VDataSeries::getAllX() const +{ + if(!m_aValues_X.is() && !m_aValues_X.getLength() && m_nPointCount) + { + //init x values from category indexes + //first category (index 0) matches with real number 1.0 + m_aValues_X.Doubles.realloc( m_nPointCount ); + for(sal_Int32 nN=m_aValues_X.getLength();nN--;) + m_aValues_X.Doubles[nN] = nN+1; + } + return m_aValues_X.Doubles; +} + +uno::Sequence< double > VDataSeries::getAllY() const +{ + if(!m_aValues_Y.is() && !m_aValues_Y.getLength() && m_nPointCount) + { + //init y values from indexes + //first y-value (index 0) matches with real number 1.0 + m_aValues_Y.Doubles.realloc( m_nPointCount ); + for(sal_Int32 nN=m_aValues_Y.getLength();nN--;) + m_aValues_Y.Doubles[nN] = nN+1; + } + return m_aValues_Y.Doubles; +} + +double VDataSeries::getYMeanValue() const +{ + if( ::rtl::math::isNan( m_fYMeanValue ) ) + { + uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( C2U("com.sun.star.chart2.MeanValueRegressionCurve") ) ); + uno::Sequence< double > aXValuesDummy; + xCalculator->recalculateRegression( aXValuesDummy, getAllY() ); + double fXDummy = 1.0; + m_fYMeanValue = xCalculator->getCurveValue( fXDummy ); + } + return m_fYMeanValue; +} + +::std::auto_ptr< Symbol > getSymbolPropertiesFromPropertySet( + const uno::Reference< beans::XPropertySet >& xProp ) +{ + ::std::auto_ptr< Symbol > apSymbolProps( new Symbol() ); + try + { + if( xProp->getPropertyValue( C2U( "Symbol" ) ) >>= *apSymbolProps ) + { + //use main color to fill symbols + xProp->getPropertyValue( C2U( "Color" ) ) >>= apSymbolProps->FillColor; + // border of symbols always same as fill color + apSymbolProps->BorderColor = apSymbolProps->FillColor; + } + else + apSymbolProps.reset(); + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return apSymbolProps; +} + +Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const +{ + Symbol* pRet=NULL; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if(!m_apSymbolProperties_AttributedPoint.get()) + m_apSymbolProperties_AttributedPoint = getSymbolPropertiesFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apSymbolProperties_AttributedPoint.get(); + //if a single data point does not have symbols but the dataseries itself has symbols + //we create an invisible symbol shape to enable selection of that point + if( !pRet || pRet->Style == SymbolStyle_NONE ) + { + if(!m_apSymbolProperties_Series.get()) + m_apSymbolProperties_Series = getSymbolPropertiesFromPropertySet( this->getPropertiesOfSeries() ); + if( m_apSymbolProperties_Series.get() && m_apSymbolProperties_Series->Style != SymbolStyle_NONE ) + { + if(!m_apSymbolProperties_InvisibleSymbolForSelection.get()) + { + m_apSymbolProperties_InvisibleSymbolForSelection = ::std::auto_ptr< Symbol >( new Symbol() ); + m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD; + m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square + m_apSymbolProperties_InvisibleSymbolForSelection->Size = m_apSymbolProperties_Series->Size; + m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible + m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible + } + pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get(); + } + } + } + else + { + if(!m_apSymbolProperties_Series.get()) + m_apSymbolProperties_Series = getSymbolPropertiesFromPropertySet( this->getPropertiesOfSeries() ); + pRet = m_apSymbolProperties_Series.get(); + } + + if( pRet && pRet->Style == SymbolStyle_AUTO ) + { + pRet->Style = SymbolStyle_STANDARD; + + sal_Int32 nIndex = m_nGlobalSeriesIndex; + if(m_aValues_X.is()) + nIndex++; + pRet->StandardSymbol = nIndex; + } + + return pRet; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProp; + + uno::Reference< beans::XPropertySet > xPointProp( this->getPropertiesOfPoint( index )); + if( xPointProp.is() ) + xPointProp->getPropertyValue( C2U( "ErrorBarY" )) >>= xErrorBarProp; + return xErrorBarProp; +} + +bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const +{ + if( !isAttributedDataPoint(index) ) + return false; + + try + { + uno::Reference< beans::XPropertyState > xPointState( this->getPropertiesOfPoint(index), uno::UNO_QUERY_THROW ); + return (xPointState->getPropertyState( C2U("Color")) != beans::PropertyState_DEFAULT_VALUE ); + } + catch( uno::Exception& e) + { + ASSERT_EXCEPTION( e ); + } + return false; +} + +bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const +{ + //returns true if the data point assigned by the given index has set it's own properties + if( index>=m_nPointCount || m_nPointCount==0) + return false; + for(sal_Int32 nN=m_aAttributedDataPointIndexList.getLength();nN--;) + { + if(index==m_aAttributedDataPointIndexList[nN]) + return true; + } + return false; +} + +bool VDataSeries::isVaryColorsByPoint() const +{ + bool bVaryColorsByPoint = false; + Reference< beans::XPropertySet > xSeriesProp( this->getPropertiesOfSeries() ); + if( xSeriesProp.is() ) + xSeriesProp->getPropertyValue( C2U("VaryColorsByPoint") ) >>= bVaryColorsByPoint; + return bVaryColorsByPoint; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const +{ + if( isAttributedDataPoint( index ) ) + return m_xDataSeries->getDataPointByIndex(index); + return this->getPropertiesOfSeries(); +} + +uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfSeries() const +{ + return uno::Reference<beans::XPropertySet>(m_xDataSeries, uno::UNO_QUERY ); +} + +::std::auto_ptr< DataPointLabel > getDataPointLabelFromPropertySet( + const uno::Reference< beans::XPropertySet >& xProp ) +{ + ::std::auto_ptr< DataPointLabel > apLabel( new DataPointLabel() ); + try + { + if( !(xProp->getPropertyValue( C2U( "Label" ) ) >>= *apLabel) ) + apLabel.reset(); + } + catch( uno::Exception &e) + { + ASSERT_EXCEPTION( e ); + } + return apLabel; +} + +void VDataSeries::adaptPointCache( sal_Int32 nNewPointIndex ) const +{ + if( m_nCurrentAttributedPoint != nNewPointIndex ) + { + m_apLabel_AttributedPoint.reset(); + m_apLabelPropNames_AttributedPoint.reset(); + m_apLabelPropValues_AttributedPoint.reset(); + m_apSymbolProperties_AttributedPoint.reset(); + m_nCurrentAttributedPoint = nNewPointIndex; + } +} + +DataPointLabel* VDataSeries::getDataPointLabel( sal_Int32 index ) const +{ + DataPointLabel* pRet = NULL; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if( !m_apLabel_AttributedPoint.get() ) + m_apLabel_AttributedPoint = getDataPointLabelFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apLabel_AttributedPoint.get(); + } + else + { + if(!m_apLabel_Series.get()) + m_apLabel_Series = getDataPointLabelFromPropertySet( this->getPropertiesOfPoint( index ) ); + pRet = m_apLabel_Series.get(); + } + if( !m_bAllowPercentValueInDataLabel ) + { + if( pRet ) + pRet->ShowNumberInPercent = false; + } + return pRet; +} + +DataPointLabel* VDataSeries::getDataPointLabelIfLabel( sal_Int32 index ) const +{ + DataPointLabel* pLabel = this->getDataPointLabel( index ); + if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent + && !pLabel->ShowCategoryName ) ) + return 0; + return pLabel; +} + +bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index + , tNameSequence*& pPropNames + , tAnySequence*& pPropValues ) const +{ + pPropNames = NULL; pPropValues = NULL; + uno::Reference< beans::XPropertySet > xTextProp; + bool bDoDynamicFontResize = false; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if(!m_apLabelPropValues_AttributedPoint.get()) + { + pPropNames = new tNameSequence(); + pPropValues = new tAnySequence(); + xTextProp.set( this->getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( xTextProp, *pPropNames, *pPropValues ); + m_apLabelPropNames_AttributedPoint = ::std::auto_ptr< tNameSequence >(pPropNames); + m_apLabelPropValues_AttributedPoint = ::std::auto_ptr< tAnySequence >(pPropValues); + bDoDynamicFontResize = true; + } + pPropNames = m_apLabelPropNames_AttributedPoint.get(); + pPropValues = m_apLabelPropValues_AttributedPoint.get(); + } + else + { + if(!m_apLabelPropValues_Series.get()) + { + pPropNames = new tNameSequence(); + pPropValues = new tAnySequence(); + xTextProp.set( this->getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( xTextProp, *pPropNames, *pPropValues ); + m_apLabelPropNames_Series = ::std::auto_ptr< tNameSequence >(pPropNames); + m_apLabelPropValues_Series = ::std::auto_ptr< tAnySequence >(pPropValues); + bDoDynamicFontResize = true; + } + pPropNames = m_apLabelPropNames_Series.get(); + pPropValues = m_apLabelPropValues_Series.get(); + } + + if( bDoDynamicFontResize && + pPropNames && pPropValues && + xTextProp.is()) + { + LabelPositionHelper::doDynamicFontResize( *pPropValues, *pPropNames, xTextProp, m_aReferenceSize ); + } + if(pPropNames&&pPropValues) + return true; + return false; +} + +void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment ) +{ + m_nMissingValueTreatment = nMissingValueTreatment; +} + +sal_Int32 VDataSeries::getMissingValueTreatment() const +{ + return m_nMissingValueTreatment; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VLegend.cxx b/chart2/source/view/main/VLegend.cxx new file mode 100644 index 000000000000..f0bcc12c0440 --- /dev/null +++ b/chart2/source/view/main/VLegend.cxx @@ -0,0 +1,829 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "VLegend.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "CommonConverters.hxx" +#include "ObjectIdentifier.hxx" +#include "RelativePositionHelper.hxx" +#include "ShapeFactory.hxx" +#include "RelativeSizeHelper.hxx" +#include "LegendEntryProvider.hxx" +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/drawing/LineJoint.hpp> +#include <com/sun/star/chart2/LegendExpansion.hpp> +#include <com/sun/star/chart2/LegendPosition.hpp> +#include <com/sun/star/chart2/RelativePosition.hpp> +#include <rtl/ustrbuf.hxx> +#include <svl/languageoptions.hxx> + +#include <vector> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; + +//............................................................................. +namespace chart +{ +//............................................................................. + +namespace +{ + +typedef ::std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues; + +typedef ::std::vector< ViewLegendEntry > tViewLegendEntryContainer; + +double lcl_CalcViewFontSize( + const Reference< beans::XPropertySet > & xProp, + const awt::Size & rReferenceSize ) +{ + double fResult = 10.0; + + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( xProp.is() && ( xProp->getPropertyValue( C2U( "CharHeight" )) >>= fFontHeight )) + { + fResult = fFontHeight; + try + { + if( (xProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0)) + { + // todo: find out if asian text is really used +// Reference< beans::XPropertySetInfo >xInfo( xProp, uno::UNO_QUERY ); +// float fFontHeight2 = fFontHeight; +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightAsian")) && +// (xProp->getPropertyValue(C2U("CharHeightAsian")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + +// if( xInfo.is() && +// xInfo->hasPropertyByName(C2U("CharHeightComplex")) && +// (xProp->getPropertyValue(C2U("CharHeightComplex")) >>= fFontHeight2) && +// fFontHeight2 > fFontHeight ) +// { +// fFontHeight = fFontHeight2; +// } + + fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ); + } + } + catch( const uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + // pt -> 1/100th mm + return (fResult * (2540.0 / 72.0)); +} + +void lcl_getProperties( + const Reference< beans::XPropertySet > & xLegendProp, + tPropertyValues & rOutLineFillProperties, + tPropertyValues & rOutTextProperties, + sal_Int32 nMaxLabelWidth, + const awt::Size & rReferenceSize ) +{ + // Get Line- and FillProperties from model legend + if( xLegendProp.is()) + { + // set rOutLineFillProperties + ::chart::tPropertyNameValueMap aLineFillValueMap; + ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp ); + + aLineFillValueMap[ C2U("LineJoint") ] = uno::makeAny( drawing::LineJoint_ROUND ); + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap ); + + // set rOutTextProperties + ::chart::tPropertyNameValueMap aTextValueMap; + ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp ); + + drawing::TextHorizontalAdjust eHorizAdjust( drawing::TextHorizontalAdjust_LEFT ); + aTextValueMap[ C2U("TextAutoGrowHeight") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextAutoGrowWidth") ] = uno::makeAny( sal_True ); + aTextValueMap[ C2U("TextHorizontalAdjust") ] = uno::makeAny( eHorizAdjust ); + aTextValueMap[ C2U("TextMaximumFrameWidth") ] = uno::makeAny( nMaxLabelWidth ); + + // recalculate font size + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( (xLegendProp->getPropertyValue( C2U( "ReferencePageSize" )) >>= aPropRefSize) && + (aPropRefSize.Height > 0) && + (aTextValueMap[ C2U("CharHeight") ] >>= fFontHeight) ) + { + aTextValueMap[ C2U("CharHeight") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + + if( aTextValueMap[ C2U("CharHeightAsian") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightAsian") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + if( aTextValueMap[ C2U("CharHeightComplex") ] >>= fFontHeight ) + { + aTextValueMap[ C2U("CharHeightComplex") ] = uno::makeAny( + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ))); + } + } + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutTextProperties.first, rOutTextProperties.second, aTextValueMap ); + } +} + +awt::Size lcl_createTextShapes( + const tViewLegendEntryContainer & rEntries, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< drawing::XShapes > & xTarget, + ::std::vector< Reference< drawing::XShape > > & rOutTextShapes, + const tPropertyValues & rTextProperties ) +{ + awt::Size aResult; + + for( tViewLegendEntryContainer::const_iterator aIt( rEntries.begin()); + aIt != rEntries.end(); ++aIt ) + { + try + { + // create label shape + Reference< drawing::XShape > xGroupShapeForSingleEntry( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY_THROW ); + Reference< drawing::XShape >xEntry( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.TextShape" )), uno::UNO_QUERY_THROW ); + xTarget->add( xGroupShapeForSingleEntry ); + + Reference< drawing::XShapes > xGroup( xGroupShapeForSingleEntry, uno::UNO_QUERY_THROW ); + xGroup->add( xEntry ); + + // set label text + Sequence< Reference< XFormattedString > > aLabelSeq = (*aIt).aLabel; + for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i ) + { + // todo: support more than one text range + if( i == 1 ) + break; + + Reference< text::XTextRange > xRange( xEntry, uno::UNO_QUERY ); + OUString aLabelString( aLabelSeq[i]->getString()); + // workaround for Issue #i67540# + if( !aLabelString.getLength()) + aLabelString = C2U(" "); + if( xRange.is()) + xRange->setString( aLabelString ); + + PropertyMapper::setMultiProperties( + rTextProperties.first, rTextProperties.second, + Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY )); + + // adapt max-extent + awt::Size aCurrSize( xEntry->getSize()); + aResult.Width = ::std::max( aResult.Width, aCurrSize.Width ); + aResult.Height = ::std::max( aResult.Height, aCurrSize.Height ); + } + + rOutTextShapes.push_back( xGroupShapeForSingleEntry ); + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + } + + return aResult; +} + + +void lcl_placeLegendEntries( + const tViewLegendEntryContainer & rEntries, + LegendExpansion eExpansion, + bool bSymbolsLeftSide, + const Reference< beans::XPropertySet > & xProperties, + tPropertyValues & rTextProperties, + const Reference< drawing::XShapes > & xTarget, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< uno::XComponentContext > & /* xContext */, + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize, + awt::Size & rOutLegendSize ) +{ + double fViewFontSize = lcl_CalcViewFontSize( xProperties, rPageSize ); + + // padding as percentage of the font height + // #i109336# Improve auto positioning in chart + double fXPadding = 0.1; + double fYPadding = 0.2; + double fXOffset = 0.15; + double fYOffset = 0.15; + + const sal_Int32 nXPadding = static_cast< sal_Int32 >( fViewFontSize * fXPadding ); + const sal_Int32 nYPadding = static_cast< sal_Int32 >( fViewFontSize * fYPadding ); + const sal_Int32 nXOffset = static_cast< sal_Int32 >( fViewFontSize * fXOffset ); + const sal_Int32 nYOffset = static_cast< sal_Int32 >( fViewFontSize * fYOffset ); + + ::std::vector< Reference< drawing::XShape > > aTextShapes; + awt::Size aMaxEntryExtent = lcl_createTextShapes( + rEntries, xShapeFactory, xTarget, aTextShapes, rTextProperties ); + OSL_ASSERT( aTextShapes.size() == rEntries.size()); + + // #i109336# Improve auto positioning in chart + double fSymbolSizeFraction = 0.8; + awt::Size aMaxSymbolExtent( static_cast< sal_Int32 >( fViewFontSize * fSymbolSizeFraction * 3.0 / 2.0 ), + static_cast< sal_Int32 >( fViewFontSize * fSymbolSizeFraction ) ); + + sal_Int32 nCurrentXPos = nXPadding; + sal_Int32 nCurrentYPos = nYPadding; + sal_Int32 nMaxEntryWidth = 2 * nXOffset + aMaxSymbolExtent.Width + aMaxEntryExtent.Width; + sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height; + sal_Int32 nNumberOfEntries = rEntries.size(); + + if( !bSymbolsLeftSide ) + nCurrentXPos = -nXPadding; + + sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0; + + // determine layout depending on LegendExpansion + if( eExpansion == LegendExpansion_HIGH ) + { + sal_Int32 nMaxNumberOfRows = nMaxEntryHeight + ? (rAvailableSpace.Height - 2*nYPadding ) / nMaxEntryHeight + : 0; + + nNumberOfColumns = nMaxNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfRows ) )) + : 0; + nNumberOfRows = nNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfColumns ) )) + : 0; + } + else if( eExpansion == LegendExpansion_WIDE ) + { + sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth + ? (rAvailableSpace.Width - 2*nXPadding ) / nMaxEntryWidth + : 0; + + nNumberOfRows = nMaxNumberOfColumns + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nMaxNumberOfColumns ) )) + : 0; + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + else // LegendExpansion_BALANCED + { + double fAspect = nMaxEntryHeight + ? static_cast< double >( nMaxEntryWidth ) / static_cast< double >( nMaxEntryHeight ) + : 0.0; + + nNumberOfRows = static_cast< sal_Int32 >( + ceil( sqrt( static_cast< double >( nNumberOfEntries ) * fAspect ))); + nNumberOfColumns = nNumberOfRows + ? static_cast< sal_Int32 >( + ceil( static_cast< double >( nNumberOfEntries ) / + static_cast< double >( nNumberOfRows ) )) + : 0; + } + + if(nNumberOfRows<=0) + return; + + // calculate maximum height for current row + std::vector< sal_Int32 > nMaxHeights( nNumberOfRows ); + sal_Int32 nRow = 0; + sal_Int32 nColumn = 0; + for( ; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nMaxHeight = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE ) + ? (nColumn + nRow * nNumberOfColumns) + // HIGH or BALANCED + : (nRow + nColumn * nNumberOfRows); + if( nEntry < nNumberOfEntries ) + nMaxHeight = ::std::max( + nMaxHeight, nYOffset + aTextShapes[ nEntry ]->getSize().Height ); + } + nMaxHeights[ nRow ] = nMaxHeight; + } + + // place entries ordered in optimal-width columns + sal_Int32 nMaxYPos = 0; + for( nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nMaxWidth = 0; + nCurrentYPos = nYPadding; + + for( nRow = 0; nRow < nNumberOfRows; ++nRow ) + { + sal_Int32 nEntry = ( eExpansion == LegendExpansion_WIDE ) + ? (nColumn + nRow * nNumberOfColumns) + // HIGH or BALANCED + : (nRow + nColumn * nNumberOfRows); + + if( nEntry >= nNumberOfEntries ) + break; + + // symbol + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + + if( xSymbol.is() ) + { + // Note: aspect ratio should always be 3:2 + + // set symbol size to 75% of maximum space + awt::Size aSymbolSize( + aMaxSymbolExtent.Width * 75 / 100, + aMaxSymbolExtent.Height * 75 / 100 ); + xSymbol->setSize( aSymbolSize ); + sal_Int32 nSymbolXPos = nCurrentXPos + ((aMaxSymbolExtent.Width - aSymbolSize.Width) / 2); + if( !bSymbolsLeftSide ) + nSymbolXPos = nSymbolXPos - aMaxSymbolExtent.Width; + + // #i109336# Improve auto positioning in chart + sal_Int32 nTextHeight = nMaxHeights[ nRow ] - nYOffset; + sal_Int32 nFontSize = static_cast< sal_Int32 >( fViewFontSize ); + sal_Int32 nMaxRowHeight = ( ( ( nTextHeight / nFontSize ) <= 1 ) ? nTextHeight : nFontSize ); + sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nMaxRowHeight - aSymbolSize.Height ) / 2 ); + xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) ); + } + + // position text shape + awt::Size aTextSize( aTextShapes[ nEntry ]->getSize()); + nMaxWidth = ::std::max( nMaxWidth, 2 * nXOffset + aMaxSymbolExtent.Width + aTextSize.Width ); + sal_Int32 nTextXPos = nCurrentXPos + aMaxSymbolExtent.Width; + if( !bSymbolsLeftSide ) + nTextXPos = nCurrentXPos - aMaxSymbolExtent.Width - aTextSize.Width; + aTextShapes[ nEntry ]->setPosition( awt::Point( nTextXPos, nCurrentYPos )); + + nCurrentYPos += nMaxHeights[ nRow ]; + nMaxYPos = ::std::max( nMaxYPos, nCurrentYPos ); + } + if( bSymbolsLeftSide ) + nCurrentXPos += nMaxWidth; + else + nCurrentXPos -= nMaxWidth; + } + + if( bSymbolsLeftSide ) + rOutLegendSize.Width = nCurrentXPos + nXPadding; + else + { + sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding); + rOutLegendSize.Width = nLegendWidth; + + awt::Point aPos(0,0); + for( sal_Int32 nEntry=0; nEntry<nNumberOfEntries; nEntry++ ) + { + Reference< drawing::XShape > xSymbol( rEntries[ nEntry ].aSymbol ); + aPos = xSymbol->getPosition(); + aPos.X += nLegendWidth; + xSymbol->setPosition( aPos ); + Reference< drawing::XShape > xText( aTextShapes[ nEntry ] ); + aPos = xText->getPosition(); + aPos.X += nLegendWidth; + xText->setPosition( aPos ); + } + } + rOutLegendSize.Height = nMaxYPos + nYPadding; +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendLeftRightMargin() +{ + return 210; // 1/100 mm +} + +// #i109336# Improve auto positioning in chart +sal_Int32 lcl_getLegendTopBottomMargin() +{ + return 185; // 1/100 mm +} + +chart2::RelativePosition lcl_getDefaultPosition( LegendPosition ePos, const awt::Rectangle& rOutAvailableSpace, const awt::Size & rPageSize ) +{ + chart2::RelativePosition aResult; + + switch( ePos ) + { + case LegendPosition_LINE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + fDefaultDistance, 0.5, drawing::Alignment_LEFT ); + } + break; + case LegendPosition_LINE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendLeftRightMargin() ) / + static_cast< double >( rPageSize.Width ) ); + aResult = chart2::RelativePosition( + 1.0 - fDefaultDistance, 0.5, drawing::Alignment_RIGHT ); + } + break; + case LegendPosition_PAGE_START: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + double fDistance = (static_cast<double>(rOutAvailableSpace.Y)/static_cast<double>(rPageSize.Height)) + fDefaultDistance; + aResult = chart2::RelativePosition( + 0.5, fDistance, drawing::Alignment_TOP ); + } + break; + case LegendPosition_PAGE_END: + { + // #i109336# Improve auto positioning in chart + const double fDefaultDistance = ( static_cast< double >( lcl_getLegendTopBottomMargin() ) / + static_cast< double >( rPageSize.Height ) ); + aResult = chart2::RelativePosition( + 0.5, 1.0 - fDefaultDistance, drawing::Alignment_BOTTOM ); + } + break; + + case LegendPosition_CUSTOM: + // to avoid warning + case LegendPosition_MAKE_FIXED_SIZE: + // nothing to be set + break; + } + + return aResult; +} + +/** @return + a point relative to the upper left corner that can be used for + XShape::setPosition() +*/ +awt::Point lcl_calculatePositionAndRemainingSpace( + awt::Rectangle & rRemainingSpace, + const awt::Size & rPageSize, + chart2::RelativePosition aRelPos, + LegendPosition ePos, + const awt::Size& aLegendSize ) +{ + // calculate position + awt::Point aResult( + static_cast< sal_Int32 >( aRelPos.Primary * rPageSize.Width ), + static_cast< sal_Int32 >( aRelPos.Secondary * rPageSize.Height )); + + aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + aResult, aLegendSize, aRelPos.Anchor ); + + // adapt rRemainingSpace if LegendPosition is not CUSTOM + // #i109336# Improve auto positioning in chart + sal_Int32 nXDistance = lcl_getLegendLeftRightMargin(); + sal_Int32 nYDistance = lcl_getLegendTopBottomMargin(); + switch( ePos ) + { + case LegendPosition_LINE_START: + { + sal_Int32 nExtent = aLegendSize.Width; + rRemainingSpace.Width -= ( nExtent + nXDistance ); + rRemainingSpace.X += ( nExtent + nXDistance ); + } + break; + case LegendPosition_LINE_END: + { + rRemainingSpace.Width -= ( aLegendSize.Width + nXDistance ); + } + break; + case LegendPosition_PAGE_START: + { + sal_Int32 nExtent = aLegendSize.Height; + rRemainingSpace.Height -= ( nExtent + nYDistance ); + rRemainingSpace.Y += ( nExtent + nYDistance ); + } + break; + case LegendPosition_PAGE_END: + { + rRemainingSpace.Height -= ( aLegendSize.Height + nYDistance ); + } + break; + + default: + // nothing + break; + } + + // adjust the legend position. Esp. for old files that had slightly smaller legends + const sal_Int32 nEdgeDistance( 30 ); + if( aResult.X + aLegendSize.Width > rPageSize.Width ) + { + sal_Int32 nNewX( (rPageSize.Width - aLegendSize.Width) - nEdgeDistance ); + if( nNewX > rPageSize.Width / 4 ) + aResult.X = nNewX; + } + if( aResult.Y + aLegendSize.Height > rPageSize.Height ) + { + sal_Int32 nNewY( (rPageSize.Height - aLegendSize.Height) - nEdgeDistance ); + if( nNewY > rPageSize.Height / 4 ) + aResult.Y = nNewY; + } + + return aResult; +} + +template< class T > +void lcl_appendSeqToVector( const Sequence< T > & rSource, ::std::vector< T > & rDest ) +{ + const sal_Int32 nCount = rSource.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + rDest.push_back( rSource[ i ] ); +} + +bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode ) +{ + bool bSymbolsLeftSide = true; + try + { + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + if(xLegendProp.is()) + { + sal_Int16 nWritingMode=-1; + if( (xLegendProp->getPropertyValue( C2U("WritingMode") ) >>= nWritingMode) ) + { + if( nWritingMode == text::WritingMode2::PAGE ) + nWritingMode = nDefaultWritingMode; + if( nWritingMode == text::WritingMode2::RL_TB ) + bSymbolsLeftSide=false; + } + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + return bSymbolsLeftSide; +} + +} // anonymous namespace + +VLegend::VLegend( + const Reference< XLegend > & xLegend, + const Reference< uno::XComponentContext > & xContext, + const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ) : + m_xLegend( xLegend ), + m_xContext( xContext ), + m_aLegendEntryProviderList( rLegendEntryProviderList ) +{ +} + +// ---------------------------------------- + +void SAL_CALL VLegend::init( + const Reference< drawing::XShapes >& xTargetPage, + const Reference< lang::XMultiServiceFactory >& xFactory, + const Reference< frame::XModel >& xModel ) +{ + m_xTarget = xTargetPage; + m_xShapeFactory = xFactory; + m_xModel = xModel; +} + +// ---------------------------------------- + +void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode ) +{ + m_nDefaultWritingMode = nDefaultWritingMode; +} + +// ---------------------------------------- + +// static +bool VLegend::isVisible( const Reference< XLegend > & xLegend ) +{ + if( ! xLegend.is()) + return sal_False; + + sal_Bool bShow = sal_False; + try + { + Reference< beans::XPropertySet > xLegendProp( xLegend, uno::UNO_QUERY_THROW ); + xLegendProp->getPropertyValue( C2U( "Show" )) >>= bShow; + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + + return bShow; +} + +// ---------------------------------------- + +void VLegend::createShapes( + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! (m_xLegend.is() && + m_xShapeFactory.is() && + m_xTarget.is())) + return; + + try + { + //create shape and add to page + m_xShape.set( m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY ); + m_xTarget->add( m_xShape ); + + // set name to enable selection + { + OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( m_xLegend, m_xModel ) ); + ShapeFactory::setShapeName( m_xShape, ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) ); + } + + // create and insert sub-shapes + Reference< drawing::XShapes > xLegendContainer( m_xShape, uno::UNO_QUERY ); + if( xLegendContainer.is()) + { + Reference< drawing::XShape > xBorder( + m_xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + + // for quickly setting properties + tPropertyValues aLineFillProperties; + tPropertyValues aTextProperties; + + // limit the width of texts to 30% of the total available width + // #i109336# Improve auto positioning in chart + sal_Int32 nMaxLabelWidth = rAvailableSpace.Width * 3 / 10; + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY ); + LegendExpansion eExpansion = LegendExpansion_HIGH; + if( xLegendProp.is()) + { + lcl_getProperties( xLegendProp, aLineFillProperties, aTextProperties, nMaxLabelWidth, + rPageSize ); + + // get Expansion property + xLegendProp->getPropertyValue( C2U( "Expansion" )) >>= eExpansion; + } + + if( xBorder.is()) + { + xLegendContainer->add( xBorder ); + + // apply legend properties + PropertyMapper::setMultiProperties( + aLineFillProperties.first, aLineFillProperties.second, + Reference< beans::XPropertySet >( xBorder, uno::UNO_QUERY )); + + //because of this name this border will be used for marking the legend + ShapeFactory(m_xShapeFactory).setShapeName( xBorder, C2U("MarkHandles") ); + } + + // create entries + tViewLegendEntryContainer aViewEntries; + { + ::std::vector< LegendEntryProvider* >::const_iterator aIter = m_aLegendEntryProviderList.begin(); + const ::std::vector< LegendEntryProvider* >::const_iterator aEnd = m_aLegendEntryProviderList.end(); + for( ; aIter != aEnd; aIter++ ) + { + LegendEntryProvider* pLegendEntryProvider( *aIter ); + if( pLegendEntryProvider ) + { + lcl_appendSeqToVector< ViewLegendEntry >( + pLegendEntryProvider->createLegendEntries( eExpansion, xLegendProp, xLegendContainer, m_xShapeFactory, m_xContext ) + , aViewEntries ); + } + } + } + + bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( xLegendProp, m_nDefaultWritingMode ); + + // place entries + awt::Size aLegendSize; + lcl_placeLegendEntries( aViewEntries, eExpansion, bSymbolsLeftSide + , xLegendProp, aTextProperties + , xLegendContainer, m_xShapeFactory, m_xContext + , rAvailableSpace, rPageSize, aLegendSize ); + + if( xBorder.is()) + xBorder->setSize( aLegendSize ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +// ---------------------------------------- + +void VLegend::changePosition( + awt::Rectangle & rOutAvailableSpace, + const awt::Size & rPageSize ) +{ + if(! m_xShape.is()) + return; + + try + { + // determine position and alignment depending on default position + awt::Size aLegendSize = m_xShape->getSize(); + Reference< beans::XPropertySet > xLegendProp( m_xLegend, uno::UNO_QUERY_THROW ); + chart2::RelativePosition aRelativePosition; + + bool bAutoPosition = + ! (xLegendProp->getPropertyValue( C2U( "RelativePosition" )) >>= aRelativePosition); + + LegendPosition ePos = LegendPosition_CUSTOM; + xLegendProp->getPropertyValue( C2U( "AnchorPosition" )) >>= ePos; + + //calculate position + if( bAutoPosition ) + { + // auto position: relative to remaining space + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + } + else + { + // manual position: relative to whole page + awt::Rectangle aAvailableSpace( 0, 0, rPageSize.Width, rPageSize.Height ); + awt::Point aPos = lcl_calculatePositionAndRemainingSpace( + aAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + m_xShape->setPosition( aPos ); + + if( ePos != LegendPosition_CUSTOM ) + { + // calculate remaining space as if having autoposition: + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, aLegendSize ); + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VLegend.hxx b/chart2/source/view/main/VLegend.hxx new file mode 100644 index 000000000000..9587b50f71e7 --- /dev/null +++ b/chart2/source/view/main/VLegend.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _VLEGEND_HXX +#define _VLEGEND_HXX + +#include <com/sun/star/chart2/XLegend.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/frame/XModel.hpp> + +#include <vector> + +//............................................................................. +namespace chart +{ +//............................................................................. + +class LegendEntryProvider; + +//----------------------------------------------------------------------------- +/** +*/ + +class VLegend +{ +public: + VLegend( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > & xLegend, + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > & xContext, + const std::vector< LegendEntryProvider* >& rLegendEntryProviderList ); + + void SAL_CALL init( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTargetPage, + const ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& xFactory, + const ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XModel > & xModel ); + + void setDefaultWritingMode( sal_Int16 nDefaultWritingMode ); + + void createShapes( const ::com::sun::star::awt::Size & rAvailableSpace, + const ::com::sun::star::awt::Size & rPageSize ); + + /** Sets the position according to its internal anchor. + + @param rOutAvailableSpace + is modified by the method, if the legend is in a standard position, + such that the space allocated by the legend is removed from it. + + @param rReferenceSize + is used to calculate the offset (default 2%) from the edge. + */ + void changePosition( + ::com::sun::star::awt::Rectangle & rOutAvailableSpace, + const ::com::sun::star::awt::Size & rReferenceSize ); + + static bool isVisible( + const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > & xLegend ); + +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XLegend > m_xLegend; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > m_xShape; + ::com::sun::star::uno::Reference< + ::com::sun::star::frame::XModel > m_xModel; + ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > m_xContext; + + std::vector< LegendEntryProvider* > m_aLegendEntryProviderList; + + sal_Int16 m_nDefaultWritingMode;//to be used when writing mode is set to page +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + diff --git a/chart2/source/view/main/VLegendSymbolFactory.cxx b/chart2/source/view/main/VLegendSymbolFactory.cxx new file mode 100644 index 000000000000..958a8defe0b6 --- /dev/null +++ b/chart2/source/view/main/VLegendSymbolFactory.cxx @@ -0,0 +1,374 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "VLegendSymbolFactory.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "ObjectIdentifier.hxx" +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/chart2/Symbol.hpp> + +// header for define DBG_ASSERT +#include <tools/debug.hxx> + +// uncomment to disable line dashes at the border of boxes +// #define DISABLE_DASHES_AT_BORDER + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::rtl::OUString; + +namespace +{ +void lcl_setPropetiesToShape( + const Reference< beans::XPropertySet > & xProp, + const Reference< drawing::XShape > & xShape, + ::chart::VLegendSymbolFactory::tPropertyType ePropertyType ) +{ + const ::chart::tPropertyNameMap & aFilledSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForFilledSeriesProperties()); + const ::chart::tPropertyNameMap & aLineSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineSeriesProperties()); + const ::chart::tPropertyNameMap & aLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineProperties()); + const ::chart::tPropertyNameMap & aFillNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillProperties()); + const ::chart::tPropertyNameMap & aFillLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties()); + + Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + if( xProp.is() && xShapeProp.is() ) + { + ::chart::tPropertyNameValueMap aValueMap; + switch( ePropertyType ) + { + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILLED_SERIES: + ::chart::PropertyMapper::getValueMap( aValueMap, aFilledSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE_SERIES: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_LINE: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL: + ::chart::PropertyMapper::getValueMap( aValueMap, aFillNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PROP_TYPE_FILL_AND_LINE: + ::chart::PropertyMapper::getValueMap( aValueMap, aFillLineNameMap, xProp ); + break; + } + + ::chart::tNameSequence aPropNames; + ::chart::tAnySequence aPropValues; + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap ); + + uno::Any* pLineWidthAny = ::chart::PropertyMapper::getValuePointer(aPropValues,aPropNames,C2U("LineWidth")); + sal_Int32 nLineWidth = 0; + if( pLineWidthAny && (*pLineWidthAny>>=nLineWidth) ) + { + const sal_Int32 nMaxLineWidthForLegend = 50;/*1/100 mm*///todo: make this dependent from legend entry height + if( nLineWidth>nMaxLineWidthForLegend ) + *pLineWidthAny = uno::makeAny( nMaxLineWidthForLegend ); + } + + ::chart::PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp ); + } +} + +} // anonymous namespace + +namespace chart +{ + +// static +Reference< drawing::XShape > VLegendSymbolFactory::createSymbol( + const Reference< drawing::XShapes > xSymbolContainer, + chart2::LegendSymbolStyle eStyle, + const Reference< lang::XMultiServiceFactory > & xShapeFactory, + const Reference< beans::XPropertySet > & xLegendEntryProperties, + tPropertyType ePropertyType, const uno::Any& rExplicitSymbol ) +{ + Reference< drawing::XShape > xResult; + + if( ! (xSymbolContainer.is() && + xShapeFactory.is())) + return xResult; + + xResult.set( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.GroupShape" )), uno::UNO_QUERY ); + xSymbolContainer->add( xResult ); + Reference< drawing::XShapes > xResultGroup( xResult, uno::UNO_QUERY ); + if( ! xResultGroup.is()) + return xResult; + + // aspect ratio of symbols is always 3:2 + awt::Size aBoundSize( 3000, 2000 ); + bool bUseBox = false; + + // add an invisible square box to maintain aspect ratio + switch( eStyle ) + { + case chart2::LegendSymbolStyle_BOX: + case chart2::LegendSymbolStyle_HORIZONTAL_LINE: + case chart2::LegendSymbolStyle_VERTICAL_LINE: + case chart2::LegendSymbolStyle_DIAGONAL_LINE: + case chart2::LegendSymbolStyle_LINE_WITH_BOX: + case chart2::LegendSymbolStyle_LINE_WITH_SYMBOL: + case chart2::LegendSymbolStyle_CIRCLE: + { + Reference< drawing::XShape > xBound( ShapeFactory(xShapeFactory).createInvisibleRectangle( + xResultGroup, aBoundSize )); + break; + } + + case chart2::LegendSymbolStyle_BAR: + case chart2::LegendSymbolStyle_RECTANGLE: + case chart2::LegendSymbolStyle_STRETCHED_RECTANGLE: + case chart2::LegendSymbolStyle_USER_DEFINED: + default: + break; + } + + // create symbol + switch( eStyle ) + { + case chart2::LegendSymbolStyle_BOX: + case chart2::LegendSymbolStyle_BAR: + case chart2::LegendSymbolStyle_RECTANGLE: + case chart2::LegendSymbolStyle_STRETCHED_RECTANGLE: + case chart2::LegendSymbolStyle_CIRCLE: + { + try + { + Reference< drawing::XShape > xShape; + + if( eStyle == chart2::LegendSymbolStyle_CIRCLE ) + xShape.set( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.EllipseShape" )), uno::UNO_QUERY ); + else + xShape.set( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + + if( xShape.is()) + { + xResultGroup->add( xShape ); + if( eStyle == chart2::LegendSymbolStyle_BOX || + eStyle == chart2::LegendSymbolStyle_CIRCLE ) + { + xShape->setSize( awt::Size( 2000, 2000 )); + xShape->setPosition( awt::Point( 500, 0 )); + } + else + { + xShape->setSize( aBoundSize ); + } + } + + lcl_setPropetiesToShape( xLegendEntryProperties, xShape, ePropertyType ); // PROP_TYPE_FILLED_SERIES ); + +#ifdef DISABLE_DASHES_AT_BORDER + // don't allow dashed border style + Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + if( xShapeProp.is()) + { + drawing::LineStyle aLineStyle; + if( ( xShapeProp->getPropertyValue( C2U("LineStyle")) >>= aLineStyle ) && + aLineStyle == drawing::LineStyle_DASH ) + { + aLineStyle = drawing::LineStyle_SOLID; + xShapeProp->setPropertyValue( C2U("LineStyle"), uno::makeAny( aLineStyle )); + } + } +#endif + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + break; + } + + case chart2::LegendSymbolStyle_HORIZONTAL_LINE: + { + try + { + Reference< drawing::XShape > xLine( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY ); + if( xLine.is()) + { + xResultGroup->add( xLine ); + xLine->setSize( awt::Size( 3000, 0 )); + xLine->setPosition( awt::Point( 0, 1000 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType ); // PROP_TYPE_LINE_SERIES ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + break; + } + + case chart2::LegendSymbolStyle_VERTICAL_LINE: + { + try + { + Reference< drawing::XShape > xLine( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY ); + if( xLine.is()) + { + xResultGroup->add( xLine ); + xLine->setSize( awt::Size( 0, 2000 )); + xLine->setPosition( awt::Point( 1500, 0 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType ); // PROP_TYPE_LINE_SERIES ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + break; + } + + case chart2::LegendSymbolStyle_DIAGONAL_LINE: + { + try + { + Reference< drawing::XShape > xLine( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY ); + if( xLine.is()) + { + xResultGroup->add( xLine ); + xLine->setSize( awt::Size( 2000, 2000 )); + xLine->setPosition( awt::Point( 500, 0 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType ); // PROP_TYPE_LINE_SERIES ); + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + break; + } + + case chart2::LegendSymbolStyle_LINE_WITH_BOX: + bUseBox = true; + // fall-through intended + case chart2::LegendSymbolStyle_LINE_WITH_SYMBOL: + try + { + Reference< drawing::XShape > xLine( + xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.LineShape" )), uno::UNO_QUERY ); + if( xLine.is()) + { + xResultGroup->add( xLine ); + xLine->setSize( awt::Size( 3000, 0 )); + xLine->setPosition( awt::Point( 0, 1000 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xLine, ePropertyType ); + } + + Reference< drawing::XShape > xSymbol; + const sal_Int32 nSize = 1500; + if( bUseBox ) + { + xSymbol.set( xShapeFactory->createInstance( + C2U( "com.sun.star.drawing.RectangleShape" )), uno::UNO_QUERY ); + xResultGroup->add( xSymbol ); + + if( xSymbol.is()) + { + xSymbol->setSize( awt::Size( nSize, nSize )); + xSymbol->setPosition( awt::Point( 1500 - nSize/2, 1000 - nSize/2 )); + + lcl_setPropetiesToShape( xLegendEntryProperties, xSymbol, ePropertyType ); + } + } + else + { + chart2::Symbol aSymbol; + + if( rExplicitSymbol >>= aSymbol ) + { + drawing::Direction3D aSymbolSize( nSize, nSize, 0 ); + drawing::Position3D aPos( 1500, 1000, 0 ); + ShapeFactory aFactory( xShapeFactory ); + if( aSymbol.Style == chart2::SymbolStyle_STANDARD ) + { + // take series color as fill color + xLegendEntryProperties->getPropertyValue( C2U("Color")) >>= aSymbol.FillColor; + // border of symbols always same as fill color + aSymbol.BorderColor = aSymbol.FillColor; + + xSymbol.set( aFactory.createSymbol2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.StandardSymbol, + aSymbol.BorderColor, + aSymbol.FillColor )); + } + else if( aSymbol.Style == chart2::SymbolStyle_GRAPHIC ) + { + xSymbol.set( aFactory.createGraphic2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.Graphic )); + } + else if( aSymbol.Style == chart2::SymbolStyle_AUTO ) + { + DBG_ERROR("the given parameter is not allowed to contain an automatic symbol style"); + } + } + } + } + catch( uno::Exception & ex ) + { + ASSERT_EXCEPTION( ex ); + } + break; + + case chart2::LegendSymbolStyle_USER_DEFINED: + break; + + default: + // just to remove warning (there is an auto-generated extra label) + break; + } + + return xResult; +} + +} // namespace chart diff --git a/chart2/source/view/main/VLineProperties.cxx b/chart2/source/view/main/VLineProperties.cxx new file mode 100644 index 000000000000..dc8409a6891d --- /dev/null +++ b/chart2/source/view/main/VLineProperties.cxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "VLineProperties.hxx" +#include "macros.hxx" +#include <com/sun/star/drawing/LineStyle.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// get line properties from a propertyset +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +VLineProperties::VLineProperties() +{ + this->Color = uno::makeAny( sal_Int32(0x000000) ); //type sal_Int32 UNO_NAME_LINECOLOR + this->LineStyle = uno::makeAny( drawing::LineStyle_SOLID ); //type drawing::LineStyle for property UNO_NAME_LINESTYLE + this->Transparence = uno::makeAny( sal_Int16(0) );//type sal_Int16 for property UNO_NAME_LINETRANSPARENCE + this->Width = uno::makeAny( sal_Int32(0) );//type sal_Int32 for property UNO_NAME_LINEWIDTH +} + +void VLineProperties::initFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp, bool bUseSeriesPropertyNames ) +{ + if(xProp.is()) + { + if( bUseSeriesPropertyNames ) try + { + this->Color = xProp->getPropertyValue( C2U( "BorderColor" ) ); + this->LineStyle = xProp->getPropertyValue( C2U( "BorderStyle" ) ); + this->Transparence = xProp->getPropertyValue( C2U( "BorderTransparency" ) ); + this->Width = xProp->getPropertyValue( C2U( "BorderWidth" ) ); + this->DashName = xProp->getPropertyValue( C2U( "BorderDashName" ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + else try + { + this->Color = xProp->getPropertyValue( C2U( "LineColor" ) ); + this->LineStyle = xProp->getPropertyValue( C2U( "LineStyle" ) ); + this->Transparence = xProp->getPropertyValue( C2U( "LineTransparence" ) ); + this->Width = xProp->getPropertyValue( C2U( "LineWidth" ) ); + this->DashName = xProp->getPropertyValue( C2U( "LineDashName" ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + } + else + this->LineStyle = uno::makeAny( drawing::LineStyle_NONE ); +} + +bool VLineProperties::isLineVisible() const +{ + bool bRet = false; + + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + this->LineStyle >>= aLineStyle; + if( aLineStyle != drawing::LineStyle_NONE ) + { + sal_Int16 nLineTransparence=0; + this->Transparence >>= nLineTransparence; + if(100!=nLineTransparence) + { + bRet = true; + } + } + + return bRet; +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VPolarTransformation.cxx b/chart2/source/view/main/VPolarTransformation.cxx new file mode 100644 index 000000000000..fd3037316cc6 --- /dev/null +++ b/chart2/source/view/main/VPolarTransformation.cxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" + +#include "VPolarTransformation.hxx" +#include "ViewDefines.hxx" +#include "CommonConverters.hxx" +#include <algorithm> + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::RuntimeException; + +namespace chart +{ + + +VPolarTransformation::VPolarTransformation( const PolarPlottingPositionHelper& rPositionHelper ) + : m_aPositionHelper(rPositionHelper) + , m_aUnitCartesianToScene( rPositionHelper.getUnitCartesianToScene() ) +{ +} + +VPolarTransformation::~VPolarTransformation() +{ +} + +// ____ XTransformation ____ +Sequence< double > SAL_CALL VPolarTransformation::transform( + const Sequence< double >& rSourceValues ) + throw (RuntimeException, + lang::IllegalArgumentException) +{ + double fScaledLogicAngle = rSourceValues[0]; + double fScaledLogicRadius = rSourceValues[1]; + + if( m_aPositionHelper.isSwapXAndY() ) + std::swap(fScaledLogicAngle,fScaledLogicRadius); + + double fAngleDegree = m_aPositionHelper.transformToAngleDegree( fScaledLogicAngle, false ); + double fAnglePi = fAngleDegree*F_PI/180.0; + double fRadius = m_aPositionHelper.transformToRadius( fScaledLogicRadius, false); + + double fX=fRadius*cos(fAnglePi); + double fY=fRadius*sin(fAnglePi); + double fZ=rSourceValues[2]; + + //!! applying matrix to vector does ignore translation, so it is important to use a B3DPoint here instead of B3DVector + ::basegfx::B3DPoint aPoint(fX,fY,fZ); + ::basegfx::B3DPoint aRet = m_aUnitCartesianToScene * aPoint; + return B3DPointToSequence(aRet); +} + +sal_Int32 SAL_CALL VPolarTransformation::getSourceDimension() + throw (RuntimeException) +{ + return 3; +} + +sal_Int32 SAL_CALL VPolarTransformation::getTargetDimension() + throw (RuntimeException) +{ + return 3; +} + + +} // namespace chart diff --git a/chart2/source/view/main/VTitle.cxx b/chart2/source/view/main/VTitle.cxx new file mode 100644 index 000000000000..f62142735b7c --- /dev/null +++ b/chart2/source/view/main/VTitle.cxx @@ -0,0 +1,299 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include "VTitle.hxx" +#include "CommonConverters.hxx" +#include "macros.hxx" +#include "PropertyMapper.hxx" +#include "ShapeFactory.hxx" +#include "RelativeSizeHelper.hxx" +#include <com/sun/star/chart2/XFormattedString.hpp> +#include <rtl/math.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/TextVerticalAdjust.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextCursor.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VTitle::VTitle( const uno::Reference< XTitle > & xTitle ) + : m_xTarget(NULL) + , m_xShapeFactory(NULL) + , m_xTitle(xTitle) + , m_xShape(NULL) + , m_aCID() + , m_fRotationAngleDegree(0.0) + , m_nXPos(0) + , m_nYPos(0) +{ +} + +VTitle::~VTitle() +{ +} + +void SAL_CALL VTitle::init( + const uno::Reference< drawing::XShapes >& xTargetPage + , const uno::Reference< lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID ) +{ + m_xTarget = xTargetPage; + m_xShapeFactory = xFactory; + m_aCID = rCID; +} + +double VTitle::getRotationAnglePi() const +{ + return m_fRotationAngleDegree*F_PI/180.0; +} + +awt::Size VTitle::getUnrotatedSize() const //size before rotation +{ + awt::Size aRet; + if(m_xShape.is()) + aRet = m_xShape->getSize(); + return aRet; +} + +awt::Size VTitle::getFinalSize() const //size after rotation +{ + return ShapeFactory::getSizeAfterRotation( + m_xShape, m_fRotationAngleDegree ); +} + +void VTitle::changePosition( const awt::Point& rPos ) +{ + if(!m_xShape.is()) + return; + uno::Reference< beans::XPropertySet > xShapeProp( m_xShape, uno::UNO_QUERY ); + if(!xShapeProp.is()) + return; + try + { + m_nXPos = rPos.X; + m_nYPos = rPos.Y; + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + ::basegfx::B2DHomMatrix aM; + aM.rotate( -m_fRotationAngleDegree*F_PI/180.0 );//#i78696#->#i80521# + aM.translate( m_nXPos, m_nYPos); + xShapeProp->setPropertyValue( C2U( "Transformation" ), uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +void VTitle::createShapes( + const awt::Point& rPos + , const awt::Size& rReferenceSize ) +{ + try + { + if(!m_xTitle.is()) + return; + + uno::Sequence< uno::Reference< XFormattedString > > aStringList = m_xTitle->getText(); + if(aStringList.getLength()<=0) + return; + + //create shape and add to page + uno::Reference< drawing::XShape > xShape( + m_xShapeFactory->createInstance( C2U( + "com.sun.star.drawing.TextShape" ) ), uno::UNO_QUERY ); + m_xTarget->add(xShape); + m_xShape = xShape; + + //set text and text properties + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + uno::Reference< text::XTextCursor > xTextCursor( xText->createTextCursor() ); + uno::Reference< text::XTextRange > xTextRange( xTextCursor, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xShapeProp( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xTitleProperties( m_xTitle, uno::UNO_QUERY ); + if( !xText.is() || !xTextRange.is() || !xTextCursor.is() || !xShapeProp.is() || !xTitleProperties.is() ) + return; + + tPropertyNameValueMap aValueMap; + //fill line-, fill- and paragraph-properties into the ValueMap + { + tMakePropertyNameMap aNameMap = PropertyMapper::getPropertyNameMapForParagraphProperties(); + aNameMap( PropertyMapper::getPropertyNameMapForFillAndLineProperties() ); + + PropertyMapper::getValueMap( aValueMap, aNameMap, xTitleProperties ); + } + + //fill some more shape properties into the ValueMap + { + drawing::TextHorizontalAdjust eHorizontalAdjust = drawing::TextHorizontalAdjust_CENTER; + drawing::TextVerticalAdjust eVerticalAdjust = drawing::TextVerticalAdjust_CENTER; + //text::WritingMode eWritingMode = text::WritingMode_LR_TB;//@todo get correct one + + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextHorizontalAdjust"), uno::makeAny(eHorizontalAdjust) ) ); // drawing::TextHorizontalAdjust + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextVerticalAdjust"), uno::makeAny(eVerticalAdjust) ) ); //drawing::TextVerticalAdjust + //aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextWritingMode"), uno::makeAny(eWritingMode) ) ); //text::WritingMode + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowHeight"), uno::makeAny(sal_True) ) ); // sal_Bool + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextAutoGrowWidth"), uno::makeAny(sal_True) ) ); // sal_Bool + + ////aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameWidth"), uno::makeAny(rSize.Width) ) ); //sal_Int32 + ////aValueMap.insert( tPropertyNameValueMap::value_type( C2U("TextMaximumFrameHeight"), uno::makeAny(rSize.Height) ) ); //sal_Int32 + + //set name/classified ObjectID (CID) + if( m_aCID.getLength() ) + aValueMap.insert( tPropertyNameValueMap::value_type( C2U("Name"), uno::makeAny( m_aCID ) ) ); //CID rtl::OUString + } + + //set global title properties + { + tNameSequence aPropNames; + tAnySequence aPropValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap ); + PropertyMapper::setMultiProperties( aPropNames, aPropValues, xShapeProp ); + } + + sal_Bool bStackCharacters(sal_False); + try + { + xTitleProperties->getPropertyValue( C2U( "StackCharacters" ) ) >>= bStackCharacters; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + if(bStackCharacters) + { + //if the characters should be stacked we use only the first character properties for code simplicity + if( aStringList.getLength()>0 ) + { + rtl::OUString aLabel; + for( sal_Int32 nN=0; nN<aStringList.getLength();nN++ ) + aLabel += aStringList[nN]->getString(); + aLabel = ShapeFactory::getStackedString( aLabel, bStackCharacters ); + + xTextCursor->gotoEnd(false); + xText->insertString( xTextRange, aLabel, false ); + xTextCursor->gotoEnd(true); + uno::Reference< beans::XPropertySet > xTargetProps( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xSourceProps( aStringList[0], uno::UNO_QUERY ); + + PropertyMapper::setMappedProperties( xTargetProps, xSourceProps + , PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + awt::Size aOldRefSize; + if( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize ) + { + RelativeSizeHelper::adaptFontSizes( xTargetProps, aOldRefSize, rReferenceSize ); + } + } + } + else + { + uno::Sequence< uno::Reference< text::XTextCursor > > aCursorList( aStringList.getLength() ); + sal_Int32 nN = 0; + for( nN=0; nN<aStringList.getLength();nN++ ) + { + xTextCursor->gotoEnd(false); + xText->insertString( xTextRange, aStringList[nN]->getString(), false ); + xTextCursor->gotoEnd(true); + aCursorList[nN] = xText->createTextCursorByRange( uno::Reference< text::XTextRange >(xTextCursor,uno::UNO_QUERY) ); + } + awt::Size aOldRefSize; + bool bHasRefPageSize = + ( xTitleProperties->getPropertyValue( C2U("ReferencePageSize")) >>= aOldRefSize ); + + //for( nN=0; nN<aStringList.getLength();nN++ ) //portion wise fromatting does not work still + if( aStringList.getLength()>0 ) + { + //uno::Reference< beans::XPropertySet > xTargetProps( aCursorList[nN], uno::UNO_QUERY ); + //uno::Reference< beans::XPropertySet > xSourceProps( aStringList[nN], uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xTargetProps( xShape, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xSourceProps( aStringList[0], uno::UNO_QUERY ); + PropertyMapper::setMappedProperties( xTargetProps, xSourceProps, PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + if( bHasRefPageSize ) + { + RelativeSizeHelper::adaptFontSizes( xTargetProps, aOldRefSize, rReferenceSize ); + } + } + } + + // #i109336# Improve auto positioning in chart + float fFontHeight = 0.0; + if ( xShapeProp.is() && ( xShapeProp->getPropertyValue( C2U( "CharHeight" ) ) >>= fFontHeight ) ) + { + fFontHeight *= ( 2540. / 72. ); // pt -> 1/100 mm + float fXFraction = 0.18; + sal_Int32 nXDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * fXFraction ) ); + float fYFraction = 0.30; + sal_Int32 nYDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * fYFraction ) ); + xShapeProp->setPropertyValue( C2U( "TextLeftDistance" ), uno::makeAny( nXDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextRightDistance" ), uno::makeAny( nXDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextUpperDistance" ), uno::makeAny( nYDistance ) ); + xShapeProp->setPropertyValue( C2U( "TextLowerDistance" ), uno::makeAny( nYDistance ) ); + } + + try + { + double fAngleDegree = 0; + xTitleProperties->getPropertyValue( C2U( "TextRotation" ) ) >>= fAngleDegree; + m_fRotationAngleDegree += fAngleDegree; + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } + m_nXPos = rPos.X; + m_nYPos = rPos.Y; + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + ::basegfx::B2DHomMatrix aM; + aM.rotate( -m_fRotationAngleDegree*F_PI/180.0 );//#i78696#->#i80521# + aM.translate( m_nXPos, m_nYPos ); + xShapeProp->setPropertyValue( C2U( "Transformation" ), uno::makeAny( B2DHomMatrixToHomogenMatrix3(aM) ) ); + } + catch( uno::Exception& e ) + { + ASSERT_EXCEPTION( e ); + } +} + +//............................................................................. +} //namespace chart +//............................................................................. diff --git a/chart2/source/view/main/VTitle.hxx b/chart2/source/view/main/VTitle.hxx new file mode 100644 index 000000000000..8a6e7d6e4f16 --- /dev/null +++ b/chart2/source/view/main/VTitle.hxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CHART2_VTITLE_HXX +#define _CHART2_VTITLE_HXX + +#include <com/sun/star/chart2/XTitle.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +//............................................................................. +namespace chart +{ +//............................................................................. + +//----------------------------------------------------------------------------- +/** +*/ + +class VTitle +{ +public: + VTitle( const ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XTitle > & xTitle ); + virtual ~VTitle(); + + void SAL_CALL init( const ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes >& xTargetPage + , const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xFactory + , const rtl::OUString& rCID ); + + void createShapes( const ::com::sun::star::awt::Point& rPos + , const ::com::sun::star::awt::Size& rReferenceSize ); + + double getRotationAnglePi() const; + ::com::sun::star::awt::Size getUnrotatedSize() const; + ::com::sun::star::awt::Size getFinalSize() const; + void changePosition( const ::com::sun::star::awt::Point& rPos ); + +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShapes > m_xTarget; + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory> m_xShapeFactory; + ::com::sun::star::uno::Reference< + ::com::sun::star::chart2::XTitle > m_xTitle; + ::com::sun::star::uno::Reference< + ::com::sun::star::drawing::XShape > m_xShape; + rtl::OUString m_aCID; + + double m_fRotationAngleDegree; + sal_Int32 m_nXPos; + sal_Int32 m_nYPos; +}; + +//............................................................................. +} //namespace chart +//............................................................................. +#endif + diff --git a/chart2/source/view/main/_serviceregistration_view.cxx b/chart2/source/view/main/_serviceregistration_view.cxx new file mode 100644 index 000000000000..26f8b9d7cf7e --- /dev/null +++ b/chart2/source/view/main/_serviceregistration_view.cxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_chart2.hxx" +#include <cppuhelper/implementationentry.hxx> + +#include "ChartView.hxx" + +static struct ::cppu::ImplementationEntry g_entries_chart2_view[] = +{ + { + ::chart::ChartView::create + , ::chart::ChartView::getImplementationName_Static + , ::chart::ChartView::getSupportedServiceNames_Static + , ::cppu::createSingleComponentFactory + , 0 + , 0 + } + ,{ 0, 0, 0, 0, 0, 0 } +}; + +// component exports +extern "C" +{ +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} +//================================================================================================== +SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( + void * pServiceManager, void * pRegistryKey ) +{ + return ::cppu::component_writeInfoHelper( + pServiceManager, pRegistryKey, g_entries_chart2_view ); +} +//================================================================================================== +SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey ) +{ + return ::cppu::component_getFactoryHelper( + pImplName, pServiceManager, pRegistryKey , g_entries_chart2_view ); +} +} +//========================================================================= diff --git a/chart2/source/view/main/makefile.mk b/chart2/source/view/main/makefile.mk new file mode 100644 index 000000000000..ec9c99f2a898 --- /dev/null +++ b/chart2/source/view/main/makefile.mk @@ -0,0 +1,68 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ= ..$/..$/.. +PRJINC= $(PRJ)$/source +PRJNAME= chart2 +TARGET= chview + +ENABLE_EXCEPTIONS= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE: settings.mk +.INCLUDE: $(PRJ)$/chartview.pmk + +# --- export library ------------------------------------------------- + +#object files to build and link together to lib $(SLB)$/$(TARGET).lib +SLOFILES = \ + $(SLO)$/ChartItemPool.obj \ + $(SLO)$/DrawModelWrapper.obj \ + $(SLO)$/NumberFormatterWrapper.obj \ + $(SLO)$/PropertyMapper.obj \ + $(SLO)$/Stripe.obj \ + $(SLO)$/VLineProperties.obj \ + $(SLO)$/ShapeFactory.obj \ + $(SLO)$/VLegendSymbolFactory.obj \ + $(SLO)$/DataPointSymbolSupplier.obj \ + $(SLO)$/Linear3DTransformation.obj \ + $(SLO)$/VPolarTransformation.obj \ + $(SLO)$/Clipping.obj \ + $(SLO)$/PlottingPositionHelper.obj \ + $(SLO)$/LabelPositionHelper.obj \ + $(SLO)$/PolarLabelPositionHelper.obj \ + $(SLO)$/PlotterBase.obj \ + $(SLO)$/VDataSeries.obj \ + $(SLO)$/VLegend.obj \ + $(SLO)$/VTitle.obj \ + $(SLO)$/ChartView.obj \ + $(SLO)$/_serviceregistration_view.obj + +# --- Targets ----------------------------------------------------------------- + +.INCLUDE: target.mk |