From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- chart2/source/chartcore.component | 259 ++ .../controller/accessibility/AccessibleBase.cxx | 854 ++++++ .../accessibility/AccessibleChartElement.cxx | 243 ++ .../accessibility/AccessibleChartElement.hxx | 104 + .../accessibility/AccessibleChartShape.cxx | 250 ++ .../accessibility/AccessibleChartShape.hxx | 83 + .../accessibility/AccessibleChartView.cxx | 358 +++ .../accessibility/AccessibleTextHelper.cxx | 168 ++ .../accessibility/AccessibleViewForwarder.cxx | 79 + .../accessibility/AccessibleViewForwarder.hxx | 56 + .../accessibility/ChartElementFactory.cxx | 71 + .../accessibility/ChartElementFactory.hxx | 39 + .../controller/chartapiwrapper/AreaWrapper.cxx | 176 ++ .../controller/chartapiwrapper/AreaWrapper.hxx | 80 + .../controller/chartapiwrapper/AxisWrapper.cxx | 672 +++++ .../controller/chartapiwrapper/AxisWrapper.hxx | 123 + .../chartapiwrapper/Chart2ModelContact.cxx | 302 +++ .../chartapiwrapper/Chart2ModelContact.hxx | 149 + .../chartapiwrapper/ChartDataWrapper.cxx | 695 +++++ .../chartapiwrapper/ChartDataWrapper.hxx | 118 + .../chartapiwrapper/ChartDocumentWrapper.cxx | 1437 ++++++++++ .../chartapiwrapper/DataSeriesPointWrapper.cxx | 899 ++++++ .../chartapiwrapper/DataSeriesPointWrapper.hxx | 124 + .../controller/chartapiwrapper/DiagramWrapper.cxx | 1918 +++++++++++++ .../controller/chartapiwrapper/DiagramWrapper.hxx | 217 ++ .../controller/chartapiwrapper/GridWrapper.cxx | 188 ++ .../controller/chartapiwrapper/GridWrapper.hxx | 81 + .../controller/chartapiwrapper/LegendWrapper.cxx | 422 +++ .../controller/chartapiwrapper/LegendWrapper.hxx | 87 + .../chartapiwrapper/MinMaxLineWrapper.cxx | 384 +++ .../chartapiwrapper/MinMaxLineWrapper.hxx | 104 + .../ReferenceSizePropertyProvider.hxx | 38 + .../controller/chartapiwrapper/TitleWrapper.cxx | 510 ++++ .../controller/chartapiwrapper/TitleWrapper.hxx | 110 + .../chartapiwrapper/UpDownBarWrapper.cxx | 356 +++ .../chartapiwrapper/UpDownBarWrapper.hxx | 105 + .../chartapiwrapper/WallFloorWrapper.cxx | 168 ++ .../chartapiwrapper/WallFloorWrapper.hxx | 69 + .../chartapiwrapper/WrappedAddInProperty.cxx | 121 + .../chartapiwrapper/WrappedAddInProperty.hxx | 87 + .../WrappedAutomaticPositionProperties.cxx | 123 + .../WrappedAutomaticPositionProperties.hxx | 46 + .../WrappedAxisAndGridExistenceProperties.cxx | 406 +++ .../WrappedAxisAndGridExistenceProperties.hxx | 54 + .../WrappedCharacterHeightProperty.cxx | 138 + .../WrappedCharacterHeightProperty.hxx | 77 + .../WrappedDataCaptionProperties.cxx | 156 ++ .../WrappedDataCaptionProperties.hxx | 44 + .../chartapiwrapper/WrappedGapwidthProperty.cxx | 168 ++ .../chartapiwrapper/WrappedGapwidthProperty.hxx | 73 + .../WrappedNumberFormatProperty.cxx | 121 + .../WrappedNumberFormatProperty.hxx | 64 + .../chartapiwrapper/WrappedScaleProperty.cxx | 587 ++++ .../chartapiwrapper/WrappedScaleProperty.hxx | 83 + .../chartapiwrapper/WrappedScaleTextProperties.cxx | 138 + .../chartapiwrapper/WrappedScaleTextProperties.hxx | 43 + .../chartapiwrapper/WrappedSceneProperty.cxx | 101 + .../chartapiwrapper/WrappedSceneProperty.hxx | 55 + .../WrappedSeriesAreaOrLineProperty.cxx | 51 + .../WrappedSeriesAreaOrLineProperty.hxx | 45 + .../WrappedSeriesOrDiagramProperty.hxx | 163 ++ .../chartapiwrapper/WrappedSplineProperties.cxx | 284 ++ .../chartapiwrapper/WrappedSplineProperties.hxx | 42 + .../chartapiwrapper/WrappedStatisticProperties.cxx | 1072 ++++++++ .../chartapiwrapper/WrappedStatisticProperties.hxx | 44 + .../chartapiwrapper/WrappedStockProperties.cxx | 281 ++ .../chartapiwrapper/WrappedStockProperties.hxx | 42 + .../chartapiwrapper/WrappedSymbolProperties.cxx | 531 ++++ .../chartapiwrapper/WrappedSymbolProperties.hxx | 44 + .../WrappedTextRotationProperty.cxx | 71 + .../WrappedTextRotationProperty.hxx | 43 + chart2/source/controller/chartcontroller.component | 58 + .../source/controller/dialogs/ChangingResource.cxx | 38 + .../controller/dialogs/ChartResourceGroupDlgs.cxx | 131 + .../controller/dialogs/ChartResourceGroups.cxx | 361 +++ .../dialogs/ChartTypeDialogController.cxx | 1253 +++++++++ chart2/source/controller/dialogs/DataBrowser.cxx | 1383 ++++++++++ chart2/source/controller/dialogs/DataBrowser.hxx | 187 ++ .../source/controller/dialogs/DataBrowserModel.cxx | 936 +++++++ .../source/controller/dialogs/DataBrowserModel.hxx | 169 ++ chart2/source/controller/dialogs/DialogModel.cxx | 841 ++++++ chart2/source/controller/dialogs/DialogModel.hxx | 176 ++ .../controller/dialogs/ObjectNameProvider.cxx | 860 ++++++ .../controller/dialogs/RangeSelectionHelper.cxx | 177 ++ .../controller/dialogs/RangeSelectionListener.cxx | 62 + .../controller/dialogs/TextDirectionListBox.cxx | 36 + .../dialogs/TimerTriggeredControllerLock.cxx | 51 + .../source/controller/dialogs/TitleDialogData.cxx | 113 + chart2/source/controller/dialogs/dlg_ChartType.cxx | 45 + .../controller/dialogs/dlg_ChartType_UNO.cxx | 113 + .../controller/dialogs/dlg_CreationWizard.cxx | 201 ++ .../controller/dialogs/dlg_CreationWizard_UNO.cxx | 351 +++ .../source/controller/dialogs/dlg_DataEditor.cxx | 147 + .../source/controller/dialogs/dlg_DataSource.cxx | 182 ++ .../controller/dialogs/dlg_InsertAxis_Grid.cxx | 88 + .../controller/dialogs/dlg_InsertDataLabel.cxx | 43 + .../controller/dialogs/dlg_InsertErrorBars.cxx | 103 + .../source/controller/dialogs/dlg_InsertLegend.cxx | 45 + .../source/controller/dialogs/dlg_InsertTitle.cxx | 41 + .../source/controller/dialogs/dlg_NumberFormat.cxx | 56 + .../source/controller/dialogs/dlg_NumberFormat.hxx | 42 + .../controller/dialogs/dlg_ObjectProperties.cxx | 627 +++++ chart2/source/controller/dialogs/dlg_ShapeFont.cxx | 61 + .../controller/dialogs/dlg_ShapeParagraph.cxx | 64 + chart2/source/controller/dialogs/dlg_View3D.cxx | 81 + .../source/controller/dialogs/res_BarGeometry.cxx | 66 + chart2/source/controller/dialogs/res_DataLabel.cxx | 362 +++ chart2/source/controller/dialogs/res_DataLabel.hxx | 93 + chart2/source/controller/dialogs/res_ErrorBar.cxx | 716 +++++ .../controller/dialogs/res_LegendPosition.cxx | 243 ++ chart2/source/controller/dialogs/res_Titles.cxx | 132 + chart2/source/controller/dialogs/res_Trendline.cxx | 438 +++ chart2/source/controller/dialogs/res_Trendline.hxx | 98 + .../controller/dialogs/tp_3D_SceneAppearance.cxx | 317 +++ .../controller/dialogs/tp_3D_SceneAppearance.hxx | 69 + .../controller/dialogs/tp_3D_SceneGeometry.cxx | 256 ++ .../controller/dialogs/tp_3D_SceneGeometry.hxx | 87 + .../controller/dialogs/tp_3D_SceneIllumination.cxx | 531 ++++ .../controller/dialogs/tp_3D_SceneIllumination.hxx | 99 + chart2/source/controller/dialogs/tp_AxisLabel.cxx | 302 +++ chart2/source/controller/dialogs/tp_AxisLabel.hxx | 84 + .../source/controller/dialogs/tp_AxisPositions.cxx | 322 +++ .../source/controller/dialogs/tp_AxisPositions.hxx | 85 + chart2/source/controller/dialogs/tp_ChartType.cxx | 380 +++ chart2/source/controller/dialogs/tp_ChartType.hxx | 94 + chart2/source/controller/dialogs/tp_DataLabel.cxx | 54 + chart2/source/controller/dialogs/tp_DataLabel.hxx | 48 + .../controller/dialogs/tp_DataPointOption.cxx | 66 + .../controller/dialogs/tp_DataPointOption.hxx | 48 + chart2/source/controller/dialogs/tp_DataSource.cxx | 926 +++++++ chart2/source/controller/dialogs/tp_DataSource.hxx | 149 + chart2/source/controller/dialogs/tp_ErrorBars.cxx | 67 + chart2/source/controller/dialogs/tp_ErrorBars.hxx | 50 + .../controller/dialogs/tp_LegendPosition.cxx | 77 + .../controller/dialogs/tp_LegendPosition.hxx | 49 + .../source/controller/dialogs/tp_PointGeometry.cxx | 78 + .../source/controller/dialogs/tp_PointGeometry.hxx | 44 + .../source/controller/dialogs/tp_PolarOptions.cxx | 106 + .../source/controller/dialogs/tp_PolarOptions.hxx | 57 + .../source/controller/dialogs/tp_RangeChooser.cxx | 381 +++ .../source/controller/dialogs/tp_RangeChooser.hxx | 99 + chart2/source/controller/dialogs/tp_Scale.cxx | 637 +++++ chart2/source/controller/dialogs/tp_Scale.hxx | 109 + .../source/controller/dialogs/tp_SeriesToAxis.cxx | 248 ++ .../source/controller/dialogs/tp_SeriesToAxis.hxx | 77 + .../source/controller/dialogs/tp_TitleRotation.cxx | 123 + .../source/controller/dialogs/tp_TitleRotation.hxx | 62 + chart2/source/controller/dialogs/tp_Trendline.cxx | 59 + chart2/source/controller/dialogs/tp_Trendline.hxx | 46 + .../dialogs/tp_Wizard_TitlesAndObjects.cxx | 159 ++ .../dialogs/tp_Wizard_TitlesAndObjects.hxx | 72 + .../controller/drawinglayer/DrawViewWrapper.cxx | 357 +++ .../drawinglayer/ViewElementListProvider.cxx | 196 ++ chart2/source/controller/inc/AccessibleBase.hxx | 324 +++ .../source/controller/inc/AccessibleChartView.hxx | 118 + .../source/controller/inc/AccessibleTextHelper.hxx | 88 + chart2/source/controller/inc/AxisItemConverter.hxx | 74 + .../inc/CharacterPropertyItemConverter.hxx | 59 + chart2/source/controller/inc/ChartController.hxx | 562 ++++ .../source/controller/inc/ChartDocumentWrapper.hxx | 172 ++ .../controller/inc/ChartToolbarController.hxx | 79 + chart2/source/controller/inc/ChartWindow.hxx | 91 + .../controller/inc/CommandDispatchContainer.hxx | 136 + .../source/controller/inc/ConfigurationAccess.hxx | 38 + .../controller/inc/DataPointItemConverter.hxx | 90 + chart2/source/controller/inc/DrawViewWrapper.hxx | 100 + .../controller/inc/ErrorBarItemConverter.hxx | 60 + .../inc/GraphicPropertyItemConverter.hxx | 64 + chart2/source/controller/inc/ItemConverter.hxx | 185 ++ chart2/source/controller/inc/ItemPropertyMap.hxx | 34 + .../source/controller/inc/LegendItemConverter.hxx | 61 + .../controller/inc/MultipleChartConverters.hxx | 103 + .../controller/inc/MultipleItemConverter.hxx | 49 + chart2/source/controller/inc/ObjectHierarchy.hxx | 127 + .../source/controller/inc/ObjectNameProvider.hxx | 69 + .../controller/inc/PositionAndSizeHelper.hxx | 48 + .../source/controller/inc/RangeSelectionHelper.hxx | 71 + .../controller/inc/RangeSelectionListener.hxx | 70 + .../inc/RegressionCurveItemConverter.hxx | 60 + .../inc/RegressionEquationItemConverter.hxx | 61 + chart2/source/controller/inc/SelectionHelper.hxx | 115 + .../controller/inc/SeriesOptionsItemConverter.hxx | 83 + chart2/source/controller/inc/ShapeController.h | 38 + .../controller/inc/StatisticsItemConverter.hxx | 52 + chart2/source/controller/inc/TabPageNotifiable.hxx | 42 + .../source/controller/inc/TextDirectionListBox.hxx | 34 + .../controller/inc/TextLabelItemConverter.hxx | 74 + .../inc/TimerTriggeredControllerLock.hxx | 58 + chart2/source/controller/inc/TitleDialogData.hxx | 53 + .../source/controller/inc/TitleItemConverter.hxx | 59 + .../controller/inc/ViewElementListProvider.hxx | 63 + chart2/source/controller/inc/dlg_ChartType.hxx | 48 + chart2/source/controller/inc/dlg_ChartType_UNO.hxx | 67 + .../source/controller/inc/dlg_CreationWizard.hxx | 83 + .../controller/inc/dlg_CreationWizard_UNO.hxx | 116 + chart2/source/controller/inc/dlg_DataEditor.hxx | 73 + chart2/source/controller/inc/dlg_DataSource.hxx | 75 + .../source/controller/inc/dlg_InsertAxis_Grid.hxx | 68 + .../source/controller/inc/dlg_InsertDataLabel.hxx | 46 + .../source/controller/inc/dlg_InsertErrorBars.hxx | 56 + chart2/source/controller/inc/dlg_InsertLegend.hxx | 49 + chart2/source/controller/inc/dlg_InsertTitle.hxx | 40 + .../source/controller/inc/dlg_ObjectProperties.hxx | 145 + chart2/source/controller/inc/dlg_ShapeFont.hxx | 43 + .../source/controller/inc/dlg_ShapeParagraph.hxx | 38 + chart2/source/controller/inc/dlg_View3D.hxx | 58 + chart2/source/controller/inc/helpids.h | 32 + chart2/source/controller/inc/res_ErrorBar.hxx | 142 + .../source/controller/inc/res_LegendPosition.hxx | 75 + chart2/source/controller/inc/res_Titles.hxx | 73 + chart2/source/controller/inc/uiobject.hxx | 68 + .../itemsetwrapper/AxisItemConverter.cxx | 987 +++++++ .../CharacterPropertyItemConverter.cxx | 556 ++++ .../itemsetwrapper/DataPointItemConverter.cxx | 822 ++++++ .../itemsetwrapper/ErrorBarItemConverter.cxx | 433 +++ .../GraphicPropertyItemConverter.cxx | 751 ++++++ .../controller/itemsetwrapper/ItemConverter.cxx | 222 ++ .../itemsetwrapper/LegendItemConverter.cxx | 205 ++ .../itemsetwrapper/MultipleChartConverters.cxx | 192 ++ .../itemsetwrapper/MultipleItemConverter.cxx | 72 + .../RegressionCurveItemConverter.cxx | 350 +++ .../RegressionEquationItemConverter.cxx | 149 + .../controller/itemsetwrapper/SchWhichPairs.hxx | 174 ++ .../itemsetwrapper/SeriesOptionsItemConverter.cxx | 435 +++ .../itemsetwrapper/StatisticsItemConverter.cxx | 858 ++++++ .../itemsetwrapper/TextLabelItemConverter.cxx | 723 +++++ .../itemsetwrapper/TitleItemConverter.cxx | 210 ++ chart2/source/controller/main/ChartController.cxx | 1688 ++++++++++++ .../controller/main/ChartController_EditData.cxx | 54 + .../controller/main/ChartController_Insert.cxx | 869 ++++++ .../controller/main/ChartController_Position.cxx | 202 ++ .../controller/main/ChartController_Properties.cxx | 826 ++++++ .../controller/main/ChartController_TextEdit.cxx | 234 ++ .../controller/main/ChartController_Tools.cxx | 1107 ++++++++ .../controller/main/ChartController_Window.cxx | 2103 +++++++++++++++ .../controller/main/ChartDropTargetHelper.cxx | 177 ++ .../controller/main/ChartDropTargetHelper.hxx | 56 + chart2/source/controller/main/ChartFrameloader.cxx | 194 ++ chart2/source/controller/main/ChartFrameloader.hxx | 67 + chart2/source/controller/main/ChartModelClone.cxx | 231 ++ chart2/source/controller/main/ChartModelClone.hxx | 75 + .../source/controller/main/ChartTransferable.cxx | 162 ++ .../source/controller/main/ChartTransferable.hxx | 60 + chart2/source/controller/main/ChartWindow.cxx | 403 +++ chart2/source/controller/main/CommandDispatch.cxx | 157 ++ chart2/source/controller/main/CommandDispatch.hxx | 133 + .../controller/main/CommandDispatchContainer.cxx | 200 ++ .../source/controller/main/ConfigurationAccess.cxx | 93 + .../controller/main/ControllerCommandDispatch.cxx | 826 ++++++ .../controller/main/ControllerCommandDispatch.hxx | 119 + chart2/source/controller/main/DragMethod_Base.cxx | 76 + chart2/source/controller/main/DragMethod_Base.hxx | 59 + .../controller/main/DragMethod_PieSegment.cxx | 151 ++ .../controller/main/DragMethod_PieSegment.hxx | 54 + .../controller/main/DragMethod_RotateDiagram.cxx | 228 ++ .../controller/main/DragMethod_RotateDiagram.hxx | 86 + .../source/controller/main/DrawCommandDispatch.cxx | 614 +++++ .../source/controller/main/DrawCommandDispatch.h | 42 + .../source/controller/main/DrawCommandDispatch.hxx | 73 + chart2/source/controller/main/ElementSelector.cxx | 319 +++ chart2/source/controller/main/ElementSelector.hxx | 99 + .../controller/main/FeatureCommandDispatchBase.cxx | 94 + .../controller/main/FeatureCommandDispatchBase.hxx | 97 + chart2/source/controller/main/ObjectHierarchy.cxx | 718 +++++ .../controller/main/PositionAndSizeHelper.cxx | 179 ++ chart2/source/controller/main/SelectionHelper.cxx | 652 +++++ chart2/source/controller/main/ShapeController.cxx | 671 +++++ chart2/source/controller/main/ShapeController.hxx | 81 + .../controller/main/StatusBarCommandDispatch.cxx | 126 + .../controller/main/StatusBarCommandDispatch.hxx | 94 + .../source/controller/main/ToolbarController.cxx | 121 + chart2/source/controller/main/UndoActions.cxx | 116 + chart2/source/controller/main/UndoActions.hxx | 101 + .../source/controller/main/UndoCommandDispatch.cxx | 145 + .../source/controller/main/UndoCommandDispatch.hxx | 69 + chart2/source/controller/main/UndoGuard.cxx | 151 ++ chart2/source/controller/main/UndoGuard.hxx | 115 + .../controller/sidebar/Chart2PanelFactory.cxx | 147 + .../controller/sidebar/Chart2PanelFactory.hxx | 56 + .../source/controller/sidebar/ChartAreaPanel.cxx | 551 ++++ .../source/controller/sidebar/ChartAreaPanel.hxx | 86 + .../source/controller/sidebar/ChartAxisPanel.cxx | 373 +++ .../source/controller/sidebar/ChartAxisPanel.hxx | 93 + .../controller/sidebar/ChartColorWrapper.cxx | 233 ++ .../controller/sidebar/ChartColorWrapper.hxx | 68 + .../controller/sidebar/ChartElementsPanel.cxx | 662 +++++ .../controller/sidebar/ChartElementsPanel.hxx | 116 + .../controller/sidebar/ChartErrorBarPanel.cxx | 425 +++ .../controller/sidebar/ChartErrorBarPanel.hxx | 91 + .../source/controller/sidebar/ChartLinePanel.cxx | 293 ++ .../source/controller/sidebar/ChartLinePanel.hxx | 87 + .../source/controller/sidebar/ChartSeriesPanel.cxx | 474 ++++ .../source/controller/sidebar/ChartSeriesPanel.hxx | 110 + .../sidebar/ChartSidebarModifyListener.cxx | 39 + .../sidebar/ChartSidebarModifyListener.hxx | 42 + .../sidebar/ChartSidebarSelectionListener.cxx | 84 + .../sidebar/ChartSidebarSelectionListener.hxx | 52 + .../source/controller/sidebar/ChartTypePanel.cxx | 437 +++ .../source/controller/sidebar/ChartTypePanel.hxx | 121 + chart2/source/controller/uitest/uiobject.cxx | 201 ++ chart2/source/inc/Axis.hxx | 136 + chart2/source/inc/AxisHelper.hxx | 230 ++ chart2/source/inc/AxisIndexDefines.hxx | 30 + chart2/source/inc/BaseCoordinateSystem.hxx | 133 + chart2/source/inc/BaseGFXHelper.hxx | 86 + chart2/source/inc/CachedDataSequence.hxx | 164 ++ chart2/source/inc/ChangingResource.hxx | 46 + chart2/source/inc/CharacterProperties.hxx | 136 + chart2/source/inc/ChartModelHelper.hxx | 88 + chart2/source/inc/ChartResourceGroupDlgs.hxx | 63 + chart2/source/inc/ChartResourceGroups.hxx | 147 + chart2/source/inc/ChartType.hxx | 155 ++ chart2/source/inc/ChartTypeDialogController.hxx | 325 +++ chart2/source/inc/ChartTypeHelper.hxx | 89 + chart2/source/inc/ChartTypeTemplate.hxx | 283 ++ chart2/source/inc/ChartTypeTemplateProvider.hxx | 37 + chart2/source/inc/ChartViewHelper.hxx | 42 + chart2/source/inc/CloneHelper.hxx | 80 + chart2/source/inc/ColorPerPointHelper.hxx | 48 + chart2/source/inc/CommonConverters.hxx | 219 ++ chart2/source/inc/CommonFunctors.hxx | 126 + chart2/source/inc/ConfigColorScheme.hxx | 76 + chart2/source/inc/ControllerLockGuard.hxx | 95 + chart2/source/inc/DataInterpreter.hxx | 154 ++ chart2/source/inc/DataSeries.hxx | 180 ++ chart2/source/inc/DataSeriesHelper.hxx | 196 ++ chart2/source/inc/DataSource.hxx | 66 + chart2/source/inc/DataSourceHelper.hxx | 126 + chart2/source/inc/Diagram.hxx | 185 ++ chart2/source/inc/DiagramHelper.hxx | 308 +++ chart2/source/inc/DisposeHelper.hxx | 49 + chart2/source/inc/ErrorBar.hxx | 140 + chart2/source/inc/EventListenerHelper.hxx | 120 + chart2/source/inc/ExplicitCategoriesProvider.hxx | 114 + .../inc/ExponentialRegressionCurveCalculator.hxx | 62 + chart2/source/inc/FastPropertyIdRanges.hxx | 46 + chart2/source/inc/FillProperties.hxx | 74 + chart2/source/inc/FormattedStringHelper.hxx | 44 + chart2/source/inc/InternalData.hxx | 96 + chart2/source/inc/InternalDataProvider.hxx | 220 ++ chart2/source/inc/LabeledDataSequence.hxx | 90 + chart2/source/inc/Legend.hxx | 105 + chart2/source/inc/LegendHelper.hxx | 58 + chart2/source/inc/LifeTime.hxx | 213 ++ chart2/source/inc/LinePropertiesHelper.hxx | 68 + .../source/inc/LinearRegressionCurveCalculator.hxx | 51 + .../inc/LogarithmicRegressionCurveCalculator.hxx | 60 + .../inc/MeanValueRegressionCurveCalculator.hxx | 59 + chart2/source/inc/MediaDescriptorHelper.hxx | 90 + chart2/source/inc/ModifyListenerCallBack.hxx | 57 + chart2/source/inc/ModifyListenerHelper.hxx | 273 ++ .../inc/MovingAverageRegressionCurveCalculator.hxx | 63 + chart2/source/inc/NameContainer.hxx | 82 + chart2/source/inc/NumberFormatterWrapper.hxx | 68 + chart2/source/inc/OPropertySet.hxx | 235 ++ chart2/source/inc/ObjectIdentifier.hxx | 254 ++ .../inc/PolynomialRegressionCurveCalculator.hxx | 61 + chart2/source/inc/PopupRequest.hxx | 42 + .../inc/PotentialRegressionCurveCalculator.hxx | 61 + chart2/source/inc/PropertyHelper.hxx | 148 + chart2/source/inc/RangeHighlighter.hxx | 107 + chart2/source/inc/ReferenceSizeProvider.hxx | 130 + chart2/source/inc/RegressionCalculationHelper.hxx | 134 + chart2/source/inc/RegressionCurveCalculator.hxx | 103 + chart2/source/inc/RegressionCurveHelper.hxx | 205 ++ chart2/source/inc/RegressionCurveModel.hxx | 243 ++ chart2/source/inc/RelativePositionHelper.hxx | 103 + chart2/source/inc/RelativeSizeHelper.hxx | 56 + chart2/source/inc/ResId.hxx | 31 + chart2/source/inc/Scaling.hxx | 159 ++ chart2/source/inc/SceneProperties.hxx | 82 + chart2/source/inc/StackMode.hxx | 35 + chart2/source/inc/StatisticsHelper.hxx | 100 + chart2/source/inc/ThreeDHelper.hxx | 132 + chart2/source/inc/Title.hxx | 110 + chart2/source/inc/TitleHelper.hxx | 95 + chart2/source/inc/UncachedDataSequence.hxx | 173 ++ chart2/source/inc/UserDefinedProperties.hxx | 54 + chart2/source/inc/WeakListenerAdapter.hxx | 86 + chart2/source/inc/WrappedDefaultProperty.hxx | 51 + chart2/source/inc/WrappedDirectStateProperty.hxx | 40 + chart2/source/inc/WrappedIgnoreProperty.hxx | 62 + chart2/source/inc/WrappedProperty.hxx | 86 + chart2/source/inc/WrappedPropertySet.hxx | 122 + chart2/source/inc/XMLRangeHelper.hxx | 60 + chart2/source/inc/charttoolsdllapi.hxx | 32 + chart2/source/inc/chartview/ChartSfxItemIds.hxx | 229 ++ .../inc/chartview/DataPointSymbolSupplier.hxx | 42 + chart2/source/inc/chartview/DrawModelWrapper.hxx | 92 + .../source/inc/chartview/ExplicitScaleValues.hxx | 154 ++ .../source/inc/chartview/ExplicitValueProvider.hxx | 101 + chart2/source/inc/chartview/chartviewdllapi.hxx | 32 + chart2/source/inc/defines.hxx | 24 + chart2/source/inc/res_BarGeometry.hxx | 45 + chart2/source/inc/servicenames.hxx | 63 + chart2/source/inc/servicenames_charttypes.hxx | 44 + chart2/source/inc/servicenames_coosystems.hxx | 26 + chart2/source/model/filter/XMLFilter.cxx | 773 ++++++ .../source/model/inc/CartesianCoordinateSystem.hxx | 71 + chart2/source/model/inc/PolarCoordinateSystem.hxx | 71 + chart2/source/model/inc/StockBar.hxx | 94 + chart2/source/model/inc/XMLFilter.hxx | 166 ++ chart2/source/model/main/Axis.cxx | 615 +++++ chart2/source/model/main/BaseCoordinateSystem.cxx | 413 +++ .../model/main/CartesianCoordinateSystem.cxx | 160 ++ chart2/source/model/main/ChartModel.cxx | 1306 +++++++++ .../source/model/main/ChartModel_Persistence.cxx | 808 ++++++ chart2/source/model/main/DataPoint.cxx | 278 ++ chart2/source/model/main/DataPoint.hxx | 111 + chart2/source/model/main/DataPointProperties.cxx | 542 ++++ chart2/source/model/main/DataPointProperties.hxx | 103 + chart2/source/model/main/DataSeries.cxx | 566 ++++ chart2/source/model/main/DataSeriesProperties.cxx | 99 + chart2/source/model/main/DataSeriesProperties.hxx | 48 + chart2/source/model/main/Diagram.cxx | 699 +++++ chart2/source/model/main/FormattedString.cxx | 300 +++ chart2/source/model/main/FormattedString.hxx | 141 + chart2/source/model/main/GridProperties.cxx | 233 ++ chart2/source/model/main/GridProperties.hxx | 100 + chart2/source/model/main/Legend.cxx | 299 ++ chart2/source/model/main/PageBackground.cxx | 222 ++ chart2/source/model/main/PageBackground.hxx | 102 + chart2/source/model/main/PolarCoordinateSystem.cxx | 158 ++ chart2/source/model/main/StockBar.cxx | 205 ++ chart2/source/model/main/Title.cxx | 374 +++ chart2/source/model/main/UndoManager.cxx | 349 +++ chart2/source/model/main/UndoManager.hxx | 91 + chart2/source/model/main/Wall.cxx | 193 ++ chart2/source/model/main/Wall.hxx | 97 + chart2/source/model/template/AreaChartType.cxx | 84 + chart2/source/model/template/AreaChartType.hxx | 53 + .../model/template/AreaChartTypeTemplate.cxx | 221 ++ .../model/template/AreaChartTypeTemplate.hxx | 82 + chart2/source/model/template/BarChartType.cxx | 90 + chart2/source/model/template/BarChartType.hxx | 55 + .../source/model/template/BarChartTypeTemplate.cxx | 292 ++ .../source/model/template/BarChartTypeTemplate.hxx | 96 + chart2/source/model/template/BubbleChartType.cxx | 219 ++ chart2/source/model/template/BubbleChartType.hxx | 71 + .../model/template/BubbleChartTypeTemplate.cxx | 195 ++ .../model/template/BubbleChartTypeTemplate.hxx | 75 + .../model/template/BubbleDataInterpreter.cxx | 278 ++ .../model/template/BubbleDataInterpreter.hxx | 46 + .../source/model/template/CandleStickChartType.cxx | 348 +++ .../source/model/template/CandleStickChartType.hxx | 75 + chart2/source/model/template/ChartType.cxx | 335 +++ chart2/source/model/template/ChartTypeManager.cxx | 588 ++++ chart2/source/model/template/ChartTypeTemplate.cxx | 861 ++++++ chart2/source/model/template/ColumnChartType.cxx | 206 ++ chart2/source/model/template/ColumnChartType.hxx | 63 + .../model/template/ColumnLineChartTypeTemplate.cxx | 356 +++ .../model/template/ColumnLineChartTypeTemplate.hxx | 95 + .../model/template/ColumnLineDataInterpreter.cxx | 80 + .../model/template/ColumnLineDataInterpreter.hxx | 44 + chart2/source/model/template/DataInterpreter.cxx | 445 +++ .../source/model/template/FilledNetChartType.cxx | 89 + .../source/model/template/FilledNetChartType.hxx | 49 + chart2/source/model/template/LineChartType.cxx | 183 ++ chart2/source/model/template/LineChartType.hxx | 61 + .../model/template/LineChartTypeTemplate.cxx | 329 +++ .../model/template/LineChartTypeTemplate.hxx | 85 + chart2/source/model/template/NetChartType.cxx | 175 ++ chart2/source/model/template/NetChartType.hxx | 75 + .../source/model/template/NetChartTypeTemplate.cxx | 175 ++ .../source/model/template/NetChartTypeTemplate.hxx | 68 + chart2/source/model/template/PieChartType.cxx | 215 ++ chart2/source/model/template/PieChartType.hxx | 68 + .../source/model/template/PieChartTypeTemplate.cxx | 567 ++++ .../source/model/template/PieChartTypeTemplate.hxx | 106 + chart2/source/model/template/ScatterChartType.cxx | 221 ++ chart2/source/model/template/ScatterChartType.hxx | 68 + .../model/template/ScatterChartTypeTemplate.cxx | 345 +++ .../model/template/ScatterChartTypeTemplate.hxx | 86 + .../model/template/StockChartTypeTemplate.cxx | 435 +++ .../model/template/StockChartTypeTemplate.hxx | 113 + .../source/model/template/StockDataInterpreter.cxx | 342 +++ .../source/model/template/StockDataInterpreter.hxx | 56 + chart2/source/model/template/XYDataInterpreter.cxx | 243 ++ chart2/source/model/template/XYDataInterpreter.hxx | 46 + chart2/source/tools/AxisHelper.cxx | 1151 ++++++++ chart2/source/tools/BaseGFXHelper.cxx | 236 ++ chart2/source/tools/CachedDataSequence.cxx | 352 +++ chart2/source/tools/CharacterProperties.cxx | 459 ++++ chart2/source/tools/ChartModelHelper.cxx | 250 ++ chart2/source/tools/ChartTypeHelper.cxx | 724 +++++ chart2/source/tools/ChartViewHelper.cxx | 56 + chart2/source/tools/ColorPerPointHelper.cxx | 78 + chart2/source/tools/CommonConverters.cxx | 600 +++++ chart2/source/tools/ConfigColorScheme.cxx | 188 ++ chart2/source/tools/ControllerLockGuard.cxx | 84 + chart2/source/tools/DataSeriesHelper.cxx | 884 ++++++ chart2/source/tools/DataSource.cxx | 88 + chart2/source/tools/DataSourceHelper.cxx | 471 ++++ chart2/source/tools/DiagramHelper.cxx | 1571 +++++++++++ chart2/source/tools/ErrorBar.cxx | 470 ++++ chart2/source/tools/ExplicitCategoriesProvider.cxx | 564 ++++ .../tools/ExponentialRegressionCurveCalculator.cxx | 221 ++ chart2/source/tools/FillProperties.cxx | 200 ++ chart2/source/tools/FormattedStringHelper.cxx | 63 + chart2/source/tools/InternalData.cxx | 557 ++++ chart2/source/tools/InternalDataProvider.cxx | 1553 +++++++++++ chart2/source/tools/LabeledDataSequence.cxx | 176 ++ chart2/source/tools/LegendHelper.cxx | 122 + chart2/source/tools/LifeTime.cxx | 441 +++ chart2/source/tools/LinePropertiesHelper.cxx | 192 ++ .../tools/LinearRegressionCurveCalculator.cxx | 69 + .../tools/LogarithmicRegressionCurveCalculator.cxx | 186 ++ .../tools/MeanValueRegressionCurveCalculator.cxx | 126 + chart2/source/tools/MediaDescriptorHelper.cxx | 225 ++ chart2/source/tools/ModifyListenerCallBack.cxx | 111 + chart2/source/tools/ModifyListenerHelper.cxx | 74 + .../MovingAverageRegressionCurveCalculator.cxx | 165 ++ chart2/source/tools/NameContainer.cxx | 128 + chart2/source/tools/NumberFormatterWrapper.cxx | 149 + chart2/source/tools/OPropertySet.cxx | 464 ++++ chart2/source/tools/ObjectIdentifier.cxx | 1379 ++++++++++ .../tools/PolynomialRegressionCurveCalculator.cxx | 392 +++ chart2/source/tools/PopupRequest.cxx | 31 + .../tools/PotentialRegressionCurveCalculator.cxx | 188 ++ chart2/source/tools/PropertyHelper.cxx | 296 ++ chart2/source/tools/RangeHighlighter.cxx | 394 +++ chart2/source/tools/ReferenceSizeProvider.cxx | 333 +++ chart2/source/tools/RegressionCurveCalculator.cxx | 217 ++ chart2/source/tools/RegressionCurveHelper.cxx | 920 +++++++ chart2/source/tools/RegressionCurveModel.cxx | 541 ++++ chart2/source/tools/RegressionEquation.cxx | 294 ++ chart2/source/tools/RegressionEquation.hxx | 118 + chart2/source/tools/RelativePositionHelper.cxx | 381 +++ chart2/source/tools/RelativeSizeHelper.cxx | 121 + chart2/source/tools/ResId.cxx | 30 + chart2/source/tools/Scaling.cxx | 267 ++ chart2/source/tools/SceneProperties.cxx | 333 +++ chart2/source/tools/StatisticsHelper.cxx | 363 +++ chart2/source/tools/ThreeDHelper.cxx | 1457 ++++++++++ chart2/source/tools/TitleHelper.cxx | 420 +++ chart2/source/tools/UncachedDataSequence.cxx | 316 +++ chart2/source/tools/UserDefinedProperties.cxx | 61 + chart2/source/tools/WeakListenerAdapter.cxx | 46 + chart2/source/tools/WrappedDefaultProperty.cxx | 77 + chart2/source/tools/WrappedDirectStateProperty.cxx | 45 + chart2/source/tools/WrappedIgnoreProperty.cxx | 113 + chart2/source/tools/WrappedProperty.cxx | 125 + chart2/source/tools/WrappedPropertySet.cxx | 445 +++ chart2/source/tools/XMLRangeHelper.cxx | 393 +++ chart2/source/view/axes/DateHelper.cxx | 93 + chart2/source/view/axes/DateScaling.cxx | 205 ++ chart2/source/view/axes/DateScaling.hxx | 95 + .../source/view/axes/MinimumAndMaximumSupplier.cxx | 203 ++ chart2/source/view/axes/ScaleAutomatism.cxx | 989 +++++++ chart2/source/view/axes/TickmarkProperties.hxx | 37 + chart2/source/view/axes/Tickmarks.cxx | 317 +++ chart2/source/view/axes/Tickmarks.hxx | 162 ++ chart2/source/view/axes/Tickmarks_Dates.cxx | 150 ++ chart2/source/view/axes/Tickmarks_Dates.hxx | 49 + chart2/source/view/axes/Tickmarks_Equidistant.cxx | 625 +++++ chart2/source/view/axes/Tickmarks_Equidistant.hxx | 146 + chart2/source/view/axes/VAxisBase.cxx | 244 ++ chart2/source/view/axes/VAxisBase.hxx | 102 + chart2/source/view/axes/VAxisOrGridBase.cxx | 70 + chart2/source/view/axes/VAxisOrGridBase.hxx | 63 + chart2/source/view/axes/VAxisProperties.cxx | 392 +++ chart2/source/view/axes/VAxisProperties.hxx | 164 ++ chart2/source/view/axes/VCartesianAxis.cxx | 1971 ++++++++++++++ chart2/source/view/axes/VCartesianAxis.hxx | 160 ++ .../view/axes/VCartesianCoordinateSystem.cxx | 216 ++ .../view/axes/VCartesianCoordinateSystem.hxx | 47 + chart2/source/view/axes/VCartesianGrid.cxx | 309 +++ chart2/source/view/axes/VCartesianGrid.hxx | 52 + chart2/source/view/axes/VCoordinateSystem.cxx | 576 ++++ chart2/source/view/axes/VPolarAngleAxis.cxx | 205 ++ chart2/source/view/axes/VPolarAngleAxis.hxx | 51 + chart2/source/view/axes/VPolarAxis.cxx | 64 + chart2/source/view/axes/VPolarAxis.hxx | 54 + chart2/source/view/axes/VPolarCoordinateSystem.cxx | 190 ++ chart2/source/view/axes/VPolarCoordinateSystem.hxx | 51 + chart2/source/view/axes/VPolarGrid.cxx | 247 ++ chart2/source/view/axes/VPolarGrid.hxx | 71 + chart2/source/view/axes/VPolarRadiusAxis.cxx | 165 ++ chart2/source/view/axes/VPolarRadiusAxis.hxx | 72 + chart2/source/view/charttypes/AreaChart.cxx | 952 +++++++ chart2/source/view/charttypes/AreaChart.hxx | 86 + chart2/source/view/charttypes/BarChart.cxx | 976 +++++++ chart2/source/view/charttypes/BarChart.hxx | 118 + .../source/view/charttypes/BarPositionHelper.cxx | 73 + .../source/view/charttypes/BarPositionHelper.hxx | 44 + chart2/source/view/charttypes/BubbleChart.cxx | 362 +++ chart2/source/view/charttypes/BubbleChart.hxx | 60 + chart2/source/view/charttypes/CandleStickChart.cxx | 314 +++ chart2/source/view/charttypes/CandleStickChart.hxx | 54 + .../view/charttypes/CategoryPositionHelper.cxx | 82 + .../view/charttypes/CategoryPositionHelper.hxx | 57 + chart2/source/view/charttypes/ConfigAccess.cxx | 74 + chart2/source/view/charttypes/NetChart.cxx | 642 +++++ chart2/source/view/charttypes/NetChart.hxx | 74 + chart2/source/view/charttypes/PieChart.cxx | 1719 ++++++++++++ chart2/source/view/charttypes/PieChart.hxx | 145 + chart2/source/view/charttypes/Splines.cxx | 872 ++++++ chart2/source/view/charttypes/Splines.hxx | 48 + chart2/source/view/charttypes/VSeriesPlotter.cxx | 2847 ++++++++++++++++++++ chart2/source/view/diagram/VDiagram.cxx | 703 +++++ chart2/source/view/inc/Clipping.hxx | 61 + chart2/source/view/inc/ConfigAccess.hxx | 35 + chart2/source/view/inc/DateHelper.hxx | 43 + chart2/source/view/inc/LabelAlignment.hxx | 38 + chart2/source/view/inc/LabelPositionHelper.hxx | 66 + chart2/source/view/inc/LegendEntryProvider.hxx | 89 + chart2/source/view/inc/Linear3DTransformation.hxx | 46 + .../source/view/inc/MinimumAndMaximumSupplier.hxx | 92 + chart2/source/view/inc/PlotterBase.hxx | 79 + chart2/source/view/inc/PlottingPositionHelper.hxx | 467 ++++ .../source/view/inc/PolarLabelPositionHelper.hxx | 70 + chart2/source/view/inc/PropertyMapper.hxx | 125 + chart2/source/view/inc/ScaleAutomatism.hxx | 144 + chart2/source/view/inc/ShapeFactory.hxx | 301 +++ chart2/source/view/inc/Stripe.hxx | 71 + chart2/source/view/inc/VCoordinateSystem.hxx | 205 ++ chart2/source/view/inc/VDataSeries.hxx | 267 ++ chart2/source/view/inc/VDiagram.hxx | 117 + chart2/source/view/inc/VLegendSymbolFactory.hxx | 53 + chart2/source/view/inc/VLineProperties.hxx | 49 + chart2/source/view/inc/VPolarTransformation.hxx | 45 + chart2/source/view/inc/VSeriesPlotter.hxx | 436 +++ chart2/source/view/inc/ViewDefines.hxx | 35 + chart2/source/view/main/AxisUsage.hxx | 143 + chart2/source/view/main/ChartItemPool.cxx | 226 ++ chart2/source/view/main/ChartItemPool.hxx | 48 + chart2/source/view/main/ChartView.cxx | 2035 ++++++++++++++ chart2/source/view/main/Clipping.cxx | 425 +++ .../source/view/main/DataPointSymbolSupplier.cxx | 44 + chart2/source/view/main/DrawModelWrapper.cxx | 335 +++ chart2/source/view/main/ExplicitValueProvider.cxx | 211 ++ chart2/source/view/main/LabelPositionHelper.cxx | 467 ++++ chart2/source/view/main/Linear3DTransformation.cxx | 124 + chart2/source/view/main/PlotterBase.cxx | 106 + chart2/source/view/main/PlottingPositionHelper.cxx | 708 +++++ .../source/view/main/PolarLabelPositionHelper.cxx | 158 ++ chart2/source/view/main/PropertyMapper.cxx | 561 ++++ chart2/source/view/main/SeriesPlotterContainer.cxx | 739 +++++ chart2/source/view/main/SeriesPlotterContainer.hxx | 159 ++ chart2/source/view/main/ShapeFactory.cxx | 2551 ++++++++++++++++++ chart2/source/view/main/Stripe.cxx | 347 +++ chart2/source/view/main/VButton.cxx | 136 + chart2/source/view/main/VButton.hxx | 86 + chart2/source/view/main/VDataSeries.cxx | 1118 ++++++++ chart2/source/view/main/VLegend.cxx | 1099 ++++++++ chart2/source/view/main/VLegend.hxx | 91 + chart2/source/view/main/VLegendSymbolFactory.cxx | 188 ++ chart2/source/view/main/VLineProperties.cxx | 85 + chart2/source/view/main/VPolarTransformation.cxx | 88 + chart2/source/view/main/VTitle.cxx | 158 ++ chart2/source/view/main/VTitle.hxx | 72 + 651 files changed, 156070 insertions(+) create mode 100644 chart2/source/chartcore.component create mode 100644 chart2/source/controller/accessibility/AccessibleBase.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleChartElement.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleChartElement.hxx create mode 100644 chart2/source/controller/accessibility/AccessibleChartShape.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleChartShape.hxx create mode 100644 chart2/source/controller/accessibility/AccessibleChartView.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleTextHelper.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleViewForwarder.cxx create mode 100644 chart2/source/controller/accessibility/AccessibleViewForwarder.hxx create mode 100644 chart2/source/controller/accessibility/ChartElementFactory.cxx create mode 100644 chart2/source/controller/accessibility/ChartElementFactory.hxx create mode 100644 chart2/source/controller/chartapiwrapper/AreaWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/AreaWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/AxisWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/AxisWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx create mode 100644 chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx create mode 100644 chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/GridWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/GridWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/LegendWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/LegendWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx create mode 100644 chart2/source/controller/chartapiwrapper/TitleWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/TitleWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx create mode 100644 chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx create mode 100644 chart2/source/controller/chartcontroller.component create mode 100644 chart2/source/controller/dialogs/ChangingResource.cxx create mode 100644 chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx create mode 100644 chart2/source/controller/dialogs/ChartResourceGroups.cxx create mode 100644 chart2/source/controller/dialogs/ChartTypeDialogController.cxx create mode 100644 chart2/source/controller/dialogs/DataBrowser.cxx create mode 100644 chart2/source/controller/dialogs/DataBrowser.hxx create mode 100644 chart2/source/controller/dialogs/DataBrowserModel.cxx create mode 100644 chart2/source/controller/dialogs/DataBrowserModel.hxx create mode 100644 chart2/source/controller/dialogs/DialogModel.cxx create mode 100644 chart2/source/controller/dialogs/DialogModel.hxx create mode 100644 chart2/source/controller/dialogs/ObjectNameProvider.cxx create mode 100644 chart2/source/controller/dialogs/RangeSelectionHelper.cxx create mode 100644 chart2/source/controller/dialogs/RangeSelectionListener.cxx create mode 100644 chart2/source/controller/dialogs/TextDirectionListBox.cxx create mode 100644 chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx create mode 100644 chart2/source/controller/dialogs/TitleDialogData.cxx create mode 100644 chart2/source/controller/dialogs/dlg_ChartType.cxx create mode 100644 chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx create mode 100644 chart2/source/controller/dialogs/dlg_CreationWizard.cxx create mode 100644 chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx create mode 100644 chart2/source/controller/dialogs/dlg_DataEditor.cxx create mode 100644 chart2/source/controller/dialogs/dlg_DataSource.cxx create mode 100644 chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx create mode 100644 chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx create mode 100644 chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx create mode 100644 chart2/source/controller/dialogs/dlg_InsertLegend.cxx create mode 100644 chart2/source/controller/dialogs/dlg_InsertTitle.cxx create mode 100644 chart2/source/controller/dialogs/dlg_NumberFormat.cxx create mode 100644 chart2/source/controller/dialogs/dlg_NumberFormat.hxx create mode 100644 chart2/source/controller/dialogs/dlg_ObjectProperties.cxx create mode 100644 chart2/source/controller/dialogs/dlg_ShapeFont.cxx create mode 100644 chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx create mode 100644 chart2/source/controller/dialogs/dlg_View3D.cxx create mode 100644 chart2/source/controller/dialogs/res_BarGeometry.cxx create mode 100644 chart2/source/controller/dialogs/res_DataLabel.cxx create mode 100644 chart2/source/controller/dialogs/res_DataLabel.hxx create mode 100644 chart2/source/controller/dialogs/res_ErrorBar.cxx create mode 100644 chart2/source/controller/dialogs/res_LegendPosition.cxx create mode 100644 chart2/source/controller/dialogs/res_Titles.cxx create mode 100644 chart2/source/controller/dialogs/res_Trendline.cxx create mode 100644 chart2/source/controller/dialogs/res_Trendline.hxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx create mode 100644 chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx create mode 100644 chart2/source/controller/dialogs/tp_AxisLabel.cxx create mode 100644 chart2/source/controller/dialogs/tp_AxisLabel.hxx create mode 100644 chart2/source/controller/dialogs/tp_AxisPositions.cxx create mode 100644 chart2/source/controller/dialogs/tp_AxisPositions.hxx create mode 100644 chart2/source/controller/dialogs/tp_ChartType.cxx create mode 100644 chart2/source/controller/dialogs/tp_ChartType.hxx create mode 100644 chart2/source/controller/dialogs/tp_DataLabel.cxx create mode 100644 chart2/source/controller/dialogs/tp_DataLabel.hxx create mode 100644 chart2/source/controller/dialogs/tp_DataPointOption.cxx create mode 100644 chart2/source/controller/dialogs/tp_DataPointOption.hxx create mode 100644 chart2/source/controller/dialogs/tp_DataSource.cxx create mode 100644 chart2/source/controller/dialogs/tp_DataSource.hxx create mode 100644 chart2/source/controller/dialogs/tp_ErrorBars.cxx create mode 100644 chart2/source/controller/dialogs/tp_ErrorBars.hxx create mode 100644 chart2/source/controller/dialogs/tp_LegendPosition.cxx create mode 100644 chart2/source/controller/dialogs/tp_LegendPosition.hxx create mode 100644 chart2/source/controller/dialogs/tp_PointGeometry.cxx create mode 100644 chart2/source/controller/dialogs/tp_PointGeometry.hxx create mode 100644 chart2/source/controller/dialogs/tp_PolarOptions.cxx create mode 100644 chart2/source/controller/dialogs/tp_PolarOptions.hxx create mode 100644 chart2/source/controller/dialogs/tp_RangeChooser.cxx create mode 100644 chart2/source/controller/dialogs/tp_RangeChooser.hxx create mode 100644 chart2/source/controller/dialogs/tp_Scale.cxx create mode 100644 chart2/source/controller/dialogs/tp_Scale.hxx create mode 100644 chart2/source/controller/dialogs/tp_SeriesToAxis.cxx create mode 100644 chart2/source/controller/dialogs/tp_SeriesToAxis.hxx create mode 100644 chart2/source/controller/dialogs/tp_TitleRotation.cxx create mode 100644 chart2/source/controller/dialogs/tp_TitleRotation.hxx create mode 100644 chart2/source/controller/dialogs/tp_Trendline.cxx create mode 100644 chart2/source/controller/dialogs/tp_Trendline.hxx create mode 100644 chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx create mode 100644 chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx create mode 100644 chart2/source/controller/drawinglayer/DrawViewWrapper.cxx create mode 100644 chart2/source/controller/drawinglayer/ViewElementListProvider.cxx create mode 100644 chart2/source/controller/inc/AccessibleBase.hxx create mode 100644 chart2/source/controller/inc/AccessibleChartView.hxx create mode 100644 chart2/source/controller/inc/AccessibleTextHelper.hxx create mode 100644 chart2/source/controller/inc/AxisItemConverter.hxx create mode 100644 chart2/source/controller/inc/CharacterPropertyItemConverter.hxx create mode 100644 chart2/source/controller/inc/ChartController.hxx create mode 100644 chart2/source/controller/inc/ChartDocumentWrapper.hxx create mode 100644 chart2/source/controller/inc/ChartToolbarController.hxx create mode 100644 chart2/source/controller/inc/ChartWindow.hxx create mode 100644 chart2/source/controller/inc/CommandDispatchContainer.hxx create mode 100644 chart2/source/controller/inc/ConfigurationAccess.hxx create mode 100644 chart2/source/controller/inc/DataPointItemConverter.hxx create mode 100644 chart2/source/controller/inc/DrawViewWrapper.hxx create mode 100644 chart2/source/controller/inc/ErrorBarItemConverter.hxx create mode 100644 chart2/source/controller/inc/GraphicPropertyItemConverter.hxx create mode 100644 chart2/source/controller/inc/ItemConverter.hxx create mode 100644 chart2/source/controller/inc/ItemPropertyMap.hxx create mode 100644 chart2/source/controller/inc/LegendItemConverter.hxx create mode 100644 chart2/source/controller/inc/MultipleChartConverters.hxx create mode 100644 chart2/source/controller/inc/MultipleItemConverter.hxx create mode 100644 chart2/source/controller/inc/ObjectHierarchy.hxx create mode 100644 chart2/source/controller/inc/ObjectNameProvider.hxx create mode 100644 chart2/source/controller/inc/PositionAndSizeHelper.hxx create mode 100644 chart2/source/controller/inc/RangeSelectionHelper.hxx create mode 100644 chart2/source/controller/inc/RangeSelectionListener.hxx create mode 100644 chart2/source/controller/inc/RegressionCurveItemConverter.hxx create mode 100644 chart2/source/controller/inc/RegressionEquationItemConverter.hxx create mode 100644 chart2/source/controller/inc/SelectionHelper.hxx create mode 100644 chart2/source/controller/inc/SeriesOptionsItemConverter.hxx create mode 100644 chart2/source/controller/inc/ShapeController.h create mode 100644 chart2/source/controller/inc/StatisticsItemConverter.hxx create mode 100644 chart2/source/controller/inc/TabPageNotifiable.hxx create mode 100644 chart2/source/controller/inc/TextDirectionListBox.hxx create mode 100644 chart2/source/controller/inc/TextLabelItemConverter.hxx create mode 100644 chart2/source/controller/inc/TimerTriggeredControllerLock.hxx create mode 100644 chart2/source/controller/inc/TitleDialogData.hxx create mode 100644 chart2/source/controller/inc/TitleItemConverter.hxx create mode 100644 chart2/source/controller/inc/ViewElementListProvider.hxx create mode 100644 chart2/source/controller/inc/dlg_ChartType.hxx create mode 100644 chart2/source/controller/inc/dlg_ChartType_UNO.hxx create mode 100644 chart2/source/controller/inc/dlg_CreationWizard.hxx create mode 100644 chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx create mode 100644 chart2/source/controller/inc/dlg_DataEditor.hxx create mode 100644 chart2/source/controller/inc/dlg_DataSource.hxx create mode 100644 chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx create mode 100644 chart2/source/controller/inc/dlg_InsertDataLabel.hxx create mode 100644 chart2/source/controller/inc/dlg_InsertErrorBars.hxx create mode 100644 chart2/source/controller/inc/dlg_InsertLegend.hxx create mode 100644 chart2/source/controller/inc/dlg_InsertTitle.hxx create mode 100644 chart2/source/controller/inc/dlg_ObjectProperties.hxx create mode 100644 chart2/source/controller/inc/dlg_ShapeFont.hxx create mode 100644 chart2/source/controller/inc/dlg_ShapeParagraph.hxx create mode 100644 chart2/source/controller/inc/dlg_View3D.hxx create mode 100644 chart2/source/controller/inc/helpids.h create mode 100644 chart2/source/controller/inc/res_ErrorBar.hxx create mode 100644 chart2/source/controller/inc/res_LegendPosition.hxx create mode 100644 chart2/source/controller/inc/res_Titles.hxx create mode 100644 chart2/source/controller/inc/uiobject.hxx create mode 100644 chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/ItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx create mode 100644 chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx create mode 100644 chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx create mode 100644 chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx create mode 100644 chart2/source/controller/main/ChartController.cxx create mode 100644 chart2/source/controller/main/ChartController_EditData.cxx create mode 100644 chart2/source/controller/main/ChartController_Insert.cxx create mode 100644 chart2/source/controller/main/ChartController_Position.cxx create mode 100644 chart2/source/controller/main/ChartController_Properties.cxx create mode 100644 chart2/source/controller/main/ChartController_TextEdit.cxx create mode 100644 chart2/source/controller/main/ChartController_Tools.cxx create mode 100644 chart2/source/controller/main/ChartController_Window.cxx create mode 100644 chart2/source/controller/main/ChartDropTargetHelper.cxx create mode 100644 chart2/source/controller/main/ChartDropTargetHelper.hxx create mode 100644 chart2/source/controller/main/ChartFrameloader.cxx create mode 100644 chart2/source/controller/main/ChartFrameloader.hxx create mode 100644 chart2/source/controller/main/ChartModelClone.cxx create mode 100644 chart2/source/controller/main/ChartModelClone.hxx create mode 100644 chart2/source/controller/main/ChartTransferable.cxx create mode 100644 chart2/source/controller/main/ChartTransferable.hxx create mode 100644 chart2/source/controller/main/ChartWindow.cxx create mode 100644 chart2/source/controller/main/CommandDispatch.cxx create mode 100644 chart2/source/controller/main/CommandDispatch.hxx create mode 100644 chart2/source/controller/main/CommandDispatchContainer.cxx create mode 100644 chart2/source/controller/main/ConfigurationAccess.cxx create mode 100644 chart2/source/controller/main/ControllerCommandDispatch.cxx create mode 100644 chart2/source/controller/main/ControllerCommandDispatch.hxx create mode 100644 chart2/source/controller/main/DragMethod_Base.cxx create mode 100644 chart2/source/controller/main/DragMethod_Base.hxx create mode 100644 chart2/source/controller/main/DragMethod_PieSegment.cxx create mode 100644 chart2/source/controller/main/DragMethod_PieSegment.hxx create mode 100644 chart2/source/controller/main/DragMethod_RotateDiagram.cxx create mode 100644 chart2/source/controller/main/DragMethod_RotateDiagram.hxx create mode 100644 chart2/source/controller/main/DrawCommandDispatch.cxx create mode 100644 chart2/source/controller/main/DrawCommandDispatch.h create mode 100644 chart2/source/controller/main/DrawCommandDispatch.hxx create mode 100644 chart2/source/controller/main/ElementSelector.cxx create mode 100644 chart2/source/controller/main/ElementSelector.hxx create mode 100644 chart2/source/controller/main/FeatureCommandDispatchBase.cxx create mode 100644 chart2/source/controller/main/FeatureCommandDispatchBase.hxx create mode 100644 chart2/source/controller/main/ObjectHierarchy.cxx create mode 100644 chart2/source/controller/main/PositionAndSizeHelper.cxx create mode 100644 chart2/source/controller/main/SelectionHelper.cxx create mode 100644 chart2/source/controller/main/ShapeController.cxx create mode 100644 chart2/source/controller/main/ShapeController.hxx create mode 100644 chart2/source/controller/main/StatusBarCommandDispatch.cxx create mode 100644 chart2/source/controller/main/StatusBarCommandDispatch.hxx create mode 100644 chart2/source/controller/main/ToolbarController.cxx create mode 100644 chart2/source/controller/main/UndoActions.cxx create mode 100644 chart2/source/controller/main/UndoActions.hxx create mode 100644 chart2/source/controller/main/UndoCommandDispatch.cxx create mode 100644 chart2/source/controller/main/UndoCommandDispatch.hxx create mode 100644 chart2/source/controller/main/UndoGuard.cxx create mode 100644 chart2/source/controller/main/UndoGuard.hxx create mode 100644 chart2/source/controller/sidebar/Chart2PanelFactory.cxx create mode 100644 chart2/source/controller/sidebar/Chart2PanelFactory.hxx create mode 100644 chart2/source/controller/sidebar/ChartAreaPanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartAreaPanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartAxisPanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartAxisPanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartColorWrapper.cxx create mode 100644 chart2/source/controller/sidebar/ChartColorWrapper.hxx create mode 100644 chart2/source/controller/sidebar/ChartElementsPanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartElementsPanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartErrorBarPanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartErrorBarPanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartLinePanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartLinePanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartSeriesPanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartSeriesPanel.hxx create mode 100644 chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx create mode 100644 chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx create mode 100644 chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx create mode 100644 chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx create mode 100644 chart2/source/controller/sidebar/ChartTypePanel.cxx create mode 100644 chart2/source/controller/sidebar/ChartTypePanel.hxx create mode 100644 chart2/source/controller/uitest/uiobject.cxx create mode 100644 chart2/source/inc/Axis.hxx create mode 100644 chart2/source/inc/AxisHelper.hxx create mode 100644 chart2/source/inc/AxisIndexDefines.hxx create mode 100644 chart2/source/inc/BaseCoordinateSystem.hxx create mode 100644 chart2/source/inc/BaseGFXHelper.hxx create mode 100644 chart2/source/inc/CachedDataSequence.hxx create mode 100644 chart2/source/inc/ChangingResource.hxx create mode 100644 chart2/source/inc/CharacterProperties.hxx create mode 100644 chart2/source/inc/ChartModelHelper.hxx create mode 100644 chart2/source/inc/ChartResourceGroupDlgs.hxx create mode 100644 chart2/source/inc/ChartResourceGroups.hxx create mode 100644 chart2/source/inc/ChartType.hxx create mode 100644 chart2/source/inc/ChartTypeDialogController.hxx create mode 100644 chart2/source/inc/ChartTypeHelper.hxx create mode 100644 chart2/source/inc/ChartTypeTemplate.hxx create mode 100644 chart2/source/inc/ChartTypeTemplateProvider.hxx create mode 100644 chart2/source/inc/ChartViewHelper.hxx create mode 100644 chart2/source/inc/CloneHelper.hxx create mode 100644 chart2/source/inc/ColorPerPointHelper.hxx create mode 100644 chart2/source/inc/CommonConverters.hxx create mode 100644 chart2/source/inc/CommonFunctors.hxx create mode 100644 chart2/source/inc/ConfigColorScheme.hxx create mode 100644 chart2/source/inc/ControllerLockGuard.hxx create mode 100644 chart2/source/inc/DataInterpreter.hxx create mode 100644 chart2/source/inc/DataSeries.hxx create mode 100644 chart2/source/inc/DataSeriesHelper.hxx create mode 100644 chart2/source/inc/DataSource.hxx create mode 100644 chart2/source/inc/DataSourceHelper.hxx create mode 100644 chart2/source/inc/Diagram.hxx create mode 100644 chart2/source/inc/DiagramHelper.hxx create mode 100644 chart2/source/inc/DisposeHelper.hxx create mode 100644 chart2/source/inc/ErrorBar.hxx create mode 100644 chart2/source/inc/EventListenerHelper.hxx create mode 100644 chart2/source/inc/ExplicitCategoriesProvider.hxx create mode 100644 chart2/source/inc/ExponentialRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/FastPropertyIdRanges.hxx create mode 100644 chart2/source/inc/FillProperties.hxx create mode 100644 chart2/source/inc/FormattedStringHelper.hxx create mode 100644 chart2/source/inc/InternalData.hxx create mode 100644 chart2/source/inc/InternalDataProvider.hxx create mode 100644 chart2/source/inc/LabeledDataSequence.hxx create mode 100644 chart2/source/inc/Legend.hxx create mode 100644 chart2/source/inc/LegendHelper.hxx create mode 100644 chart2/source/inc/LifeTime.hxx create mode 100644 chart2/source/inc/LinePropertiesHelper.hxx create mode 100644 chart2/source/inc/LinearRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/LogarithmicRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/MeanValueRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/MediaDescriptorHelper.hxx create mode 100644 chart2/source/inc/ModifyListenerCallBack.hxx create mode 100644 chart2/source/inc/ModifyListenerHelper.hxx create mode 100644 chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/NameContainer.hxx create mode 100644 chart2/source/inc/NumberFormatterWrapper.hxx create mode 100644 chart2/source/inc/OPropertySet.hxx create mode 100644 chart2/source/inc/ObjectIdentifier.hxx create mode 100644 chart2/source/inc/PolynomialRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/PopupRequest.hxx create mode 100644 chart2/source/inc/PotentialRegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/PropertyHelper.hxx create mode 100644 chart2/source/inc/RangeHighlighter.hxx create mode 100644 chart2/source/inc/ReferenceSizeProvider.hxx create mode 100644 chart2/source/inc/RegressionCalculationHelper.hxx create mode 100644 chart2/source/inc/RegressionCurveCalculator.hxx create mode 100644 chart2/source/inc/RegressionCurveHelper.hxx create mode 100644 chart2/source/inc/RegressionCurveModel.hxx create mode 100644 chart2/source/inc/RelativePositionHelper.hxx create mode 100644 chart2/source/inc/RelativeSizeHelper.hxx create mode 100644 chart2/source/inc/ResId.hxx create mode 100644 chart2/source/inc/Scaling.hxx create mode 100644 chart2/source/inc/SceneProperties.hxx create mode 100644 chart2/source/inc/StackMode.hxx create mode 100644 chart2/source/inc/StatisticsHelper.hxx create mode 100644 chart2/source/inc/ThreeDHelper.hxx create mode 100644 chart2/source/inc/Title.hxx create mode 100644 chart2/source/inc/TitleHelper.hxx create mode 100644 chart2/source/inc/UncachedDataSequence.hxx create mode 100644 chart2/source/inc/UserDefinedProperties.hxx create mode 100644 chart2/source/inc/WeakListenerAdapter.hxx create mode 100644 chart2/source/inc/WrappedDefaultProperty.hxx create mode 100644 chart2/source/inc/WrappedDirectStateProperty.hxx create mode 100644 chart2/source/inc/WrappedIgnoreProperty.hxx create mode 100644 chart2/source/inc/WrappedProperty.hxx create mode 100644 chart2/source/inc/WrappedPropertySet.hxx create mode 100644 chart2/source/inc/XMLRangeHelper.hxx create mode 100644 chart2/source/inc/charttoolsdllapi.hxx create mode 100644 chart2/source/inc/chartview/ChartSfxItemIds.hxx create mode 100644 chart2/source/inc/chartview/DataPointSymbolSupplier.hxx create mode 100644 chart2/source/inc/chartview/DrawModelWrapper.hxx create mode 100644 chart2/source/inc/chartview/ExplicitScaleValues.hxx create mode 100644 chart2/source/inc/chartview/ExplicitValueProvider.hxx create mode 100644 chart2/source/inc/chartview/chartviewdllapi.hxx create mode 100644 chart2/source/inc/defines.hxx create mode 100644 chart2/source/inc/res_BarGeometry.hxx create mode 100644 chart2/source/inc/servicenames.hxx create mode 100644 chart2/source/inc/servicenames_charttypes.hxx create mode 100644 chart2/source/inc/servicenames_coosystems.hxx create mode 100644 chart2/source/model/filter/XMLFilter.cxx create mode 100644 chart2/source/model/inc/CartesianCoordinateSystem.hxx create mode 100644 chart2/source/model/inc/PolarCoordinateSystem.hxx create mode 100644 chart2/source/model/inc/StockBar.hxx create mode 100644 chart2/source/model/inc/XMLFilter.hxx create mode 100644 chart2/source/model/main/Axis.cxx create mode 100644 chart2/source/model/main/BaseCoordinateSystem.cxx create mode 100644 chart2/source/model/main/CartesianCoordinateSystem.cxx create mode 100644 chart2/source/model/main/ChartModel.cxx create mode 100644 chart2/source/model/main/ChartModel_Persistence.cxx create mode 100644 chart2/source/model/main/DataPoint.cxx create mode 100644 chart2/source/model/main/DataPoint.hxx create mode 100644 chart2/source/model/main/DataPointProperties.cxx create mode 100644 chart2/source/model/main/DataPointProperties.hxx create mode 100644 chart2/source/model/main/DataSeries.cxx create mode 100644 chart2/source/model/main/DataSeriesProperties.cxx create mode 100644 chart2/source/model/main/DataSeriesProperties.hxx create mode 100644 chart2/source/model/main/Diagram.cxx create mode 100644 chart2/source/model/main/FormattedString.cxx create mode 100644 chart2/source/model/main/FormattedString.hxx create mode 100644 chart2/source/model/main/GridProperties.cxx create mode 100644 chart2/source/model/main/GridProperties.hxx create mode 100644 chart2/source/model/main/Legend.cxx create mode 100644 chart2/source/model/main/PageBackground.cxx create mode 100644 chart2/source/model/main/PageBackground.hxx create mode 100644 chart2/source/model/main/PolarCoordinateSystem.cxx create mode 100644 chart2/source/model/main/StockBar.cxx create mode 100644 chart2/source/model/main/Title.cxx create mode 100644 chart2/source/model/main/UndoManager.cxx create mode 100644 chart2/source/model/main/UndoManager.hxx create mode 100644 chart2/source/model/main/Wall.cxx create mode 100644 chart2/source/model/main/Wall.hxx create mode 100644 chart2/source/model/template/AreaChartType.cxx create mode 100644 chart2/source/model/template/AreaChartType.hxx create mode 100644 chart2/source/model/template/AreaChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/AreaChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/BarChartType.cxx create mode 100644 chart2/source/model/template/BarChartType.hxx create mode 100644 chart2/source/model/template/BarChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/BarChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/BubbleChartType.cxx create mode 100644 chart2/source/model/template/BubbleChartType.hxx create mode 100644 chart2/source/model/template/BubbleChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/BubbleChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/BubbleDataInterpreter.cxx create mode 100644 chart2/source/model/template/BubbleDataInterpreter.hxx create mode 100644 chart2/source/model/template/CandleStickChartType.cxx create mode 100644 chart2/source/model/template/CandleStickChartType.hxx create mode 100644 chart2/source/model/template/ChartType.cxx create mode 100644 chart2/source/model/template/ChartTypeManager.cxx create mode 100644 chart2/source/model/template/ChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/ColumnChartType.cxx create mode 100644 chart2/source/model/template/ColumnChartType.hxx create mode 100644 chart2/source/model/template/ColumnLineChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/ColumnLineChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/ColumnLineDataInterpreter.cxx create mode 100644 chart2/source/model/template/ColumnLineDataInterpreter.hxx create mode 100644 chart2/source/model/template/DataInterpreter.cxx create mode 100644 chart2/source/model/template/FilledNetChartType.cxx create mode 100644 chart2/source/model/template/FilledNetChartType.hxx create mode 100644 chart2/source/model/template/LineChartType.cxx create mode 100644 chart2/source/model/template/LineChartType.hxx create mode 100644 chart2/source/model/template/LineChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/LineChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/NetChartType.cxx create mode 100644 chart2/source/model/template/NetChartType.hxx create mode 100644 chart2/source/model/template/NetChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/NetChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/PieChartType.cxx create mode 100644 chart2/source/model/template/PieChartType.hxx create mode 100644 chart2/source/model/template/PieChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/PieChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/ScatterChartType.cxx create mode 100644 chart2/source/model/template/ScatterChartType.hxx create mode 100644 chart2/source/model/template/ScatterChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/ScatterChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/StockChartTypeTemplate.cxx create mode 100644 chart2/source/model/template/StockChartTypeTemplate.hxx create mode 100644 chart2/source/model/template/StockDataInterpreter.cxx create mode 100644 chart2/source/model/template/StockDataInterpreter.hxx create mode 100644 chart2/source/model/template/XYDataInterpreter.cxx create mode 100644 chart2/source/model/template/XYDataInterpreter.hxx create mode 100644 chart2/source/tools/AxisHelper.cxx create mode 100644 chart2/source/tools/BaseGFXHelper.cxx create mode 100644 chart2/source/tools/CachedDataSequence.cxx create mode 100644 chart2/source/tools/CharacterProperties.cxx create mode 100644 chart2/source/tools/ChartModelHelper.cxx create mode 100644 chart2/source/tools/ChartTypeHelper.cxx create mode 100644 chart2/source/tools/ChartViewHelper.cxx create mode 100644 chart2/source/tools/ColorPerPointHelper.cxx create mode 100644 chart2/source/tools/CommonConverters.cxx create mode 100644 chart2/source/tools/ConfigColorScheme.cxx create mode 100644 chart2/source/tools/ControllerLockGuard.cxx create mode 100644 chart2/source/tools/DataSeriesHelper.cxx create mode 100644 chart2/source/tools/DataSource.cxx create mode 100644 chart2/source/tools/DataSourceHelper.cxx create mode 100644 chart2/source/tools/DiagramHelper.cxx create mode 100644 chart2/source/tools/ErrorBar.cxx create mode 100644 chart2/source/tools/ExplicitCategoriesProvider.cxx create mode 100644 chart2/source/tools/ExponentialRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/FillProperties.cxx create mode 100644 chart2/source/tools/FormattedStringHelper.cxx create mode 100644 chart2/source/tools/InternalData.cxx create mode 100644 chart2/source/tools/InternalDataProvider.cxx create mode 100644 chart2/source/tools/LabeledDataSequence.cxx create mode 100644 chart2/source/tools/LegendHelper.cxx create mode 100644 chart2/source/tools/LifeTime.cxx create mode 100644 chart2/source/tools/LinePropertiesHelper.cxx create mode 100644 chart2/source/tools/LinearRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/MeanValueRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/MediaDescriptorHelper.cxx create mode 100644 chart2/source/tools/ModifyListenerCallBack.cxx create mode 100644 chart2/source/tools/ModifyListenerHelper.cxx create mode 100644 chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/NameContainer.cxx create mode 100644 chart2/source/tools/NumberFormatterWrapper.cxx create mode 100644 chart2/source/tools/OPropertySet.cxx create mode 100644 chart2/source/tools/ObjectIdentifier.cxx create mode 100644 chart2/source/tools/PolynomialRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/PopupRequest.cxx create mode 100644 chart2/source/tools/PotentialRegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/PropertyHelper.cxx create mode 100644 chart2/source/tools/RangeHighlighter.cxx create mode 100644 chart2/source/tools/ReferenceSizeProvider.cxx create mode 100644 chart2/source/tools/RegressionCurveCalculator.cxx create mode 100644 chart2/source/tools/RegressionCurveHelper.cxx create mode 100644 chart2/source/tools/RegressionCurveModel.cxx create mode 100644 chart2/source/tools/RegressionEquation.cxx create mode 100644 chart2/source/tools/RegressionEquation.hxx create mode 100644 chart2/source/tools/RelativePositionHelper.cxx create mode 100644 chart2/source/tools/RelativeSizeHelper.cxx create mode 100644 chart2/source/tools/ResId.cxx create mode 100644 chart2/source/tools/Scaling.cxx create mode 100644 chart2/source/tools/SceneProperties.cxx create mode 100644 chart2/source/tools/StatisticsHelper.cxx create mode 100644 chart2/source/tools/ThreeDHelper.cxx create mode 100644 chart2/source/tools/TitleHelper.cxx create mode 100644 chart2/source/tools/UncachedDataSequence.cxx create mode 100644 chart2/source/tools/UserDefinedProperties.cxx create mode 100644 chart2/source/tools/WeakListenerAdapter.cxx create mode 100644 chart2/source/tools/WrappedDefaultProperty.cxx create mode 100644 chart2/source/tools/WrappedDirectStateProperty.cxx create mode 100644 chart2/source/tools/WrappedIgnoreProperty.cxx create mode 100644 chart2/source/tools/WrappedProperty.cxx create mode 100644 chart2/source/tools/WrappedPropertySet.cxx create mode 100644 chart2/source/tools/XMLRangeHelper.cxx create mode 100644 chart2/source/view/axes/DateHelper.cxx create mode 100644 chart2/source/view/axes/DateScaling.cxx create mode 100644 chart2/source/view/axes/DateScaling.hxx create mode 100644 chart2/source/view/axes/MinimumAndMaximumSupplier.cxx create mode 100644 chart2/source/view/axes/ScaleAutomatism.cxx create mode 100644 chart2/source/view/axes/TickmarkProperties.hxx create mode 100644 chart2/source/view/axes/Tickmarks.cxx create mode 100644 chart2/source/view/axes/Tickmarks.hxx create mode 100644 chart2/source/view/axes/Tickmarks_Dates.cxx create mode 100644 chart2/source/view/axes/Tickmarks_Dates.hxx create mode 100644 chart2/source/view/axes/Tickmarks_Equidistant.cxx create mode 100644 chart2/source/view/axes/Tickmarks_Equidistant.hxx create mode 100644 chart2/source/view/axes/VAxisBase.cxx create mode 100644 chart2/source/view/axes/VAxisBase.hxx create mode 100644 chart2/source/view/axes/VAxisOrGridBase.cxx create mode 100644 chart2/source/view/axes/VAxisOrGridBase.hxx create mode 100644 chart2/source/view/axes/VAxisProperties.cxx create mode 100644 chart2/source/view/axes/VAxisProperties.hxx create mode 100644 chart2/source/view/axes/VCartesianAxis.cxx create mode 100644 chart2/source/view/axes/VCartesianAxis.hxx create mode 100644 chart2/source/view/axes/VCartesianCoordinateSystem.cxx create mode 100644 chart2/source/view/axes/VCartesianCoordinateSystem.hxx create mode 100644 chart2/source/view/axes/VCartesianGrid.cxx create mode 100644 chart2/source/view/axes/VCartesianGrid.hxx create mode 100644 chart2/source/view/axes/VCoordinateSystem.cxx create mode 100644 chart2/source/view/axes/VPolarAngleAxis.cxx create mode 100644 chart2/source/view/axes/VPolarAngleAxis.hxx create mode 100644 chart2/source/view/axes/VPolarAxis.cxx create mode 100644 chart2/source/view/axes/VPolarAxis.hxx create mode 100644 chart2/source/view/axes/VPolarCoordinateSystem.cxx create mode 100644 chart2/source/view/axes/VPolarCoordinateSystem.hxx create mode 100644 chart2/source/view/axes/VPolarGrid.cxx create mode 100644 chart2/source/view/axes/VPolarGrid.hxx create mode 100644 chart2/source/view/axes/VPolarRadiusAxis.cxx create mode 100644 chart2/source/view/axes/VPolarRadiusAxis.hxx create mode 100644 chart2/source/view/charttypes/AreaChart.cxx create mode 100644 chart2/source/view/charttypes/AreaChart.hxx create mode 100644 chart2/source/view/charttypes/BarChart.cxx create mode 100644 chart2/source/view/charttypes/BarChart.hxx create mode 100644 chart2/source/view/charttypes/BarPositionHelper.cxx create mode 100644 chart2/source/view/charttypes/BarPositionHelper.hxx create mode 100644 chart2/source/view/charttypes/BubbleChart.cxx create mode 100644 chart2/source/view/charttypes/BubbleChart.hxx create mode 100644 chart2/source/view/charttypes/CandleStickChart.cxx create mode 100644 chart2/source/view/charttypes/CandleStickChart.hxx create mode 100644 chart2/source/view/charttypes/CategoryPositionHelper.cxx create mode 100644 chart2/source/view/charttypes/CategoryPositionHelper.hxx create mode 100644 chart2/source/view/charttypes/ConfigAccess.cxx create mode 100644 chart2/source/view/charttypes/NetChart.cxx create mode 100644 chart2/source/view/charttypes/NetChart.hxx create mode 100644 chart2/source/view/charttypes/PieChart.cxx create mode 100644 chart2/source/view/charttypes/PieChart.hxx create mode 100644 chart2/source/view/charttypes/Splines.cxx create mode 100644 chart2/source/view/charttypes/Splines.hxx create mode 100644 chart2/source/view/charttypes/VSeriesPlotter.cxx create mode 100644 chart2/source/view/diagram/VDiagram.cxx create mode 100644 chart2/source/view/inc/Clipping.hxx create mode 100644 chart2/source/view/inc/ConfigAccess.hxx create mode 100644 chart2/source/view/inc/DateHelper.hxx create mode 100644 chart2/source/view/inc/LabelAlignment.hxx create mode 100644 chart2/source/view/inc/LabelPositionHelper.hxx create mode 100644 chart2/source/view/inc/LegendEntryProvider.hxx create mode 100644 chart2/source/view/inc/Linear3DTransformation.hxx create mode 100644 chart2/source/view/inc/MinimumAndMaximumSupplier.hxx create mode 100644 chart2/source/view/inc/PlotterBase.hxx create mode 100644 chart2/source/view/inc/PlottingPositionHelper.hxx create mode 100644 chart2/source/view/inc/PolarLabelPositionHelper.hxx create mode 100644 chart2/source/view/inc/PropertyMapper.hxx create mode 100644 chart2/source/view/inc/ScaleAutomatism.hxx create mode 100644 chart2/source/view/inc/ShapeFactory.hxx create mode 100644 chart2/source/view/inc/Stripe.hxx create mode 100644 chart2/source/view/inc/VCoordinateSystem.hxx create mode 100644 chart2/source/view/inc/VDataSeries.hxx create mode 100644 chart2/source/view/inc/VDiagram.hxx create mode 100644 chart2/source/view/inc/VLegendSymbolFactory.hxx create mode 100644 chart2/source/view/inc/VLineProperties.hxx create mode 100644 chart2/source/view/inc/VPolarTransformation.hxx create mode 100644 chart2/source/view/inc/VSeriesPlotter.hxx create mode 100644 chart2/source/view/inc/ViewDefines.hxx create mode 100644 chart2/source/view/main/AxisUsage.hxx create mode 100644 chart2/source/view/main/ChartItemPool.cxx create mode 100644 chart2/source/view/main/ChartItemPool.hxx create mode 100644 chart2/source/view/main/ChartView.cxx create mode 100644 chart2/source/view/main/Clipping.cxx create mode 100644 chart2/source/view/main/DataPointSymbolSupplier.cxx create mode 100644 chart2/source/view/main/DrawModelWrapper.cxx create mode 100644 chart2/source/view/main/ExplicitValueProvider.cxx create mode 100644 chart2/source/view/main/LabelPositionHelper.cxx create mode 100644 chart2/source/view/main/Linear3DTransformation.cxx create mode 100644 chart2/source/view/main/PlotterBase.cxx create mode 100644 chart2/source/view/main/PlottingPositionHelper.cxx create mode 100644 chart2/source/view/main/PolarLabelPositionHelper.cxx create mode 100644 chart2/source/view/main/PropertyMapper.cxx create mode 100644 chart2/source/view/main/SeriesPlotterContainer.cxx create mode 100644 chart2/source/view/main/SeriesPlotterContainer.hxx create mode 100644 chart2/source/view/main/ShapeFactory.cxx create mode 100644 chart2/source/view/main/Stripe.cxx create mode 100644 chart2/source/view/main/VButton.cxx create mode 100644 chart2/source/view/main/VButton.hxx create mode 100644 chart2/source/view/main/VDataSeries.cxx create mode 100644 chart2/source/view/main/VLegend.cxx create mode 100644 chart2/source/view/main/VLegend.hxx create mode 100644 chart2/source/view/main/VLegendSymbolFactory.cxx create mode 100644 chart2/source/view/main/VLineProperties.cxx create mode 100644 chart2/source/view/main/VPolarTransformation.cxx create mode 100644 chart2/source/view/main/VTitle.cxx create mode 100644 chart2/source/view/main/VTitle.hxx (limited to 'chart2/source') diff --git a/chart2/source/chartcore.component b/chart2/source/chartcore.component new file mode 100644 index 000000000..f58ba98ba --- /dev/null +++ b/chart2/source/chartcore.component @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chart2/source/controller/accessibility/AccessibleBase.cxx b/chart2/source/controller/accessibility/AccessibleBase.cxx new file mode 100644 index 000000000..4e8b20574 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleBase.cxx @@ -0,0 +1,854 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "AccessibleChartShape.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ChartElementFactory.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Reference; +using ::osl::MutexGuard; +using ::osl::ClearableMutexGuard; +using ::com::sun::star::uno::Any; + +namespace chart +{ + +/** @param bMayHaveChildren is false per default + */ +AccessibleBase::AccessibleBase( + const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren, + bool bAlwaysTransparent /* default: false */ ) : + impl::AccessibleBase_Base( m_aMutex ), + m_bIsDisposed( false ), + m_bMayHaveChildren( bMayHaveChildren ), + m_bChildrenInitialized( false ), + m_nEventNotifierId(0), + m_xStateSetHelper( new ::utl::AccessibleStateSetHelper() ), + m_aAccInfo( rAccInfo ), + m_bAlwaysTransparent( bAlwaysTransparent ), + m_bStateSetInitialized( false ) +{ + // initialize some states + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->AddState( AccessibleStateType::ENABLED ); + m_xStateSetHelper->AddState( AccessibleStateType::SHOWING ); + m_xStateSetHelper->AddState( AccessibleStateType::VISIBLE ); + m_xStateSetHelper->AddState( AccessibleStateType::SELECTABLE ); + m_xStateSetHelper->AddState( AccessibleStateType::FOCUSABLE ); +} + +AccessibleBase::~AccessibleBase() +{ + OSL_ASSERT( m_bIsDisposed ); +} + +bool AccessibleBase::CheckDisposeState( bool bThrowException /* default: true */ ) const +{ + if( bThrowException && + m_bIsDisposed ) + { + throw lang::DisposedException("component has state DEFUNC", + static_cast< uno::XWeak * >( const_cast< AccessibleBase * >( this ))); + } + return m_bIsDisposed; +} + +bool AccessibleBase::NotifyEvent( EventType eEventType, const AccessibleUniqueId & rId ) +{ + if( GetId() == rId ) + { + // event is addressed to this object + + css::uno::Any aEmpty; + css::uno::Any aSelected; + aSelected <<= AccessibleStateType::SELECTED; + switch( eEventType ) + { + case EventType::GOT_SELECTION: + { + AddState( AccessibleStateType::SELECTED ); + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty ); + + AddState( AccessibleStateType::FOCUSED ); + aSelected <<= AccessibleStateType::FOCUSED; + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aSelected, aEmpty ); + + SAL_INFO("chart2.accessibility", "Selection acquired by: " << getAccessibleName()); + } + break; + + case EventType::LOST_SELECTION: + { + RemoveState( AccessibleStateType::SELECTED ); + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected ); + + AddState( AccessibleStateType::FOCUSED ); + aSelected <<= AccessibleStateType::FOCUSED; + BroadcastAccEvent( AccessibleEventId::STATE_CHANGED, aEmpty, aSelected ); + SAL_INFO("chart2.accessibility", "Selection lost by: " << getAccessibleName()); + } + break; + } + return true; + } + else if( m_bMayHaveChildren ) + { + bool bStop = false; + + ClearableMutexGuard aGuard( m_aMutex ); + // make local copy for notification + ChildListVectorType aLocalChildList( m_aChildList ); + aGuard.clear(); + + for (auto const& localChild : aLocalChildList) + { + // Note: at this place we must be sure to have an AccessibleBase + // object in the UNO reference to XAccessible ! + bStop = (*static_cast< AccessibleBase * > + ( localChild.get() )).NotifyEvent( eEventType, rId ); + if (bStop) + break; + } + return bStop; + } + + return false; +} + +void AccessibleBase::AddState( sal_Int16 aState ) +{ + CheckDisposeState(); + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->AddState( aState ); +} + +void AccessibleBase::RemoveState( sal_Int16 aState ) +{ + CheckDisposeState(); + OSL_ASSERT( m_xStateSetHelper.is() ); + m_xStateSetHelper->RemoveState( aState ); +} + +bool AccessibleBase::UpdateChildren() +{ + bool bMustUpdateChildren = false; + { + MutexGuard aGuard( m_aMutex ); + if( ! m_bMayHaveChildren || + m_bIsDisposed ) + return false; + + bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + } + + // update unguarded + if( bMustUpdateChildren ) + m_bChildrenInitialized = ImplUpdateChildren(); + + return m_bChildrenInitialized; +} + +bool AccessibleBase::ImplUpdateChildren() +{ + bool bResult = false; + + if( m_aAccInfo.m_spObjectHierarchy ) + { + ObjectHierarchy::tChildContainer aModelChildren( + m_aAccInfo.m_spObjectHierarchy->getChildren( GetId() )); + std::vector< ChildOIDMap::key_type > aAccChildren; + aAccChildren.reserve( aModelChildren.size()); + std::transform( m_aChildOIDMap.begin(), m_aChildOIDMap.end(), + std::back_inserter( aAccChildren ), + ::o3tl::select1st< ChildOIDMap::value_type >() ); + + std::sort( aModelChildren.begin(), aModelChildren.end()); + + std::vector< ObjectIdentifier > aChildrenToRemove, aChildrenToAdd; + std::set_difference( aModelChildren.begin(), aModelChildren.end(), + aAccChildren.begin(), aAccChildren.end(), + std::back_inserter( aChildrenToAdd )); + std::set_difference( aAccChildren.begin(), aAccChildren.end(), + aModelChildren.begin(), aModelChildren.end(), + std::back_inserter( aChildrenToRemove )); + + for (auto const& childToRemove : aChildrenToRemove) + { + RemoveChildByOId(childToRemove); + } + + AccessibleElementInfo aAccInfo( GetInfo()); + aAccInfo.m_pParent = this; + + for (auto const& childToAdd : aChildrenToAdd) + { + aAccInfo.m_aOID = childToAdd; + if ( childToAdd.isAutoGeneratedObject() ) + { + AddChild( ChartElementFactory::CreateChartElement( aAccInfo ).get() ); + } + else if ( childToAdd.isAdditionalShape() ) + { + AddChild( new AccessibleChartShape( aAccInfo ) ); + } + } + bResult = true; + } + + return bResult; +} + +void AccessibleBase::AddChild( AccessibleBase * pChild ) +{ + OSL_ENSURE( pChild != nullptr, "Invalid Child" ); + if( !pChild ) + return; + + ClearableMutexGuard aGuard( m_aMutex ); + + Reference< XAccessible > xChild( pChild ); + m_aChildList.push_back( xChild ); + + m_aChildOIDMap[ pChild->GetId() ] = xChild; + + // inform listeners of new child + if( m_bChildrenInitialized ) + { + Any aEmpty, aNew; + aNew <<= xChild; + + aGuard.clear(); + BroadcastAccEvent( AccessibleEventId::CHILD, aNew, aEmpty ); + } +} + +/** in this method we imply that the Reference< XAccessible > elements in the + vector are AccessibleBase objects ! + */ +void AccessibleBase::RemoveChildByOId( const ObjectIdentifier& rOId ) +{ + ClearableMutexGuard aGuard( m_aMutex ); + + ChildOIDMap::iterator aIt( m_aChildOIDMap.find( rOId )); + if( aIt == m_aChildOIDMap.end()) + return; + + Reference< XAccessible > xChild( aIt->second ); + + // remove from map + m_aChildOIDMap.erase( aIt ); + + // search child in vector + ChildListVectorType::iterator aVecIter = + std::find( m_aChildList.begin(), m_aChildList.end(), xChild ); + + OSL_ENSURE( aVecIter != m_aChildList.end(), + "Inconsistent ChildMap" ); + + // remove child from vector + m_aChildList.erase( aVecIter ); + bool bInitialized = m_bChildrenInitialized; + + // call listeners unguarded + aGuard.clear(); + + // inform listeners of removed child + if( bInitialized ) + { + Any aEmpty, aOld; + aOld <<= xChild; + + BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld ); + } + + // dispose the child + Reference< lang::XComponent > xComp( xChild, UNO_QUERY ); + if( xComp.is()) + xComp->dispose(); +} + +awt::Point AccessibleBase::GetUpperLeftOnScreen() const +{ + awt::Point aResult; + if( m_aAccInfo.m_pParent ) + { + ClearableMutexGuard aGuard( m_aMutex ); + AccessibleBase * pParent = m_aAccInfo.m_pParent; + aGuard.clear(); + + if( pParent ) + { + aResult = pParent->GetUpperLeftOnScreen(); + } + else + OSL_FAIL( "Default position used is probably incorrect." ); + } + + return aResult; +} + +void AccessibleBase::BroadcastAccEvent( + sal_Int16 nId, + const Any & rNew, + const Any & rOld ) const +{ + ClearableMutexGuard aGuard( m_aMutex ); + + if ( !m_nEventNotifierId ) + return; + // if we don't have a client id for the notifier, then we don't have listeners, then + // we don't need to notify anything + + // the const cast is needed, because UNO parameters are never const + const AccessibleEventObject aEvent( + const_cast< uno::XWeak * >( static_cast< const uno::XWeak * >( this )), + nId, rNew, rOld ); + + // let the notifier handle this event + ::comphelper::AccessibleEventNotifier::addEvent( m_nEventNotifierId, aEvent ); + + aGuard.clear(); +} + +void AccessibleBase::KillAllChildren() +{ + ClearableMutexGuard aGuard( m_aMutex ); + + // make local copy for notification, and remove all children + ChildListVectorType aLocalChildList; + aLocalChildList.swap( m_aChildList ); + m_aChildOIDMap.clear(); + + aGuard.clear(); + + // call dispose for all children + // and notify listeners + Reference< lang::XComponent > xComp; + Any aEmpty, aOld; + for (auto const& localChild : aLocalChildList) + { + aOld <<= localChild; + BroadcastAccEvent( AccessibleEventId::CHILD, aEmpty, aOld ); + + xComp.set(localChild, UNO_QUERY); + if( xComp.is()) + xComp->dispose(); + } + m_bChildrenInitialized = false; +} + +void AccessibleBase::SetInfo( const AccessibleElementInfo & rNewInfo ) +{ + m_aAccInfo = rNewInfo; + if( m_bMayHaveChildren ) + { + KillAllChildren(); + } + BroadcastAccEvent( AccessibleEventId::INVALIDATE_ALL_CHILDREN, uno::Any(), uno::Any()); +} + +// ________ (XComponent::dispose) ________ +void SAL_CALL AccessibleBase::disposing() +{ + { + MutexGuard aGuard(m_aMutex); + OSL_ENSURE(!m_bIsDisposed, "dispose() called twice"); + + // notify disposing to all AccessibleEvent listeners asynchronous + if (m_nEventNotifierId) + { + ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(m_nEventNotifierId, + *this); + m_nEventNotifierId = 0; + } + + // reset pointers + m_aAccInfo.m_pParent = nullptr; + + // attach new empty state set helper to member reference + rtl::Reference<::utl::AccessibleStateSetHelper> pHelper = new ::utl::AccessibleStateSetHelper(); + pHelper->AddState(AccessibleStateType::DEFUNC); + // release old helper and attach new one + m_xStateSetHelper = pHelper; + + m_bIsDisposed = true; + + } + // call listeners unguarded + + if( m_bMayHaveChildren ) + { + KillAllChildren(); + } + else + OSL_ENSURE( m_aChildList.empty(), "Child list should be empty" ); +} + +// ________ XAccessible ________ +Reference< XAccessibleContext > SAL_CALL AccessibleBase::getAccessibleContext() +{ + return this; +} + +// ________ AccessibleBase::XAccessibleContext ________ +sal_Int32 SAL_CALL AccessibleBase::getAccessibleChildCount() +{ + ClearableMutexGuard aGuard( m_aMutex ); + if( ! m_bMayHaveChildren || + m_bIsDisposed ) + return 0; + + bool bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + + aGuard.clear(); + + // update unguarded + if( bMustUpdateChildren ) + UpdateChildren(); + + return ImplGetAccessibleChildCount(); +} + +sal_Int32 AccessibleBase::ImplGetAccessibleChildCount() const +{ + return m_aChildList.size(); +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleChild( sal_Int32 i ) +{ + CheckDisposeState(); + Reference< XAccessible > xResult; + + ClearableMutexGuard aGuard( m_aMutex ); + bool bMustUpdateChildren = ( m_bMayHaveChildren && + ! m_bChildrenInitialized ); + + aGuard.clear(); + + if( bMustUpdateChildren ) + UpdateChildren(); + + xResult.set( ImplGetAccessibleChildById( i )); + + return xResult; +} + +Reference< XAccessible > AccessibleBase::ImplGetAccessibleChildById( sal_Int32 i ) const +{ + Reference< XAccessible > xResult; + + MutexGuard aGuard( m_aMutex); + if( ! m_bMayHaveChildren || + i < 0 || + o3tl::make_unsigned( i ) >= m_aChildList.size() ) + { + OUString aBuf = "Index " + OUString::number( i ) + " is invalid for range [ 0, " + + OUString::number( m_aChildList.size() - 1 ) + + " ]"; + lang::IndexOutOfBoundsException aEx( aBuf, + const_cast< ::cppu::OWeakObject * >( + static_cast< const ::cppu::OWeakObject * >( this ))); + throw aEx; + } + else + xResult.set( m_aChildList[ i ] ); + + return xResult; +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleParent() +{ + CheckDisposeState(); + Reference< XAccessible > aResult; + if( m_aAccInfo.m_pParent ) + aResult.set( m_aAccInfo.m_pParent ); + + return aResult; +} + +sal_Int32 SAL_CALL AccessibleBase::getAccessibleIndexInParent() +{ + CheckDisposeState(); + + if( m_aAccInfo.m_spObjectHierarchy ) + return m_aAccInfo.m_spObjectHierarchy->getIndexInParent( GetId() ); + return -1; +} + +sal_Int16 SAL_CALL AccessibleBase::getAccessibleRole() +{ + return AccessibleRole::SHAPE; +} + +Reference< XAccessibleRelationSet > SAL_CALL AccessibleBase::getAccessibleRelationSet() +{ + Reference< XAccessibleRelationSet > aResult; + return aResult; +} + +Reference< XAccessibleStateSet > SAL_CALL AccessibleBase::getAccessibleStateSet() +{ + if( ! m_bStateSetInitialized ) + { + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + if ( xSelSupp.is() ) + { + ObjectIdentifier aOID( xSelSupp->getSelection() ); + if ( aOID.isValid() && GetId() == aOID ) + { + AddState( AccessibleStateType::SELECTED ); + AddState( AccessibleStateType::FOCUSED ); + } + } + m_bStateSetInitialized = true; + } + + return m_xStateSetHelper; +} + +lang::Locale SAL_CALL AccessibleBase::getLocale() +{ + CheckDisposeState(); + + return Application::GetSettings().GetLanguageTag().getLocale(); +} + +// ________ AccessibleBase::XAccessibleComponent ________ +sal_Bool SAL_CALL AccessibleBase::containsPoint( const awt::Point& aPoint ) +{ + awt::Rectangle aRect( getBounds() ); + + // contains() works with relative coordinates + aRect.X = 0; + aRect.Y = 0; + + return ( aPoint.X >= aRect.X && + aPoint.Y >= aRect.Y && + aPoint.X < (aRect.X + aRect.Width) && + aPoint.Y < (aRect.Y + aRect.Height) ); +} + +Reference< XAccessible > SAL_CALL AccessibleBase::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + CheckDisposeState(); + Reference< XAccessible > aResult; + awt::Rectangle aRect( getBounds()); + + // children are positioned relative to this object, so translate bound rect + aRect.X = 0; + aRect.Y = 0; + + // children must be inside the own bound rect + if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) && + ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height))) + { + ClearableMutexGuard aGuard( m_aMutex ); + ChildListVectorType aLocalChildList( m_aChildList ); + aGuard.clear(); + + Reference< XAccessibleComponent > aComp; + for (auto const& localChild : aLocalChildList) + { + aComp.set(localChild, UNO_QUERY); + if( aComp.is()) + { + aRect = aComp->getBounds(); + if( ( aRect.X <= aPoint.X && aPoint.X <= (aRect.X + aRect.Width) ) && + ( aRect.Y <= aPoint.Y && aPoint.Y <= (aRect.Y + aRect.Height))) + { + aResult = localChild; + break; + } + } + } + } + + return aResult; +} + +awt::Rectangle SAL_CALL AccessibleBase::getBounds() +{ + ExplicitValueProvider *pExplicitValueProvider( + comphelper::getFromUnoTunnel( m_aAccInfo.m_xView )); + if( pExplicitValueProvider ) + { + VclPtr pWindow( VCLUnoHelper::GetWindow( m_aAccInfo.m_xWindow )); + awt::Rectangle aLogicRect( pExplicitValueProvider->getRectangleOfObject( m_aAccInfo.m_aOID.getObjectCID() )); + if( pWindow ) + { + tools::Rectangle aRect( aLogicRect.X, aLogicRect.Y, + aLogicRect.X + aLogicRect.Width, + aLogicRect.Y + aLogicRect.Height ); + SolarMutexGuard aSolarGuard; + aRect = pWindow->LogicToPixel( aRect ); + + // aLogicRect is relative to the page, but we need a value relative + // to the parent object + awt::Point aParentLocOnScreen; + uno::Reference< XAccessibleComponent > xParent( getAccessibleParent(), uno::UNO_QUERY ); + if( xParent.is() ) + aParentLocOnScreen = xParent->getLocationOnScreen(); + + awt::Point aULOnScreen = GetUpperLeftOnScreen(); + awt::Point aOffset( aParentLocOnScreen.X - aULOnScreen.X, + aParentLocOnScreen.Y - aULOnScreen.Y ); + + return awt::Rectangle( aRect.Left() - aOffset.X, aRect.Top() - aOffset.Y, + aRect.getWidth(), aRect.getHeight()); + } + } + + return awt::Rectangle(); +} + +awt::Point SAL_CALL AccessibleBase::getLocation() +{ + CheckDisposeState(); + awt::Rectangle aBBox( getBounds() ); + return awt::Point( aBBox.X, aBBox.Y ); +} + +awt::Point SAL_CALL AccessibleBase::getLocationOnScreen() +{ + CheckDisposeState(); + + if (AccessibleBase* pParent = m_aAccInfo.m_pParent) + { + awt::Point aLocThisRel( getLocation()); + awt::Point aUpperLeft(pParent->getLocationOnScreen()); + + return awt::Point( aUpperLeft.X + aLocThisRel.X, + aUpperLeft.Y + aLocThisRel.Y ); + } + else + return getLocation(); +} + +awt::Size SAL_CALL AccessibleBase::getSize() +{ + CheckDisposeState(); + awt::Rectangle aBBox( getBounds() ); + return awt::Size( aBBox.Width, aBBox.Height ); +} + +void SAL_CALL AccessibleBase::grabFocus() +{ + CheckDisposeState(); + + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + if ( xSelSupp.is() ) + { + xSelSupp->select( GetId().getAny() ); + } +} + +sal_Int32 SAL_CALL AccessibleBase::getForeground() +{ + return sal_Int32(getColor( ACC_BASE_FOREGROUND )); +} + +sal_Int32 SAL_CALL AccessibleBase::getBackground() +{ + return sal_Int32(getColor( ACC_BASE_BACKGROUND )); +} + +Color AccessibleBase::getColor( eColorType eColType ) +{ + Color nResult = COL_TRANSPARENT; + if( m_bAlwaysTransparent ) + return nResult; + + ObjectIdentifier aOID( m_aAccInfo.m_aOID ); + ObjectType eType( aOID.getObjectType() ); + Reference< beans::XPropertySet > xObjProp; + OUString aObjectCID = aOID.getObjectCID(); + if( eType == OBJECTTYPE_LEGEND_ENTRY ) + { + // for colors get the data series/point properties + std::u16string_view aParentParticle( ObjectIdentifier::getFullParentParticle( aObjectCID )); + aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle ); + } + + xObjProp = + ObjectIdentifier::getObjectPropertySet( + aObjectCID, m_aAccInfo.m_xChartDocument ); + if( xObjProp.is()) + { + try + { + OUString aPropName; + OUString aStylePropName; + + switch( eType ) + { + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + if( eColType == ACC_BASE_FOREGROUND ) + { + aPropName = "BorderColor"; + aStylePropName = "BorderTransparency"; + } + else + { + aPropName = "Color"; + aStylePropName = "Transparency"; + } + break; + default: + if( eColType == ACC_BASE_FOREGROUND ) + { + aPropName = "LineColor"; + aStylePropName = "LineTransparence"; + } + else + { + aPropName = "FillColor"; + aStylePropName = "FillTransparence"; + } + break; + } + + bool bTransparent = m_bAlwaysTransparent; + Reference< beans::XPropertySetInfo > xInfo = xObjProp->getPropertySetInfo(); + if( xInfo.is() && + xInfo->hasPropertyByName( aStylePropName )) + { + if( eColType == ACC_BASE_FOREGROUND ) + { + drawing::LineStyle aLStyle; + if( xObjProp->getPropertyValue( aStylePropName ) >>= aLStyle ) + bTransparent = (aLStyle == drawing::LineStyle_NONE); + } + else + { + drawing::FillStyle aFStyle; + if( xObjProp->getPropertyValue( aStylePropName ) >>= aFStyle ) + bTransparent = (aFStyle == drawing::FillStyle_NONE); + } + } + + if( !bTransparent && + xInfo.is() && + xInfo->hasPropertyByName( aPropName )) + { + xObjProp->getPropertyValue( aPropName ) >>= nResult; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nResult; +} + +// ________ AccessibleBase::XServiceInfo ________ +OUString SAL_CALL AccessibleBase::getImplementationName() +{ + return "AccessibleBase"; +} + +sal_Bool SAL_CALL AccessibleBase::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +uno::Sequence< OUString > SAL_CALL AccessibleBase::getSupportedServiceNames() +{ + return { + "com.sun.star.accessibility.Accessible", + "com.sun.star.accessibility.AccessibleContext" + }; +} + +// ________ AccessibleBase::XEventListener ________ +void SAL_CALL AccessibleBase::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +// ________ XAccessibleEventBroadcasters ________ +void SAL_CALL AccessibleBase::addAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( xListener.is() ) + { + if ( !m_nEventNotifierId ) + m_nEventNotifierId = ::comphelper::AccessibleEventNotifier::registerClient(); + + ::comphelper::AccessibleEventNotifier::addEventListener( m_nEventNotifierId, xListener ); + } +} + +void SAL_CALL AccessibleBase::removeAccessibleEventListener( const Reference< XAccessibleEventListener >& xListener ) +{ + MutexGuard aGuard( m_aMutex ); + + if ( xListener.is() && m_nEventNotifierId) + { + sal_Int32 nListenerCount = ::comphelper::AccessibleEventNotifier::removeEventListener( m_nEventNotifierId, xListener ); + if ( !nListenerCount ) + { + // no listeners anymore + ::comphelper::AccessibleEventNotifier::revokeClient( m_nEventNotifierId ); + m_nEventNotifierId = 0; + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartElement.cxx b/chart2/source/controller/accessibility/AccessibleChartElement.cxx new file mode 100644 index 000000000..d89a5d027 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartElement.cxx @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AccessibleChartElement.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +AccessibleChartElement::AccessibleChartElement( + const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren ) : + impl::AccessibleChartElement_Base( rAccInfo, bMayHaveChildren, false/*bAlwaysTransparent*/ ), + m_bHasText( false ) +{ + AddState( AccessibleStateType::TRANSIENT ); +} + +AccessibleChartElement::~AccessibleChartElement() +{ + OSL_ASSERT( CheckDisposeState( false /* don't throw exceptions */ ) ); +} + +// ________ protected ________ + +bool AccessibleChartElement::ImplUpdateChildren() +{ + bool bResult = false; + Reference< chart2::XTitle > xTitle( + ObjectIdentifier::getObjectPropertySet( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ), + uno::UNO_QUERY ); + m_bHasText = xTitle.is(); + + if( m_bHasText ) + { + InitTextEdit(); + bResult = true; + } + else + bResult = AccessibleBase::ImplUpdateChildren(); + + return bResult; +} + +void AccessibleChartElement::InitTextEdit() +{ + if( ! m_xTextHelper.is()) + { + // get hard reference + Reference< view::XSelectionSupplier > xSelSupp( GetInfo().m_xSelectionSupplier ); + // get factory from selection supplier (controller) + Reference< lang::XMultiServiceFactory > xFact( xSelSupp, uno::UNO_QUERY ); + if( xFact.is()) + { + m_xTextHelper.set( + xFact->createInstance( CHART_ACCESSIBLE_TEXT_SERVICE_NAME ), uno::UNO_QUERY ); + } + } + + if( !m_xTextHelper.is()) + return; + + try + { + Reference< lang::XInitialization > xInit( m_xTextHelper, uno::UNO_QUERY_THROW ); + Sequence< uno::Any > aArgs{ uno::Any(GetInfo().m_aOID.getObjectCID()), + uno::Any(Reference< XAccessible >( this )), + uno::Any(Reference< awt::XWindow >( GetInfo().m_xWindow )) }; + xInit->initialize( aArgs ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// Interfaces + +// ________ AccessibleBase::XAccessibleContext ________ +Reference< XAccessible > AccessibleChartElement::ImplGetAccessibleChildById( sal_Int32 i ) const +{ + Reference< XAccessible > xResult; + + if( m_bHasText ) + xResult.set( m_xTextHelper->getAccessibleChild( i )); + else + xResult.set( AccessibleBase::ImplGetAccessibleChildById( i )); + + return xResult; +} + +sal_Int32 AccessibleChartElement::ImplGetAccessibleChildCount() const +{ + if( m_bHasText ) + { + if( m_xTextHelper.is()) + return m_xTextHelper->getAccessibleChildCount(); + return 0; + } + + return AccessibleBase::ImplGetAccessibleChildCount(); +} + +// ________ XServiceInfo ________ +OUString SAL_CALL AccessibleChartElement::getImplementationName() +{ + return "AccessibleChartElement"; +} + +// ________ AccessibleChartElement::XAccessibleContext (override) ________ +OUString SAL_CALL AccessibleChartElement::getAccessibleName() +{ + return ObjectNameProvider::getNameForCID( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ); +} + +// ________ AccessibleChartElement::XAccessibleContext (override) ________ +OUString SAL_CALL AccessibleChartElement::getAccessibleDescription() +{ + return getToolTipText(); +} + +// ________ AccessibleChartElement::XAccessibleExtendedComponent ________ +Reference< awt::XFont > SAL_CALL AccessibleChartElement::getFont() +{ + CheckDisposeState(); + + Reference< awt::XFont > xFont; + Reference< awt::XDevice > xDevice( Reference< awt::XWindow >( GetInfo().m_xWindow ), uno::UNO_QUERY ); + + if( xDevice.is()) + { + Reference< beans::XMultiPropertySet > xObjProp( + ObjectIdentifier::getObjectPropertySet( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ), uno::UNO_QUERY ); + awt::FontDescriptor aDescr( + CharacterProperties::createFontDescriptorFromPropertySet( xObjProp )); + xFont = xDevice->getFont( aDescr ); + } + + return xFont; +} + +OUString SAL_CALL AccessibleChartElement::getTitledBorderText() +{ + return OUString(); +} + +OUString SAL_CALL AccessibleChartElement::getToolTipText() +{ + CheckDisposeState(); + + return ObjectNameProvider::getHelpText( + GetInfo().m_aOID.getObjectCID(), GetInfo().m_xChartDocument ); +} + +// ________ XAccessibleComponent ________ +sal_Bool SAL_CALL AccessibleChartElement::containsPoint( const awt::Point& aPoint ) +{ + return AccessibleBase::containsPoint( aPoint ); +} + +Reference< XAccessible > SAL_CALL AccessibleChartElement::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + return AccessibleBase::getAccessibleAtPoint( aPoint ); +} + +awt::Rectangle SAL_CALL AccessibleChartElement::getBounds() +{ + return AccessibleBase::getBounds(); +} + +awt::Point SAL_CALL AccessibleChartElement::getLocation() +{ + return AccessibleBase::getLocation(); +} + +awt::Point SAL_CALL AccessibleChartElement::getLocationOnScreen() +{ + return AccessibleBase::getLocationOnScreen(); +} + +awt::Size SAL_CALL AccessibleChartElement::getSize() +{ + return AccessibleBase::getSize(); +} + +void SAL_CALL AccessibleChartElement::grabFocus() +{ + return AccessibleBase::grabFocus(); +} + +sal_Int32 SAL_CALL AccessibleChartElement::getForeground() +{ + return AccessibleBase::getForeground(); +} + +sal_Int32 SAL_CALL AccessibleChartElement::getBackground() +{ + return AccessibleBase::getBackground(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartElement.hxx b/chart2/source/controller/accessibility/AccessibleChartElement.hxx new file mode 100644 index 000000000..12982db8f --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartElement.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::accessibility { class XAccessibleContext; } +namespace com::sun::star::awt { class XFont; } + +namespace chart +{ + +/** Base class for all Chart Accessibility objects except the root node (see AccessibleChartView) + + This class contains a reference to the ChartModel, thus, components can easily access all core functionality. + + Usage Instructions: + +
    +
  • define the getAccessibleName() method of XAccessibleContext
  • +
  • set the ChartModel using SetChartModel() for the first node before + creating any children
  • +
  • override UpdateChildren()
  • +
+ */ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + AccessibleBase, + css::accessibility::XAccessibleExtendedComponent + > AccessibleChartElement_Base; +} + +class AccessibleChartElement : + public impl::AccessibleChartElement_Base +{ +public: + AccessibleChartElement( const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren ); + virtual ~AccessibleChartElement() override; + + // ________ AccessibleBase ________ + virtual bool ImplUpdateChildren() override; + virtual css::uno::Reference< css::accessibility::XAccessible > + ImplGetAccessibleChildById( sal_Int32 i ) const override; + virtual sal_Int32 ImplGetAccessibleChildCount() const override; + + // ________ XAccessibleContext ________ + virtual OUString SAL_CALL getAccessibleName() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + + // ________ XAccessibleExtendedComponent ________ + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override; + virtual OUString SAL_CALL getTitledBorderText() override; + virtual OUString SAL_CALL getToolTipText() override; + + // the following interface is implemented in AccessibleBase, however it is + // also a (non-virtual) base class of XAccessibleExtendedComponent Thus + // these methods have to be overridden and forward to AccessibleBase + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XServiceInfo ________ + virtual OUString SAL_CALL getImplementationName() override; + +private: + bool m_bHasText; + css::uno::Reference< css::accessibility::XAccessibleContext > + m_xTextHelper; + + void InitTextEdit(); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartShape.cxx b/chart2/source/controller/accessibility/AccessibleChartShape.cxx new file mode 100644 index 000000000..73ff2e9c0 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartShape.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AccessibleChartShape.hxx" + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +AccessibleChartShape::AccessibleChartShape( + const AccessibleElementInfo& rAccInfo ) + :impl::AccessibleChartShape_Base( rAccInfo, true/*bMayHaveChildren*/, false/*bAlwaysTransparent*/ ) +{ + if ( !rAccInfo.m_aOID.isAdditionalShape() ) + return; + + Reference< drawing::XShape > xShape( rAccInfo.m_aOID.getAdditionalShape() ); + Reference< XAccessible > xParent; + if ( rAccInfo.m_pParent ) + { + xParent.set( rAccInfo.m_pParent ); + } + ::accessibility::AccessibleShapeInfo aShapeInfo( xShape, xParent ); + + m_aShapeTreeInfo.SetSdrView( rAccInfo.m_pSdrView ); + m_aShapeTreeInfo.SetController( nullptr ); + m_aShapeTreeInfo.SetWindow( VCLUnoHelper::GetWindow( rAccInfo.m_xWindow ) ); + m_aShapeTreeInfo.SetViewForwarder( rAccInfo.m_pViewForwarder ); + + ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance(); + m_pAccShape = rShapeHandler.CreateAccessibleObject( aShapeInfo, m_aShapeTreeInfo ); + if ( m_pAccShape.is() ) + { + m_pAccShape->Init(); + } +} + +AccessibleChartShape::~AccessibleChartShape() +{ + OSL_ASSERT( CheckDisposeState( false /* don't throw exceptions */ ) ); + + if ( m_pAccShape.is() ) + { + m_pAccShape->dispose(); + } +} + +// ________ XServiceInfo ________ +OUString AccessibleChartShape::getImplementationName() +{ + return "AccessibleChartShape"; +} + +// ________ XAccessibleContext ________ +sal_Int32 AccessibleChartShape::getAccessibleChildCount() +{ + sal_Int32 nCount(0); + if ( m_pAccShape.is() ) + { + nCount = m_pAccShape->getAccessibleChildCount(); + } + return nCount; +} + +Reference< XAccessible > AccessibleChartShape::getAccessibleChild( sal_Int32 i ) +{ + Reference< XAccessible > xChild; + if ( m_pAccShape.is() ) + { + xChild = m_pAccShape->getAccessibleChild( i ); + } + return xChild; +} + +sal_Int16 AccessibleChartShape::getAccessibleRole() +{ + sal_Int16 nRole(0); + if ( m_pAccShape.is() ) + { + nRole = m_pAccShape->getAccessibleRole(); + } + return nRole; +} + +OUString AccessibleChartShape::getAccessibleDescription() +{ + OUString aDescription; + if ( m_pAccShape.is() ) + { + aDescription = m_pAccShape->getAccessibleDescription(); + } + return aDescription; +} + +OUString AccessibleChartShape::getAccessibleName() +{ + OUString aName; + if ( m_pAccShape.is() ) + { + aName = m_pAccShape->getAccessibleName(); + } + return aName; +} + +// ________ XAccessibleComponent ________ +sal_Bool AccessibleChartShape::containsPoint( const awt::Point& aPoint ) +{ + bool bReturn = false; + if ( m_pAccShape.is() ) + { + bReturn = m_pAccShape->containsPoint( aPoint ); + } + return bReturn; +} + +Reference< XAccessible > AccessibleChartShape::getAccessibleAtPoint( const awt::Point& aPoint ) +{ + Reference< XAccessible > xResult; + if ( m_pAccShape.is() ) + { + xResult.set( m_pAccShape->getAccessibleAtPoint( aPoint ) ); + } + return xResult; +} + +awt::Rectangle AccessibleChartShape::getBounds() +{ + awt::Rectangle aBounds; + if ( m_pAccShape.is() ) + { + aBounds = m_pAccShape->getBounds(); + } + return aBounds; +} + +awt::Point AccessibleChartShape::getLocation() +{ + awt::Point aLocation; + if ( m_pAccShape.is() ) + { + aLocation = m_pAccShape->getLocation(); + } + return aLocation; +} + +awt::Point AccessibleChartShape::getLocationOnScreen() +{ + awt::Point aLocation; + if ( m_pAccShape.is() ) + { + aLocation = m_pAccShape->getLocationOnScreen(); + } + return aLocation; +} + +awt::Size AccessibleChartShape::getSize() +{ + awt::Size aSize; + if ( m_pAccShape.is() ) + { + aSize = m_pAccShape->getSize(); + } + return aSize; +} + +void AccessibleChartShape::grabFocus() +{ + return AccessibleBase::grabFocus(); +} + +sal_Int32 AccessibleChartShape::getForeground() +{ + sal_Int32 nColor(0); + if ( m_pAccShape.is() ) + { + nColor = m_pAccShape->getForeground(); + } + return nColor; +} + +sal_Int32 AccessibleChartShape::getBackground() +{ + sal_Int32 nColor(0); + if ( m_pAccShape.is() ) + { + nColor = m_pAccShape->getBackground(); + } + return nColor; +} + +// ________ XAccessibleExtendedComponent ________ +Reference< awt::XFont > AccessibleChartShape::getFont() +{ + Reference< awt::XFont > xFont; + if ( m_pAccShape.is() ) + { + xFont.set( m_pAccShape->getFont() ); + } + return xFont; +} + +OUString AccessibleChartShape::getTitledBorderText() +{ + OUString aText; + if ( m_pAccShape.is() ) + { + aText = m_pAccShape->getTitledBorderText(); + } + return aText; +} + +OUString AccessibleChartShape::getToolTipText() +{ + OUString aText; + if ( m_pAccShape.is() ) + { + aText = m_pAccShape->getToolTipText(); + } + return aText; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartShape.hxx b/chart2/source/controller/accessibility/AccessibleChartShape.hxx new file mode 100644 index 000000000..4377929fa --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartShape.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include + +namespace accessibility +{ +class AccessibleShape; +} + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + AccessibleBase, + css::accessibility::XAccessibleExtendedComponent > AccessibleChartShape_Base; +} + +class AccessibleChartShape : + public impl::AccessibleChartShape_Base +{ +public: + explicit AccessibleChartShape( const AccessibleElementInfo& rAccInfo ); + virtual ~AccessibleChartShape() override; + + // ________ XServiceInfo ________ + virtual OUString SAL_CALL getImplementationName() override; + + // ________ XAccessibleContext ________ + virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual OUString SAL_CALL getAccessibleName() override; + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XAccessibleExtendedComponent ________ + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont() override; + virtual OUString SAL_CALL getTitledBorderText() override; + virtual OUString SAL_CALL getToolTipText() override; + +private: + rtl::Reference m_pAccShape; + ::accessibility::AccessibleShapeTreeInfo m_aShapeTreeInfo; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleChartView.cxx b/chart2/source/controller/accessibility/AccessibleChartView.cxx new file mode 100644 index 000000000..6f9dad562 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleChartView.cxx @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include "AccessibleViewForwarder.hxx" +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::WeakReference; +using ::com::sun::star::uno::Any; +using osl::MutexGuard; + +namespace chart +{ + +AccessibleChartView::AccessibleChartView(SdrView* pView ) : + impl::AccessibleChartView_Base( + AccessibleElementInfo(), // empty for now + true, // has children + true // always transparent + ), + m_pSdrView( pView ) +{ + AddState( AccessibleStateType::OPAQUE ); +} + +AccessibleChartView::~AccessibleChartView() +{ +} + +awt::Rectangle AccessibleChartView::GetWindowPosSize() const +{ + Reference< awt::XWindow > xWindow( GetInfo().m_xWindow ); + if( ! xWindow.is()) + return awt::Rectangle(); + + awt::Rectangle aBBox( xWindow->getPosSize() ); + + VclPtr pWindow( VCLUnoHelper::GetWindow( GetInfo().m_xWindow )); + if( pWindow ) + { + SolarMutexGuard aSolarGuard; + Point aVCLPoint( pWindow->OutputToAbsoluteScreenPixel( Point( 0, 0 ) )); + aBBox.X = aVCLPoint.getX(); + aBBox.Y = aVCLPoint.getY(); + } + + return aBBox; +} + +awt::Point AccessibleChartView::GetUpperLeftOnScreen() const +{ + awt::Point aParentPosition; + + awt::Rectangle aBBox( GetWindowPosSize() ); + aParentPosition.X = aBBox.X; + aParentPosition.Y = aBBox.Y; + + return aParentPosition; +} + +// ________ XAccessibleContext ________ +OUString SAL_CALL AccessibleChartView::getAccessibleName() +{ + return SchResId(STR_OBJECT_DIAGRAM); +} + +OUString SAL_CALL AccessibleChartView::getAccessibleDescription() +{ + return getAccessibleName(); +} + +Reference< XAccessible > SAL_CALL AccessibleChartView::getAccessibleParent() +{ + return Reference< XAccessible >( m_xParent ); +} + +sal_Int32 SAL_CALL AccessibleChartView::getAccessibleIndexInParent() +{ + // the document is always the only child of the window + return 0; +} + +sal_Int16 SAL_CALL AccessibleChartView::getAccessibleRole() +{ + return AccessibleRole::DOCUMENT; +} + +// ________ XAccessibleComponent ________ +awt::Rectangle SAL_CALL AccessibleChartView::getBounds() +{ + awt::Rectangle aResult( GetWindowPosSize()); + Reference< XAccessible > xParent( m_xParent ); + if( xParent.is()) + { + Reference< XAccessibleComponent > xContext( xParent->getAccessibleContext(), uno::UNO_QUERY ); + if( xContext.is()) + { + awt::Point aParentPosition = xContext->getLocationOnScreen(); + aResult.X -= aParentPosition.X; + aResult.Y -= aParentPosition.Y; + } + } + return aResult; +} + +awt::Point SAL_CALL AccessibleChartView::getLocationOnScreen() +{ + awt::Rectangle aBounds( getBounds()); + awt::Point aResult; + Reference< XAccessible > xParent( m_xParent ); + if( xParent.is()) + { + Reference< XAccessibleComponent > xAccComp( + xParent->getAccessibleContext(), uno::UNO_QUERY ); + aResult = xAccComp->getLocationOnScreen(); + aResult.X += aBounds.X; + aResult.Y += aBounds.Y; + } + return aResult; +} + +// lang::XInitialization + +void SAL_CALL AccessibleChartView::initialize( const Sequence< Any >& rArguments ) +{ + //0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself + //1: frame::XModel representing the chart model - offers access to object data + //2: lang::XInterface representing the normal chart view - offers access to some extra object data + + //all arguments are only valid until next initialization + bool bChanged = false; + bool bOldInvalid = false; + bool bNewInvalid = false; + + Reference< view::XSelectionSupplier > xSelectionSupplier; + rtl::Reference<::chart::ChartModel> xChartModel; + Reference< uno::XInterface > xChartView; + Reference< XAccessible > xParent; + Reference< awt::XWindow > xWindow; + { + MutexGuard aGuard( m_aMutex); + xSelectionSupplier.set( m_xSelectionSupplier ); + xChartModel = m_xChartModel; + xChartView.set( m_xChartView ); + xParent.set( m_xParent ); + xWindow.set( m_xWindow ); + } + + if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() ) + { + bOldInvalid = true; + } + + if( rArguments.getLength() > 1 ) + { + Reference< frame::XModel > xNewChartModel; + rArguments[1] >>= xNewChartModel; + assert(!xNewChartModel || dynamic_cast<::chart::ChartModel*>(xNewChartModel.get())); + ::chart::ChartModel* pNewChartModel = dynamic_cast<::chart::ChartModel*>(xNewChartModel.get()); + if( pNewChartModel != xChartModel.get() ) + { + xChartModel = pNewChartModel; + bChanged = true; + } + } + else if( xChartModel.is() ) + { + bChanged = true; + xChartModel = nullptr; + } + + if( rArguments.getLength() > 2 ) + { + Reference< uno::XInterface > xNewChartView; + rArguments[2] >>= xNewChartView; + if( xNewChartView != xChartView ) + { + xChartView = xNewChartView; + bChanged = true; + } + } + else if( xChartView.is() ) + { + bChanged = true; + xChartView = nullptr; + } + + if( rArguments.getLength() > 3 ) + { + Reference< XAccessible > xNewParent; + rArguments[3] >>= xNewParent; + if( xNewParent != xParent ) + { + xParent = xNewParent; + bChanged = true; + } + } + + if( rArguments.getLength() > 4 ) + { + Reference< awt::XWindow > xNewWindow; + rArguments[4] >>= xNewWindow; + if( xNewWindow != xWindow ) + { + xWindow.set( xNewWindow ); + bChanged = true; + } + } + + if( rArguments.hasElements() && xChartModel.is() && xChartView.is() ) + { + Reference< view::XSelectionSupplier > xNewSelectionSupplier; + rArguments[0] >>= xNewSelectionSupplier; + if(xSelectionSupplier!=xNewSelectionSupplier) + { + bChanged = true; + if(xSelectionSupplier.is()) + xSelectionSupplier->removeSelectionChangeListener(this); + if(xNewSelectionSupplier.is()) + xNewSelectionSupplier->addSelectionChangeListener(this); + xSelectionSupplier = xNewSelectionSupplier; + } + } + else if( xSelectionSupplier.is() ) + { + bChanged = true; + xSelectionSupplier->removeSelectionChangeListener(this); + xSelectionSupplier = nullptr; + } + + if( !xSelectionSupplier.is() || !xChartModel.is() || !xChartView.is() ) + { + if(xSelectionSupplier.is()) + xSelectionSupplier->removeSelectionChangeListener(this); + xSelectionSupplier = nullptr; + xChartModel.clear(); + xChartView.clear(); + xParent.clear(); + xWindow.clear(); + + bNewInvalid = true; + } + + { + MutexGuard aGuard( m_aMutex); + m_xSelectionSupplier = WeakReference< view::XSelectionSupplier >(xSelectionSupplier); + m_xChartModel = xChartModel.get(); + m_xChartView = WeakReference< uno::XInterface >(xChartView); + m_xParent = WeakReference< XAccessible >(xParent); + m_xWindow = WeakReference< awt::XWindow >(xWindow); + } + + if( bOldInvalid && bNewInvalid ) + bChanged = false; + + if( !bChanged ) + return; + + { + //before notification we prepare for creation of new context + //the old context will be deleted after notification than + MutexGuard aGuard( m_aMutex); + if( xChartModel.is()) + m_spObjectHierarchy = + std::make_shared( xChartModel, comphelper::getFromUnoTunnel(m_xChartView) ); + else + m_spObjectHierarchy.reset(); + } + + { + AccessibleElementInfo aAccInfo; + aAccInfo.m_aOID = ObjectIdentifier("ROOT"); + aAccInfo.m_xChartDocument = m_xChartModel; + aAccInfo.m_xSelectionSupplier = m_xSelectionSupplier; + aAccInfo.m_xView = m_xChartView; + aAccInfo.m_xWindow = m_xWindow; + aAccInfo.m_pParent = nullptr; + aAccInfo.m_spObjectHierarchy = m_spObjectHierarchy; + aAccInfo.m_pSdrView = m_pSdrView; + VclPtr pWindow = VCLUnoHelper::GetWindow( m_xWindow ); + m_pViewForwarder.reset( new AccessibleViewForwarder( this, pWindow ) ); + aAccInfo.m_pViewForwarder = m_pViewForwarder.get(); + // broadcasts an INVALIDATE_ALL_CHILDREN event globally + SetInfo( aAccInfo ); + } +} + +// view::XSelectionChangeListener + +void SAL_CALL AccessibleChartView::selectionChanged( const lang::EventObject& /*rEvent*/ ) +{ + Reference< view::XSelectionSupplier > xSelectionSupplier; + { + MutexGuard aGuard( m_aMutex); + xSelectionSupplier.set(m_xSelectionSupplier); + } + + if( !xSelectionSupplier.is() ) + return; + + ObjectIdentifier aSelectedOID( xSelectionSupplier->getSelection() ); + if ( m_aCurrentSelectionOID.isValid() ) + { + NotifyEvent( EventType::LOST_SELECTION, m_aCurrentSelectionOID ); + } + if( aSelectedOID.isValid() ) + { + NotifyEvent( EventType::GOT_SELECTION, aSelectedOID ); + } + m_aCurrentSelectionOID = aSelectedOID; +} + +// XEventListener +void SAL_CALL AccessibleChartView::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleTextHelper.cxx b/chart2/source/controller/accessibility/AccessibleTextHelper.cxx new file mode 100644 index 000000000..2a58d9484 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleTextHelper.cxx @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +AccessibleTextHelper::AccessibleTextHelper( + DrawViewWrapper * pDrawViewWrapper ) : + m_pDrawViewWrapper( pDrawViewWrapper ) +{} + +AccessibleTextHelper::~AccessibleTextHelper() +{ +} + +// ____ XInitialization ____ +void SAL_CALL AccessibleTextHelper::initialize( const Sequence< uno::Any >& aArguments ) +{ + OUString aCID; + Reference< XAccessible > xEventSource; + Reference< awt::XWindow > xWindow; + + if( aArguments.getLength() >= 3 ) + { + aArguments[0] >>= aCID; + aArguments[1] >>= xEventSource; + aArguments[2] >>= xWindow; + } + OSL_ENSURE( !aCID.isEmpty(), "Empty CID" ); + OSL_ENSURE( xEventSource.is(), "Empty Event Source" ); + OSL_ENSURE( xWindow.is(), "Empty Window" ); + if( !xEventSource.is() || aCID.isEmpty() ) + return; + + SolarMutexGuard aSolarGuard; + + m_pTextHelper.reset(); + + VclPtr pWindow( VCLUnoHelper::GetWindow( xWindow )); + if( pWindow ) + { + SdrView * pView = m_pDrawViewWrapper; + if( pView ) + { + SdrObject * pTextObj = m_pDrawViewWrapper->getNamedSdrObject( aCID ); + if( pTextObj ) + { + m_pTextHelper.reset( new ::accessibility::AccessibleTextHelper(std::make_unique(*pTextObj, nullptr, *pView, *pWindow->GetOutDev())) ); + m_pTextHelper->SetEventSource( xEventSource ); + } + } + } + + OSL_ENSURE( m_pTextHelper, "Couldn't create text helper" ); +} + +// ____ XAccessibleContext ____ +::sal_Int32 SAL_CALL AccessibleTextHelper::getAccessibleChildCount() +{ + if( m_pTextHelper ) + { + SolarMutexGuard aSolarGuard; + return m_pTextHelper->GetChildCount(); + } + return 0; +} + +Reference< XAccessible > SAL_CALL AccessibleTextHelper::getAccessibleChild( ::sal_Int32 i ) +{ + if( m_pTextHelper ) + { + SolarMutexGuard aSolarGuard; + return m_pTextHelper->GetChild( i ); + } + return Reference< XAccessible >(); +} + +Reference< XAccessible > SAL_CALL AccessibleTextHelper::getAccessibleParent() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessible >(); +} + +::sal_Int32 SAL_CALL AccessibleTextHelper::getAccessibleIndexInParent() +{ + OSL_FAIL( "Not implemented in this helper" ); + return -1; +} + +::sal_Int16 SAL_CALL AccessibleTextHelper::getAccessibleRole() +{ + OSL_FAIL( "Not implemented in this helper" ); + return AccessibleRole::UNKNOWN; +} + +OUString SAL_CALL AccessibleTextHelper::getAccessibleDescription() +{ + OSL_FAIL( "Not implemented in this helper" ); + return OUString(); +} + +OUString SAL_CALL AccessibleTextHelper::getAccessibleName() +{ + OSL_FAIL( "Not implemented in this helper" ); + return OUString(); +} + +Reference< XAccessibleRelationSet > SAL_CALL AccessibleTextHelper::getAccessibleRelationSet() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessibleRelationSet >(); +} + +Reference< XAccessibleStateSet > SAL_CALL AccessibleTextHelper::getAccessibleStateSet() +{ + OSL_FAIL( "Not implemented in this helper" ); + return Reference< XAccessibleStateSet >(); +} + +lang::Locale SAL_CALL AccessibleTextHelper::getLocale() +{ + OSL_FAIL( "Not implemented in this helper" ); + return lang::Locale(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx b/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx new file mode 100644 index 000000000..31395f118 --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleViewForwarder.cxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AccessibleViewForwarder.hxx" +#include + +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +AccessibleViewForwarder::AccessibleViewForwarder( AccessibleChartView* pAccChartView, vcl::Window* pWindow ) + :m_pAccChartView( pAccChartView ) + ,m_pWindow( pWindow ) + ,m_aMapMode( MapUnit::Map100thMM ) +{ +} + +AccessibleViewForwarder::~AccessibleViewForwarder() +{ +} + +// ________ IAccessibleViewforwarder ________ + +tools::Rectangle AccessibleViewForwarder::GetVisibleArea() const +{ + tools::Rectangle aVisibleArea; + if ( m_pWindow ) + { + aVisibleArea.SetPos( Point( 0, 0 ) ); + aVisibleArea.SetSize( m_pWindow->GetOutputSizePixel() ); + aVisibleArea = m_pWindow->PixelToLogic( aVisibleArea, m_aMapMode ); + } + return aVisibleArea; +} + +Point AccessibleViewForwarder::LogicToPixel( const Point& rPoint ) const +{ + Point aPoint; + if ( m_pAccChartView && m_pWindow ) + { + awt::Point aLocation = m_pAccChartView->getLocationOnScreen(); + Point aTopLeft( aLocation.X, aLocation.Y ); + aPoint = m_pWindow->LogicToPixel( rPoint, m_aMapMode ) + aTopLeft; + } + return aPoint; +} + +Size AccessibleViewForwarder::LogicToPixel( const Size& rSize ) const +{ + Size aSize; + if ( m_pWindow ) + { + aSize = m_pWindow->LogicToPixel( rSize, m_aMapMode ); + } + return aSize; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx b/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx new file mode 100644 index 000000000..5bfbd06ad --- /dev/null +++ b/chart2/source/controller/accessibility/AccessibleViewForwarder.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace vcl +{ +class Window; +} + +namespace chart +{ +class AccessibleChartView; + +class AccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder +{ +public: + AccessibleViewForwarder(AccessibleChartView* pAccChartView, vcl::Window* pWindow); + virtual ~AccessibleViewForwarder() override; + + // ________ IAccessibleViewforwarder ________ + virtual tools::Rectangle GetVisibleArea() const override; + virtual Point LogicToPixel(const Point& rPoint) const override; + virtual Size LogicToPixel(const Size& rSize) const override; + +private: + AccessibleViewForwarder(AccessibleViewForwarder const&) = delete; + AccessibleViewForwarder& operator=(AccessibleViewForwarder const&) = delete; + + AccessibleChartView* m_pAccChartView; + VclPtr m_pWindow; + MapMode m_aMapMode; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/ChartElementFactory.cxx b/chart2/source/controller/accessibility/ChartElementFactory.cxx new file mode 100644 index 000000000..a173ac0f4 --- /dev/null +++ b/chart2/source/controller/accessibility/ChartElementFactory.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartElementFactory.hxx" +#include +#include "AccessibleChartElement.hxx" + +namespace chart +{ +rtl::Reference +ChartElementFactory::CreateChartElement(const AccessibleElementInfo& rAccInfo) +{ + ObjectIdentifier aOID(rAccInfo.m_aOID); + ObjectType eType(aOID.getObjectType()); + + switch (eType) + { + case OBJECTTYPE_DATA_POINT: + case OBJECTTYPE_LEGEND_ENTRY: + return new AccessibleChartElement(rAccInfo, false); + case OBJECTTYPE_PAGE: + case OBJECTTYPE_TITLE: + case OBJECTTYPE_LEGEND: + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM_FLOOR: + case OBJECTTYPE_AXIS: + case OBJECTTYPE_AXIS_UNITLABEL: + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_CURVE: // e.g. a statistical method printed as line + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_STOCK_RANGE: + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + case OBJECTTYPE_DATA_CURVE_EQUATION: + return new AccessibleChartElement(rAccInfo, true); + case OBJECTTYPE_UNKNOWN: + break; + default: + break; + } + + return nullptr; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/accessibility/ChartElementFactory.hxx b/chart2/source/controller/accessibility/ChartElementFactory.hxx new file mode 100644 index 000000000..08ae64598 --- /dev/null +++ b/chart2/source/controller/accessibility/ChartElementFactory.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class AccessibleBase; +struct AccessibleElementInfo; + +class ChartElementFactory +{ +public: + /** @return a newly created object (using the new operator) that corresponds + to the given unique id + */ + static rtl::Reference CreateChartElement(const AccessibleElementInfo& rAccInfo); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx b/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx new file mode 100644 index 000000000..10cd00e29 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AreaWrapper.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AreaWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include + +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticAreaWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticAreaWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticAreaWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +AreaWrapper::AreaWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +AreaWrapper::~AreaWrapper() +{} + +// ____ XShape ____ +awt::Point SAL_CALL AreaWrapper::getPosition() +{ + return awt::Point(0,0); +} + +void SAL_CALL AreaWrapper::setPosition( const awt::Point& /*aPosition*/ ) +{ + OSL_FAIL( "trying to set position of chart area" ); +} + +awt::Size SAL_CALL AreaWrapper::getSize() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +void SAL_CALL AreaWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of chart area" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL AreaWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartArea"; +} + +// ____ XComponent ____ +void SAL_CALL AreaWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL AreaWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL AreaWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > AreaWrapper::getInnerPropertySet() +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + return xChartDoc->getPageBackground(); + OSL_FAIL("AreaWrapper::getInnerPropertySet() is NULL"); + return nullptr; +} + +const Sequence< beans::Property >& AreaWrapper::getPropertySequence() +{ + return *StaticAreaWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > AreaWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("LineStyle","LineStyle") ); + + return aWrappedProperties; +} + +OUString SAL_CALL AreaWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Area"; +} + +sal_Bool SAL_CALL AreaWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL AreaWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties" }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx b/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx new file mode 100644 index 000000000..3de57f421 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AreaWrapper.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class AreaWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + explicit AreaWrapper(const std::shared_ptr& spChart2ModelContact); + virtual ~AreaWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx b/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx new file mode 100644 index 000000000..02306d2c1 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AxisWrapper.cxx @@ -0,0 +1,672 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AxisWrapper.hxx" +#include +#include +#include +#include "Chart2ModelContact.hxx" +#include +#include "GridWrapper.hxx" +#include "TitleWrapper.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "WrappedCharacterHeightProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include "WrappedGapwidthProperty.hxx" +#include "WrappedScaleProperty.hxx" +#include "WrappedNumberFormatProperty.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +enum +{ + PROP_AXIS_MAX, + PROP_AXIS_MIN, + PROP_AXIS_STEPMAIN, + PROP_AXIS_STEPHELP, //deprecated property use 'StepHelpCount' instead + PROP_AXIS_STEPHELP_COUNT, + PROP_AXIS_AUTO_MAX, + PROP_AXIS_AUTO_MIN, + PROP_AXIS_AUTO_STEPMAIN, + PROP_AXIS_AUTO_STEPHELP, + PROP_AXIS_TYPE, + PROP_AXIS_TIME_INCREMENT, + PROP_AXIS_EXPLICIT_TIME_INCREMENT, + PROP_AXIS_LOGARITHMIC, + PROP_AXIS_REVERSEDIRECTION, + PROP_AXIS_VISIBLE, + PROP_AXIS_CROSSOVER_POSITION, + PROP_AXIS_CROSSOVER_VALUE, + PROP_AXIS_ORIGIN, + PROP_AXIS_AUTO_ORIGIN, + PROP_AXIS_MARKS, + PROP_AXIS_HELPMARKS, + PROP_AXIS_MARK_POSITION, + PROP_AXIS_DISPLAY_LABELS, + PROP_AXIS_NUMBERFORMAT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_AXIS_LABEL_POSITION, + PROP_AXIS_TEXT_ROTATION, + PROP_AXIS_ARRANGE_ORDER, + PROP_AXIS_TEXTBREAK, + PROP_AXIS_CAN_OVERLAP, + PROP_AXIS_STACKEDTEXT, + PROP_AXIS_OVERLAP, + PROP_AXIS_GAP_WIDTH, + PROP_AXIS_DISPLAY_UNITS, + PROP_AXIS_BUILTINUNIT, + PROP_AXIS_TRY_STAGGERING_FIRST, + PROP_AXIS_MAJOR_ORIGIN +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + //Properties for scaling: + rOutProperties.emplace_back( "Max", + PROP_AXIS_MAX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "Min", + PROP_AXIS_MIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StepMain", + PROP_AXIS_STEPMAIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StepHelpCount", + PROP_AXIS_STEPHELP_COUNT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + //deprecated property use 'StepHelpCount' instead + rOutProperties.emplace_back( "StepHelp", + PROP_AXIS_STEPHELP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutoMax", + PROP_AXIS_AUTO_MAX, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoMin", + PROP_AXIS_AUTO_MIN, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoStepMain", + PROP_AXIS_AUTO_STEPMAIN, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AutoStepHelp", + PROP_AXIS_AUTO_STEPHELP, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AxisType", + PROP_AXIS_TYPE, + cppu::UnoType::get(), //type css::chart::ChartAxisType + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TimeIncrement", + PROP_AXIS_TIME_INCREMENT, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ExplicitTimeIncrement", + PROP_AXIS_EXPLICIT_TIME_INCREMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::READONLY | + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "Logarithmic", + PROP_AXIS_LOGARITHMIC, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReverseDirection", + PROP_AXIS_REVERSEDIRECTION, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //todo: this property is missing in the API + rOutProperties.emplace_back( "Visible", + PROP_AXIS_VISIBLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverPosition", + PROP_AXIS_CROSSOVER_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverValue", + PROP_AXIS_CROSSOVER_VALUE, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "Origin", + PROP_AXIS_ORIGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutoOrigin", + PROP_AXIS_AUTO_ORIGIN, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for interval marks: + rOutProperties.emplace_back( "Marks", + PROP_AXIS_MARKS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "HelpMarks", + PROP_AXIS_HELPMARKS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MarkPosition", + PROP_AXIS_MARK_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for labels: + rOutProperties.emplace_back( "DisplayLabels", + PROP_AXIS_DISPLAY_LABELS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_AXIS_NUMBERFORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LabelPosition", + PROP_AXIS_LABEL_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextRotation", + PROP_AXIS_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ArrangeOrder", + PROP_AXIS_ARRANGE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextBreak", + PROP_AXIS_TEXTBREAK, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextCanOverlap", + PROP_AXIS_CAN_OVERLAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StackedText", + PROP_AXIS_STACKEDTEXT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Properties related to bar charts: + rOutProperties.emplace_back( "Overlap", + PROP_AXIS_OVERLAP, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GapWidth", + PROP_AXIS_GAP_WIDTH, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for display units: + rOutProperties.emplace_back( "DisplayUnits", + PROP_AXIS_DISPLAY_UNITS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for labels: + rOutProperties.emplace_back( "BuiltInUnit", + PROP_AXIS_BUILTINUNIT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + rOutProperties.emplace_back( "TryStaggeringFirst", + PROP_AXIS_TRY_STAGGERING_FIRST, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MajorOrigin", + PROP_AXIS_MAJOR_ORIGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +struct StaticAxisWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticAxisWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticAxisWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +AxisWrapper::AxisWrapper( + tAxisType eType, const std::shared_ptr& spChart2ModelContact) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_eType( eType ) +{ +} + +AxisWrapper::~AxisWrapper() +{ +} + +// ____ chart::XAxis ____ +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getAxisTitle() +{ + if( !m_xAxisTitle.is() ) + { + TitleHelper::eTitleType eTitleType( TitleHelper::X_AXIS_TITLE ); + switch( m_eType ) + { + case X_AXIS: + eTitleType = TitleHelper::X_AXIS_TITLE; + break; + case Y_AXIS: + eTitleType = TitleHelper::Y_AXIS_TITLE; + break; + case Z_AXIS: + eTitleType = TitleHelper::Z_AXIS_TITLE; + break; + case SECOND_X_AXIS: + eTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + break; + case SECOND_Y_AXIS: + eTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + break; + default: + return nullptr; + } + m_xAxisTitle = new TitleWrapper( eTitleType, m_spChart2ModelContact ); + } + return m_xAxisTitle; +} +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getMajorGrid() +{ + if( !m_xMajorGrid.is() ) + { + GridWrapper::tGridType eGridType( GridWrapper::X_MAJOR_GRID ); + switch( m_eType ) + { + case X_AXIS: + eGridType = GridWrapper::X_MAJOR_GRID; + break; + case Y_AXIS: + eGridType = GridWrapper::Y_MAJOR_GRID; + break; + case Z_AXIS: + eGridType = GridWrapper::Z_MAJOR_GRID; + break; + default: + return nullptr; + } + m_xMajorGrid = new GridWrapper( eGridType, m_spChart2ModelContact ); + } + return m_xMajorGrid; +} +Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getMinorGrid() +{ + if( !m_xMinorGrid.is() ) + { + GridWrapper::tGridType eGridType( GridWrapper::X_MAJOR_GRID ); + switch( m_eType ) + { + case X_AXIS: + eGridType = GridWrapper::X_MINOR_GRID; + break; + case Y_AXIS: + eGridType = GridWrapper::Y_MINOR_GRID; + break; + case Z_AXIS: + eGridType = GridWrapper::Z_MINOR_GRID; + break; + default: + return nullptr; + } + m_xMinorGrid = new GridWrapper( eGridType, m_spChart2ModelContact ); + } + return m_xMinorGrid; +} + +// ____ XShape ____ +awt::Point SAL_CALL AxisWrapper::getPosition() +{ + awt::Point aResult( m_spChart2ModelContact->GetAxisPosition( getAxis() ) ); + return aResult; +} + +void SAL_CALL AxisWrapper::setPosition( const awt::Point& /*aPosition*/ ) +{ + OSL_FAIL( "trying to set position of Axis" ); +} + +awt::Size SAL_CALL AxisWrapper::getSize() +{ + awt::Size aSize( m_spChart2ModelContact->GetAxisSize( getAxis() ) ); + return aSize; +} + +void SAL_CALL AxisWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of Axis" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL AxisWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartAxis"; +} + +// ____ XNumberFormatsSupplier ____ +uno::Reference< beans::XPropertySet > SAL_CALL AxisWrapper::getNumberFormatSettings() +{ + rtl::Reference xChartModel( m_spChart2ModelContact->getDocumentModel() ); + if( xChartModel ) + return xChartModel->getNumberFormatSettings(); + + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< util::XNumberFormats > SAL_CALL AxisWrapper::getNumberFormats() +{ + rtl::Reference xChartModel( m_spChart2ModelContact->getDocumentModel() ); + if( xChartModel ) + return xChartModel->getNumberFormats(); + + return uno::Reference< util::XNumberFormats >(); +} + +void AxisWrapper::getDimensionAndMainAxisBool( tAxisType eType, sal_Int32& rnDimensionIndex, bool& rbMainAxis ) +{ + switch( eType ) + { + case X_AXIS: + rnDimensionIndex = 0; rbMainAxis = true; break; + case Y_AXIS: + rnDimensionIndex = 1; rbMainAxis = true; break; + case Z_AXIS: + rnDimensionIndex = 2; rbMainAxis = true; break; + case SECOND_X_AXIS: + rnDimensionIndex = 0; rbMainAxis = false; break; + case SECOND_Y_AXIS: + rnDimensionIndex = 1; rbMainAxis = false; break; + } +} + +// ____ XComponent ____ +void SAL_CALL AxisWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + DisposeHelper::DisposeAndClear( m_xAxisTitle ); + DisposeHelper::DisposeAndClear( m_xMajorGrid ); + DisposeHelper::DisposeAndClear( m_xMinorGrid ); + + clearWrappedPropertySet(); +} + +void SAL_CALL AxisWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL AxisWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//ReferenceSizePropertyProvider +void AxisWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp( getAxis(), uno::UNO_QUERY ); + if( xProp.is() ) + { + if( xProp->getPropertyValue("ReferencePageSize").hasValue() ) + xProp->setPropertyValue("ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any AxisWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp( getAxis(), uno::UNO_QUERY ); + if( xProp.is() ) + aRet = xProp->getPropertyValue("ReferencePageSize"); + return aRet; +} +awt::Size AxisWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +Reference< chart2::XAxis > AxisWrapper::getAxis() +{ + rtl::Reference< Axis > xAxis; + try + { + sal_Int32 nDimensionIndex = 0; + bool bMainAxis = true; + AxisWrapper::getDimensionAndMainAxisBool( m_eType, nDimensionIndex, bMainAxis ); + + rtl::Reference< Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + if( !xAxis.is() ) + { + xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, m_spChart2ModelContact->m_xContext ); + if( xAxis.is() ) + xAxis->setPropertyValue("Show", uno::Any( false ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xAxis; +} + +// WrappedPropertySet +Reference< beans::XPropertySet > AxisWrapper::getInnerPropertySet() +{ + return Reference< beans::XPropertySet >( getAxis(), uno::UNO_QUERY ); +} + +const Sequence< beans::Property >& AxisWrapper::getPropertySequence() +{ + return *StaticAxisWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > AxisWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedTextRotationProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty("Marks","MajorTickmarks") ); + aWrappedProperties.emplace_back( new WrappedProperty("HelpMarks","MinorTickmarks") ); + aWrappedProperties.emplace_back( new WrappedProperty("TextCanOverlap","TextOverlap") ); + aWrappedProperties.emplace_back( new WrappedProperty("ArrangeOrder","ArrangeOrder") ); + aWrappedProperties.emplace_back( new WrappedProperty("Visible","Show") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("DisplayLabels","DisplayLabels") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("TryStaggeringFirst","TryStaggeringFirst") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("TextBreak","TextBreak") ); + aWrappedProperties.emplace_back( new WrappedNumberFormatProperty(m_spChart2ModelContact) ); + aWrappedProperties.emplace_back( new WrappedLinkNumberFormatProperty ); + aWrappedProperties.emplace_back( new WrappedProperty("StackedText","StackCharacters") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("CrossoverPosition","CrossoverPosition") ); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("MajorOrigin","MajorOrigin") ); + { + WrappedGapwidthProperty* pWrappedGapwidthProperty( new WrappedGapwidthProperty( m_spChart2ModelContact ) ); + WrappedBarOverlapProperty* pWrappedBarOverlapProperty( new WrappedBarOverlapProperty( m_spChart2ModelContact ) ); + sal_Int32 nDimensionIndex = 0; + bool bMainAxis = true; + sal_Int32 nAxisIndex = 0; + AxisWrapper::getDimensionAndMainAxisBool( m_eType, nDimensionIndex, bMainAxis ); + if( !bMainAxis ) + nAxisIndex = 1; + pWrappedGapwidthProperty->setDimensionAndAxisIndex( nDimensionIndex, nAxisIndex ); + pWrappedBarOverlapProperty->setDimensionAndAxisIndex( nDimensionIndex, nAxisIndex ); + aWrappedProperties.emplace_back( pWrappedGapwidthProperty ); + aWrappedProperties.emplace_back( pWrappedBarOverlapProperty ); + } + + WrappedScaleProperty::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL AxisWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Axis"; +} + +sal_Bool SAL_CALL AxisWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL AxisWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartAxis", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx b/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx new file mode 100644 index 000000000..b421ab331 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/AxisWrapper.hxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "ReferenceSizePropertyProvider.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::chart2 { class XAxis; } + +namespace chart::wrapper +{ +class Chart2ModelContact; + +class AxisWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::chart::XAxis + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + , css::util::XNumberFormatsSupplier + > + , public ReferenceSizePropertyProvider +{ +public: + enum tAxisType + { + X_AXIS, + Y_AXIS, + Z_AXIS, + SECOND_X_AXIS, + SECOND_Y_AXIS + }; + + AxisWrapper(tAxisType eType, const std::shared_ptr& spChart2ModelContact); + virtual ~AxisWrapper() override; + + static void getDimensionAndMainAxisBool( tAxisType eType, sal_Int32& rnDimensionIndex, bool& rbMainAxis ); + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + // ____ chart::XAxis ____ + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getAxisTitle( ) override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getMajorGrid( ) override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getMinorGrid( ) override; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XNumberFormatsSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getNumberFormatSettings() override; + virtual css::uno::Reference< + css::util::XNumberFormats > SAL_CALL getNumberFormats() override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: //methods + css::uno::Reference< css::chart2::XAxis > getAxis(); + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + tAxisType m_eType; + + css::uno::Reference< css::beans::XPropertySet > m_xAxisTitle; + css::uno::Reference< css::beans::XPropertySet > m_xMajorGrid; + css::uno::Reference< css::beans::XPropertySet > m_xMinorGrid; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx new file mode 100644 index 000000000..e65d78915 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.cxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +Chart2ModelContact::Chart2ModelContact( + const Reference< uno::XComponentContext > & xContext ) : + m_xContext( xContext ), + m_xChartModel( nullptr ) +{ +} + +Chart2ModelContact::~Chart2ModelContact() +{ + clear(); +} + +void Chart2ModelContact::setDocumentModel( ChartModel* pChartModel ) +{ + clear(); + m_xChartModel = pChartModel; + if( !pChartModel ) + return; + + uno::Reference< container::XNameContainer > xDashTable( pChartModel->createInstance("com.sun.star.drawing.DashTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xGradientTable( pChartModel->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xHatchTable( pChartModel->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xBitmapTable( pChartModel->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY ); + uno::Reference< container::XNameContainer > xTransparencyGradientTable( pChartModel->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY ); + m_aTableMap["LineDashName"] = xDashTable; + m_aTableMap["FillGradientName"] = xGradientTable; + m_aTableMap["FillHatchName"] = xHatchTable; + m_aTableMap["FillBitmapName"] = xBitmapTable; + m_aTableMap["FillTransparenceGradientName"] = xTransparencyGradientTable; +} + +void Chart2ModelContact::clear() +{ + m_xChartModel.clear(); + m_xChartView.clear(); +} + +rtl::Reference< ChartModel > Chart2ModelContact::getDocumentModel() const +{ + return m_xChartModel; +} + +rtl::Reference< ::chart::Diagram > Chart2ModelContact::getDiagram() const +{ + try + { + rtl::Reference xChartModel = getDocumentModel(); + if( xChartModel) + return xChartModel->getFirstChartDiagram(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; +} + +rtl::Reference< ::chart::ChartView > const & Chart2ModelContact::getChartView() const +{ + if(!m_xChartView.is()) + { + // get the chart view + rtl::Reference xChartModel( m_xChartModel ); + if( xChartModel ) + { + auto xInstance = xChartModel->createInstance( CHART_VIEW_SERVICE_NAME ); + auto pChartView = dynamic_cast(xInstance.get()); + assert(!xInstance || pChartView); + m_xChartView = pChartView; + } + } + return m_xChartView; +} + +ExplicitValueProvider* Chart2ModelContact::getExplicitValueProvider() const +{ + getChartView(); + + //obtain the ExplicitValueProvider from the chart view + return m_xChartView.get(); +} + +rtl::Reference Chart2ModelContact::getDrawPage() const +{ + rtl::Reference xResult; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + xResult = pProvider->getDrawModelWrapper()->getMainDrawPage(); + } + return xResult; +} + +void Chart2ModelContact::getExplicitValuesForAxis( + const Reference< XAxis > & xAxis, + ExplicitScaleData & rOutExplicitScale, + ExplicitIncrementData & rOutExplicitIncrement ) +{ + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + pProvider->getExplicitValuesForAxis( + xAxis, rOutExplicitScale, rOutExplicitIncrement ); + } +} + +sal_Int32 Chart2ModelContact::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis ) +{ + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( + xAxis, ChartModelHelper::findDiagram( m_xChartModel ) ) ); + + return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( xAxis, xCooSys + , m_xChartModel.get() ); +} + +sal_Int32 Chart2ModelContact::getExplicitNumberFormatKeyForSeries( + const Reference< chart2::XDataSeries >& xSeries ) +{ + return ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + uno::Reference< beans::XPropertySet >( xSeries, uno::UNO_QUERY )); +} + +awt::Size Chart2ModelContact::GetPageSize() const +{ + return ChartModelHelper::getPageSize(m_xChartModel.get()); +} + +awt::Rectangle Chart2ModelContact::SubstractAxisTitleSizes( const awt::Rectangle& rPositionRect ) +{ + awt::Rectangle aRect = ExplicitValueProvider::AddSubtractAxisTitleSizes( + *m_xChartModel.get(), getChartView().get(), rPositionRect, true ); + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleIncludingTitle() const +{ + awt::Rectangle aRect( GetDiagramRectangleIncludingAxes() ); + + //add axis title sizes to the diagram size + aRect = ExplicitValueProvider::AddSubtractAxisTitleSizes( + *m_xChartModel.get(), getChartView().get(), aRect, false ); + + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleIncludingAxes() const +{ + awt::Rectangle aRect(0,0,0,0); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + + if( DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_INCLUDING ) + aRect = DiagramHelper::getDiagramRectangleFromModel(m_xChartModel.get()); + else + { + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + aRect = pProvider->getRectangleOfObject("PlotAreaIncludingAxes"); + } + return aRect; +} + +awt::Rectangle Chart2ModelContact::GetDiagramRectangleExcludingAxes() const +{ + awt::Rectangle aRect(0,0,0,0); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + + if( DiagramHelper::getDiagramPositioningMode( xDiagram ) == DiagramPositioningMode_EXCLUDING ) + aRect = DiagramHelper::getDiagramRectangleFromModel(m_xChartModel.get()); + else + { + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + aRect = pProvider->getDiagramRectangleExcludingAxes(); + } + return aRect; +} + +awt::Size Chart2ModelContact::GetLegendSize() const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_xChartModel.get() ); + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xLegend, m_xChartModel ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetLegendPosition() const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider ) + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_xChartModel.get() ); + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xLegend, m_xChartModel ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +awt::Size Chart2ModelContact::GetTitleSize( const uno::Reference< css::chart2::XTitle > & xTitle ) const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xTitle.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, m_xChartModel ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetTitlePosition( const uno::Reference< css::chart2::XTitle > & xTitle ) const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xTitle.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, m_xChartModel.get() ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +awt::Size Chart2ModelContact::GetAxisSize( const uno::Reference< css::chart2::XAxis > & xAxis ) const +{ + awt::Size aSize; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xAxis.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, m_xChartModel.get() ) ); + aSize = ToSize( pProvider->getRectangleOfObject( aCID ) ); + } + return aSize; +} + +awt::Point Chart2ModelContact::GetAxisPosition( const uno::Reference< css::chart2::XAxis > & xAxis ) const +{ + awt::Point aPoint; + ExplicitValueProvider* pProvider( getExplicitValueProvider() ); + if( pProvider && xAxis.is() ) + { + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, m_xChartModel.get() ) ); + aPoint = ToPoint( pProvider->getRectangleOfObject( aCID ) ); + } + return aPoint; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx new file mode 100644 index 000000000..7a89fb7dd --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/Chart2ModelContact.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart { struct ExplicitIncrementData; } +namespace chart { struct ExplicitScaleData; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XTitle; } +namespace com::sun::star::container { class XNameContainer; } +namespace com::sun::star::drawing { class XDrawPage; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XUnoTunnel; } +namespace com::sun::star::uno { class XComponentContext; } + + +namespace chart +{ +class ExplicitValueProvider; +class ChartModel; + +namespace wrapper +{ + +class Chart2ModelContact final +{ +public: + explicit Chart2ModelContact( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + ~Chart2ModelContact(); + +public: + void setDocumentModel( ChartModel* pChartModel ); + void clear(); + + rtl::Reference getDocumentModel() const; + + rtl::Reference< ::chart::Diagram > getDiagram() const; + + rtl::Reference getDrawPage() const; + + /** get the current values calculated for an axis in the current view in + case properties are 'auto'. + */ + void getExplicitValuesForAxis( + const css::uno::Reference< css::chart2::XAxis > & xAxis, + ExplicitScaleData & rOutExplicitScale, + ExplicitIncrementData & rOutExplicitIncrement ); + + sal_Int32 getExplicitNumberFormatKeyForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis ); + + static sal_Int32 getExplicitNumberFormatKeyForSeries( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + + /** Returns the size of the page in logic coordinates. This value is used + for setting an appropriate "ReferencePageSize" for FontHeights. + */ + css::awt::Size GetPageSize() const; + + /** calculates the current axes title sizes and subtract that space them from the given rectangle + */ + css::awt::Rectangle SubstractAxisTitleSizes( const css::awt::Rectangle& rPositionRect ); + + /** Returns the position and size of the diagram in logic coordinates (100th mm) including + the space used for axes including axes titles. + */ + css::awt::Rectangle GetDiagramRectangleIncludingTitle() const; + + /** Returns the position and size of the diagram in logic coordinates (100th mm) including + the space used for axes excluding axes titles. + */ + css::awt::Rectangle GetDiagramRectangleIncludingAxes() const; + + /** Returns the position and size of the diagram in logic coordinates (100th mm) excluding + the space used for axes (inner plot area). + */ + css::awt::Rectangle GetDiagramRectangleExcludingAxes() const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetLegendSize() const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetLegendPosition() const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetTitleSize( const css::uno::Reference< css::chart2::XTitle > & xTitle ) const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetTitlePosition( const css::uno::Reference< css::chart2::XTitle > & xTitle ) const; + + /** Returns the size of the object in logic coordinates. + */ + css::awt::Size GetAxisSize( const css::uno::Reference< css::chart2::XAxis > & xAxis ) const; + + /** Returns the position of the object in logic coordinates. + */ + css::awt::Point GetAxisPosition( const css::uno::Reference< css::chart2::XAxis > & xAxis ) const; + +private: //methods + ExplicitValueProvider* getExplicitValueProvider() const; + rtl::Reference< ChartView > const & getChartView() const; + +public: //member + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +private: //member + unotools::WeakReference< ChartModel > m_xChartModel; + + mutable rtl::Reference< ChartView > m_xChartView; + + std::map< OUString, css::uno::Reference< css::container::XNameContainer > > m_aTableMap; +}; + +} // namespace wrapper +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx new file mode 100644 index 000000000..787c9ba1b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.cxx @@ -0,0 +1,695 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartDataWrapper.hxx" +#include +#include +#include +#include +#include +#include "Chart2ModelContact.hxx" +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::chart2::XAnyDescriptionAccess; +using ::com::sun::star::chart::XComplexDescriptionAccess; +using ::com::sun::star::chart::XChartData; +using ::com::sun::star::chart::XChartDataArray; +using ::com::sun::star::chart::XDateCategories; + +namespace +{ + +uno::Sequence< uno::Sequence< double > > lcl_getNANInsteadDBL_MIN( const uno::Sequence< uno::Sequence< double > >& rData ) +{ + uno::Sequence< uno::Sequence< double > > aRet; + const sal_Int32 nOuterSize = rData.getLength(); + aRet.realloc( nOuterSize ); + auto pRet = aRet.getArray(); + for( sal_Int32 nOuter=0; nOuter::quiet_NaN(); + } + } + return aRet; +} + +uno::Sequence< uno::Sequence< double > > lcl_getDBL_MINInsteadNAN( const uno::Sequence< uno::Sequence< double > >& rData ) +{ + uno::Sequence< uno::Sequence< double > > aRet; + const sal_Int32 nOuterSize = rData.getLength(); + aRet.realloc( nOuterSize ); + auto pRet = aRet.getArray(); + for( sal_Int32 nOuter=0; nOuter& xDataAccess ) = 0; + + virtual bool setsCategories( bool /*bDataInColumns*/ ) + { + return false; + } +}; + +namespace { + +struct lcl_AllOperator : public lcl_Operator +{ + explicit lcl_AllOperator( const Reference< XChartData >& xDataToApply ) + : m_xDataToApply( xDataToApply ) + { + } + + virtual bool setsCategories( bool /*bDataInColumns*/ ) override + { + return true; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( !xDataAccess.is() ) + return; + + Reference< XAnyDescriptionAccess > xNewAny( m_xDataToApply, uno::UNO_QUERY ); + Reference< XComplexDescriptionAccess > xNewComplex( m_xDataToApply, uno::UNO_QUERY ); + if( xNewAny.is() ) + { + xDataAccess->setData( xNewAny->getData() ); + xDataAccess->setComplexRowDescriptions( xNewAny->getComplexRowDescriptions() ); + xDataAccess->setComplexColumnDescriptions( xNewAny->getComplexColumnDescriptions() ); + } + else if( xNewComplex.is() ) + { + xDataAccess->setData( xNewComplex->getData() ); + xDataAccess->setComplexRowDescriptions( xNewComplex->getComplexRowDescriptions() ); + xDataAccess->setComplexColumnDescriptions( xNewComplex->getComplexColumnDescriptions() ); + } + else + { + Reference< XChartDataArray > xNew( m_xDataToApply, uno::UNO_QUERY ); + if( xNew.is() ) + { + xDataAccess->setData( xNew->getData() ); + xDataAccess->setRowDescriptions( xNew->getRowDescriptions() ); + xDataAccess->setColumnDescriptions( xNew->getColumnDescriptions() ); + } + } + } + + Reference< XChartData > m_xDataToApply; +}; + +struct lcl_DataOperator : public lcl_Operator +{ + explicit lcl_DataOperator( const Sequence< Sequence< double > >& rData ) + : m_rData( rData ) + { + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setData( lcl_getNANInsteadDBL_MIN( m_rData ) ); + } + + const Sequence< Sequence< double > >& m_rData; +}; + +struct lcl_RowDescriptionsOperator : public lcl_Operator +{ + lcl_RowDescriptionsOperator( const Sequence< OUString >& rRowDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rRowDescriptions( rRowDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setRowDescriptions( m_rRowDescriptions ); + if( m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< OUString >& m_rRowDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_ComplexRowDescriptionsOperator : public lcl_Operator +{ + lcl_ComplexRowDescriptionsOperator( const Sequence< Sequence< OUString > >& rComplexRowDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rComplexRowDescriptions( rComplexRowDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setComplexRowDescriptions( m_rComplexRowDescriptions ); + if( m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< Sequence< OUString > >& m_rComplexRowDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_AnyRowDescriptionsOperator : public lcl_Operator +{ + explicit lcl_AnyRowDescriptionsOperator( const Sequence< Sequence< uno::Any > >& rAnyRowDescriptions ) + : m_rAnyRowDescriptions( rAnyRowDescriptions ) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setAnyRowDescriptions( m_rAnyRowDescriptions ); + } + + const Sequence< Sequence< uno::Any > >& m_rAnyRowDescriptions; +}; + +struct lcl_ColumnDescriptionsOperator : public lcl_Operator +{ + lcl_ColumnDescriptionsOperator( const Sequence< OUString >& rColumnDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rColumnDescriptions( rColumnDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return !bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setColumnDescriptions( m_rColumnDescriptions ); + if( !m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< OUString >& m_rColumnDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_ComplexColumnDescriptionsOperator : public lcl_Operator +{ + lcl_ComplexColumnDescriptionsOperator( const Sequence< Sequence< OUString > >& rComplexColumnDescriptions + , const rtl::Reference<::chart::ChartModel>& xChartDoc ) + : m_rComplexColumnDescriptions( rComplexColumnDescriptions ) + , m_xChartDoc(xChartDoc) + , m_bDataInColumns(true) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + m_bDataInColumns = bDataInColumns; + return !bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + { + xDataAccess->setComplexColumnDescriptions( m_rComplexColumnDescriptions ); + if( !m_bDataInColumns ) + DiagramHelper::switchToTextCategories( m_xChartDoc ); + } + } + + const Sequence< Sequence< OUString > >& m_rComplexColumnDescriptions; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bDataInColumns; +}; + +struct lcl_AnyColumnDescriptionsOperator : public lcl_Operator +{ + explicit lcl_AnyColumnDescriptionsOperator( const Sequence< Sequence< uno::Any > >& rAnyColumnDescriptions ) + : m_rAnyColumnDescriptions( rAnyColumnDescriptions ) + { + } + + virtual bool setsCategories( bool bDataInColumns ) override + { + return bDataInColumns; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + if( xDataAccess.is() ) + xDataAccess->setAnyColumnDescriptions( m_rAnyColumnDescriptions ); + } + + const Sequence< Sequence< uno::Any > >& m_rAnyColumnDescriptions; +}; + +struct lcl_DateCategoriesOperator : public lcl_Operator +{ + explicit lcl_DateCategoriesOperator( const Sequence< double >& rDates ) + : m_rDates( rDates ) + { + } + + virtual bool setsCategories( bool /*bDataInColumns*/ ) override + { + return true; + } + + virtual void apply( const Reference< XAnyDescriptionAccess >& xDataAccess ) override + { + Reference< XDateCategories > xDateCategories( xDataAccess, uno::UNO_QUERY ); + if( xDateCategories.is() ) + xDateCategories->setDateCategories( m_rDates ); + } + + const Sequence< double >& m_rDates; +}; + +} + +ChartDataWrapper::ChartDataWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ + osl_atomic_increment( &m_refCount ); + initDataAccess(); + osl_atomic_decrement( &m_refCount ); +} + +ChartDataWrapper::ChartDataWrapper( const std::shared_ptr& spChart2ModelContact, + const Reference< XChartData >& xNewData ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ) +{ + osl_atomic_increment( &m_refCount ); + lcl_AllOperator aOperator( xNewData ); + applyData( aOperator ); + osl_atomic_decrement( &m_refCount ); +} + +ChartDataWrapper::~ChartDataWrapper() +{ + // @todo: implement XComponent and call this in dispose(). In the DTOR the + // ref-count is 0, thus creating a stack reference to this calls the DTOR at + // the end of the block recursively +// uno::Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); +// m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +// ____ XChartDataArray (read)____ +Sequence< Sequence< double > > SAL_CALL ChartDataWrapper::getData() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return lcl_getDBL_MINInsteadNAN( m_xDataAccess->getData() ); + return Sequence< Sequence< double > >(); +} +Sequence< OUString > SAL_CALL ChartDataWrapper::getRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getRowDescriptions(); + return Sequence< OUString >(); +} +Sequence< OUString > SAL_CALL ChartDataWrapper::getColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getColumnDescriptions(); + return Sequence< OUString > (); +} + +// ____ XComplexDescriptionAccess (read) ____ +Sequence< Sequence< OUString > > SAL_CALL ChartDataWrapper::getComplexRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getComplexRowDescriptions(); + return Sequence< Sequence< OUString > >(); +} +Sequence< Sequence< OUString > > SAL_CALL ChartDataWrapper::getComplexColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getComplexColumnDescriptions(); + return Sequence< Sequence< OUString > >(); +} + +// ____ XAnyDescriptionAccess (read) ____ +Sequence< Sequence< uno::Any > > SAL_CALL ChartDataWrapper::getAnyRowDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getAnyRowDescriptions(); + return Sequence< Sequence< uno::Any > >(); +} +Sequence< Sequence< uno::Any > > SAL_CALL ChartDataWrapper::getAnyColumnDescriptions() +{ + initDataAccess(); + if( m_xDataAccess.is() ) + return m_xDataAccess->getAnyColumnDescriptions(); + return Sequence< Sequence< uno::Any > >(); +} + +// ____ XDateCategories (read) ____ +Sequence< double > SAL_CALL ChartDataWrapper::getDateCategories() +{ + initDataAccess(); + Reference< XDateCategories > xDateCategories( m_xDataAccess, uno::UNO_QUERY ); + if( xDateCategories.is() ) + return xDateCategories->getDateCategories(); + return Sequence< double >(); +} + +// ____ XChartDataArray (write)____ +void SAL_CALL ChartDataWrapper::setData( const Sequence< Sequence< double > >& rData ) +{ + lcl_DataOperator aOperator( rData ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setRowDescriptions( const Sequence< OUString >& rRowDescriptions ) +{ + lcl_RowDescriptionsOperator aOperator( rRowDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setColumnDescriptions( const Sequence< OUString >& rColumnDescriptions ) +{ + lcl_ColumnDescriptionsOperator aOperator( rColumnDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} + +// ____ XComplexDescriptionAccess (write) ____ +void SAL_CALL ChartDataWrapper::setComplexRowDescriptions( const Sequence< Sequence< OUString > >& rRowDescriptions ) +{ + lcl_ComplexRowDescriptionsOperator aOperator( rRowDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setComplexColumnDescriptions( const Sequence< Sequence< OUString > >& rColumnDescriptions ) +{ + lcl_ComplexColumnDescriptionsOperator aOperator( rColumnDescriptions, m_spChart2ModelContact->getDocumentModel() ); + applyData( aOperator ); +} + +// ____ XAnyDescriptionAccess (write) ____ +void SAL_CALL ChartDataWrapper::setAnyRowDescriptions( const Sequence< Sequence< uno::Any > >& rRowDescriptions ) +{ + lcl_AnyRowDescriptionsOperator aOperator( rRowDescriptions ); + applyData( aOperator ); +} +void SAL_CALL ChartDataWrapper::setAnyColumnDescriptions( const Sequence< Sequence< uno::Any > >& rColumnDescriptions ) +{ + lcl_AnyColumnDescriptionsOperator aOperator( rColumnDescriptions ); + applyData( aOperator ); +} + +// ____ XDateCategories (write) ____ +void SAL_CALL ChartDataWrapper::setDateCategories( const Sequence< double >& rDates ) +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + lcl_DateCategoriesOperator aOperator( rDates ); + applyData( aOperator ); + DiagramHelper::switchToDateCategories( xChartDoc ); +} + +// ____ XChartData (base of XChartDataArray) ____ +void SAL_CALL ChartDataWrapper::addChartDataChangeEventListener( + const uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) +{ + m_aEventListenerContainer.addInterface( aListener ); +} + +void SAL_CALL ChartDataWrapper::removeChartDataChangeEventListener( + const uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +double SAL_CALL ChartDataWrapper::getNotANumber() +{ + return DBL_MIN; +} + +sal_Bool SAL_CALL ChartDataWrapper::isNotANumber( double nNumber ) +{ + return nNumber == DBL_MIN + || std::isnan( nNumber ) + || std::isinf( nNumber ); +} + +// ____ XComponent ____ +void SAL_CALL ChartDataWrapper::dispose() +{ + m_aEventListenerContainer.disposeAndClear( lang::EventObject( static_cast< ::cppu::OWeakObject* >( this ))); + m_xDataAccess=nullptr; +} + +void SAL_CALL ChartDataWrapper::addEventListener( + const uno::Reference< lang::XEventListener > & xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL ChartDataWrapper::removeEventListener( + const uno::Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// ____ XEventListener ____ +void SAL_CALL ChartDataWrapper::disposing( const lang::EventObject& /* Source */ ) +{ +} + +void ChartDataWrapper::fireChartDataChangeEvent( css::chart::ChartDataChangeEvent& aEvent ) +{ + if( ! m_aEventListenerContainer.getLength() ) + return; + + uno::Reference< uno::XInterface > xSrc( static_cast< cppu::OWeakObject* >( this )); + OSL_ASSERT( xSrc.is()); + if( xSrc.is() ) + aEvent.Source = xSrc; + + m_aEventListenerContainer.notifyEach( &css::chart::XChartDataChangeEventListener::chartDataChanged, aEvent ); +} + +void ChartDataWrapper::switchToInternalDataProvider() +{ + //create an internal data provider that is connected to the model + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + xChartDoc->createInternalDataProvider( true /*bCloneExistingData*/ ); + m_xDataAccess.clear(); + initDataAccess(); +} + +void ChartDataWrapper::initDataAccess() +{ + if (m_xDataAccess) + return; + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return; + if( xChartDoc->hasInternalDataProvider() ) + m_xDataAccess.set( xChartDoc->getDataProvider(), uno::UNO_QUERY_THROW ); + else + { + //create a separate "internal data provider" that is not connected to the model + auto xInternal = ChartModelHelper::createInternalDataProvider( + xChartDoc, false /*bConnectToModel*/ ); + m_xDataAccess.set( static_cast(xInternal.get()), uno::UNO_QUERY_THROW ); + } +} + +void ChartDataWrapper::applyData( lcl_Operator& rDataOperator ) +{ + //bool bSetValues, bool bSetRowDescriptions, bool bSetColumnDescriptions + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return; + + // remember some diagram properties to reset later + bool bStacked = false; + bool bPercent = false; + bool bDeep = false; + uno::Reference< css::chart::XChartDocument > xOldDoc( static_cast(xChartDoc.get()), uno::UNO_QUERY ); + OSL_ASSERT( xOldDoc.is()); + uno::Reference< beans::XPropertySet > xDiaProp( xOldDoc->getDiagram(), uno::UNO_QUERY ); + if( xDiaProp.is()) + { + xDiaProp->getPropertyValue("Stacked") >>= bStacked; + xDiaProp->getPropertyValue("Percent") >>= bPercent; + xDiaProp->getPropertyValue("Deep") >>= bDeep; + } + + //detect arguments for the new data source + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + (void)DataSourceHelper::detectRangeSegmentation( + xChartDoc, + aRangeString, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ); + + if( !bHasCategories && rDataOperator.setsCategories( bUseColumns ) ) + bHasCategories = true; + + aRangeString = "all"; + uno::Sequence< beans::PropertyValue > aArguments( DataSourceHelper::createArguments( + aRangeString, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ) ); + + // -- locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + + // create and attach new data source + switchToInternalDataProvider(); + rDataOperator.apply(m_xDataAccess); + uno::Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + OSL_ASSERT( xDataProvider.is() ); + if( !xDataProvider.is() ) + return; + uno::Reference< chart2::data::XDataSource > xSource( xDataProvider->createDataSource( aArguments ) ); + + rtl::Reference< Diagram > xDia( xChartDoc->getFirstChartDiagram() ); + if( xDia.is() ) + xDia->setDiagramData( xSource, aArguments ); + + //correct stacking mode + if( bStacked || bPercent || bDeep ) + { + StackMode eStackMode = StackMode::YStacked; + if( bDeep ) + eStackMode = StackMode::ZStacked; + else if( bPercent ) + eStackMode = StackMode::YStackedPercent; + DiagramHelper::setStackMode( xDia, eStackMode ); + } + + // notify listeners + css::chart::ChartDataChangeEvent aEvent( + static_cast< ::cppu::OWeakObject* >( this ), + css::chart::ChartDataChangeType_ALL, 0, 0, 0, 0 ); + fireChartDataChangeEvent( aEvent ); + // \-- locked controllers +} + +OUString SAL_CALL ChartDataWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.ChartData"; +} + +sal_Bool SAL_CALL ChartDataWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartDataWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDataArray", + "com.sun.star.chart.ChartData" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx new file mode 100644 index 000000000..dcf7c50ad --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDataWrapper.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; +struct lcl_Operator; + +class ChartDataWrapper final : public cppu::BaseMutex, public + ::cppu::WeakImplHelper< + css::chart2::XAnyDescriptionAccess, + css::chart::XDateCategories, + css::lang::XServiceInfo, + css::lang::XEventListener, + css::lang::XComponent > +{ +public: + explicit ChartDataWrapper(const std::shared_ptr& spChart2ModelContact); + ChartDataWrapper(const std::shared_ptr& spChart2ModelContact + , const css::uno::Reference< css::chart::XChartData >& xNewData ); + virtual ~ChartDataWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +private: + // ____ XDateCategories ____ + virtual css::uno::Sequence< double > SAL_CALL getDateCategories() override; + virtual void SAL_CALL setDateCategories( const css::uno::Sequence< double >& rDates ) override; + + // ____ XAnyDescriptionAccess ____ + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyRowDescriptions() override; + virtual void SAL_CALL setAnyRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyColumnDescriptions() override; + virtual void SAL_CALL setAnyColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aColumnDescriptions ) override; + + // ____ XComplexDescriptionAccess (base of XAnyDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexRowDescriptions() override; + virtual void SAL_CALL setComplexRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexColumnDescriptions() override; + virtual void SAL_CALL setComplexColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aColumnDescriptions ) override; + + // ____ XChartDataArray (base of XComplexDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< double > > SAL_CALL getData() override; + virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Sequence< double > >& aData ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getRowDescriptions() override; + virtual void SAL_CALL setRowDescriptions( const css::uno::Sequence< OUString >& aRowDescriptions ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getColumnDescriptions() override; + virtual void SAL_CALL setColumnDescriptions( const css::uno::Sequence< OUString >& aColumnDescriptions ) override; + + // ____ XChartData (base of XChartDataArray) ____ + virtual void SAL_CALL addChartDataChangeEventListener( const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual void SAL_CALL removeChartDataChangeEventListener( const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual double SAL_CALL getNotANumber() override; + virtual sal_Bool SAL_CALL isNotANumber( double nNumber ) override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + void fireChartDataChangeEvent( css::chart::ChartDataChangeEvent& aEvent ); + + void switchToInternalDataProvider(); + void initDataAccess(); + void applyData( lcl_Operator& rDataOperator ); + + css::uno::Reference< css::chart2::XAnyDescriptionAccess > m_xDataAccess; + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper2 m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx b/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx new file mode 100644 index 000000000..d8acdefe7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ChartDocumentWrapper.cxx @@ -0,0 +1,1437 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DataSeriesPointWrapper.hxx" +#include +#include +#include "Chart2ModelContact.hxx" +#include + +#include + +#include +#include +#include +#include +#include + +#include "TitleWrapper.hxx" +#include "ChartDataWrapper.hxx" +#include "DiagramWrapper.hxx" +#include "LegendWrapper.hxx" +#include "AreaWrapper.hxx" +#include "WrappedAddInProperty.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ +enum eServiceType +{ + SERVICE_NAME_AREA_DIAGRAM = 0, + SERVICE_NAME_BAR_DIAGRAM, + SERVICE_NAME_DONUT_DIAGRAM, + SERVICE_NAME_LINE_DIAGRAM, + SERVICE_NAME_NET_DIAGRAM, + SERVICE_NAME_FILLED_NET_DIAGRAM, + SERVICE_NAME_PIE_DIAGRAM, + SERVICE_NAME_STOCK_DIAGRAM, + SERVICE_NAME_XY_DIAGRAM, + SERVICE_NAME_BUBBLE_DIAGRAM, + + SERVICE_NAME_DASH_TABLE, + SERVICE_NAME_GRADIENT_TABLE, + SERVICE_NAME_HATCH_TABLE, + SERVICE_NAME_BITMAP_TABLE, + SERVICE_NAME_TRANSP_GRADIENT_TABLE, + SERVICE_NAME_MARKER_TABLE, + + SERVICE_NAME_NAMESPACE_MAP, + SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER, + SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER +}; + +typedef std::map< OUString, enum eServiceType > tServiceNameMap; + +tServiceNameMap & lcl_getStaticServiceNameMap() +{ + static tServiceNameMap aServiceNameMap { + {"com.sun.star.chart.AreaDiagram", SERVICE_NAME_AREA_DIAGRAM}, + {"com.sun.star.chart.BarDiagram", SERVICE_NAME_BAR_DIAGRAM}, + {"com.sun.star.chart.DonutDiagram", SERVICE_NAME_DONUT_DIAGRAM}, + {"com.sun.star.chart.LineDiagram", SERVICE_NAME_LINE_DIAGRAM}, + {"com.sun.star.chart.NetDiagram", SERVICE_NAME_NET_DIAGRAM}, + {"com.sun.star.chart.FilledNetDiagram", SERVICE_NAME_FILLED_NET_DIAGRAM}, + {"com.sun.star.chart.PieDiagram", SERVICE_NAME_PIE_DIAGRAM}, + {"com.sun.star.chart.StockDiagram", SERVICE_NAME_STOCK_DIAGRAM}, + {"com.sun.star.chart.XYDiagram", SERVICE_NAME_XY_DIAGRAM}, + {"com.sun.star.chart.BubbleDiagram", SERVICE_NAME_BUBBLE_DIAGRAM}, + + {"com.sun.star.drawing.DashTable", SERVICE_NAME_DASH_TABLE}, + {"com.sun.star.drawing.GradientTable", SERVICE_NAME_GRADIENT_TABLE}, + {"com.sun.star.drawing.HatchTable", SERVICE_NAME_HATCH_TABLE}, + {"com.sun.star.drawing.BitmapTable", SERVICE_NAME_BITMAP_TABLE}, + {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_NAME_TRANSP_GRADIENT_TABLE}, + {"com.sun.star.drawing.MarkerTable", SERVICE_NAME_MARKER_TABLE}, + + {"com.sun.star.xml.NamespaceMap", SERVICE_NAME_NAMESPACE_MAP}, + {"com.sun.star.document.ExportGraphicStorageHandler", SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER}, + {"com.sun.star.document.ImportGraphicStorageHandler", SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER} + }; + + return aServiceNameMap; +} + +enum +{ + PROP_DOCUMENT_HAS_MAIN_TITLE, + PROP_DOCUMENT_HAS_SUB_TITLE, + PROP_DOCUMENT_HAS_LEGEND, + PROP_DOCUMENT_LABELS_IN_FIRST_ROW, + PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN, + PROP_DOCUMENT_ADDIN, + PROP_DOCUMENT_BASEDIAGRAM, + PROP_DOCUMENT_ADDITIONAL_SHAPES, + PROP_DOCUMENT_UPDATE_ADDIN, + PROP_DOCUMENT_NULL_DATE, + PROP_DOCUMENT_ENABLE_COMPLEX_CHARTTYPES, + PROP_DOCUMENT_ENABLE_DATATABLE_DIALOG +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "HasMainTitle", + PROP_DOCUMENT_HAS_MAIN_TITLE, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSubTitle", + PROP_DOCUMENT_HAS_SUB_TITLE, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasLegend", + PROP_DOCUMENT_HAS_LEGEND, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + // really needed? + rOutProperties.emplace_back( "DataSourceLabelsInFirstRow", + PROP_DOCUMENT_LABELS_IN_FIRST_ROW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataSourceLabelsInFirstColumn", + PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + //add-in + rOutProperties.emplace_back( "AddIn", + PROP_DOCUMENT_ADDIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "BaseDiagram", + PROP_DOCUMENT_BASEDIAGRAM, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "AdditionalShapes", + PROP_DOCUMENT_ADDITIONAL_SHAPES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::READONLY ); + rOutProperties.emplace_back( "RefreshAddInAllowed", + PROP_DOCUMENT_UPDATE_ADDIN, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::TRANSIENT ); + + // table:null-date // i99104 + rOutProperties.emplace_back( "NullDate", + PROP_DOCUMENT_NULL_DATE, + ::cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "EnableComplexChartTypes", + PROP_DOCUMENT_ENABLE_COMPLEX_CHARTTYPES, + cppu::UnoType::get(), + //#i112666# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "EnableDataTableDialog", + PROP_DOCUMENT_ENABLE_DATATABLE_DIALOG, + cppu::UnoType::get(), + //#i112666# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticChartDocumentWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticChartDocumentWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticChartDocumentWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +namespace { + +//PROP_DOCUMENT_LABELS_IN_FIRST_ROW +class WrappedDataSourceLabelsInFirstRowProperty : public WrappedProperty +{ +public: + explicit WrappedDataSourceLabelsInFirstRowProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataSourceLabelsInFirstRowProperty::WrappedDataSourceLabelsInFirstRowProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("DataSourceLabelsInFirstRow",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataSourceLabelsInFirstRowProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataSourceLabelsInFirstRowProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bLabelsInFirstRow = true; + if( ! (rOuterValue >>= bLabelsInFirstRow) ) + throw lang::IllegalArgumentException("Property DataSourceLabelsInFirstRow requires value of type boolean", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + bool bNewValue = bLabelsInFirstRow; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( !DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + return; + + if( bUseColumns && bNewValue != bFirstCellAsLabel ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns ,bNewValue, bHasCategories ); + } + else if( !bUseColumns && bNewValue != bHasCategories ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns , bFirstCellAsLabel, bNewValue ); + } +} + +Any WrappedDataSourceLabelsInFirstRowProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + bool bLabelsInFirstRow = true; + if( bUseColumns ) + bLabelsInFirstRow = bFirstCellAsLabel; + else + bLabelsInFirstRow = bHasCategories; + + m_aOuterValue <<= bLabelsInFirstRow; + } + return m_aOuterValue; +} + +Any WrappedDataSourceLabelsInFirstRowProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_LABELS_IN_FIRST_COLUMN +class WrappedDataSourceLabelsInFirstColumnProperty : public WrappedProperty +{ +public: + explicit WrappedDataSourceLabelsInFirstColumnProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataSourceLabelsInFirstColumnProperty::WrappedDataSourceLabelsInFirstColumnProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("DataSourceLabelsInFirstColumn",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataSourceLabelsInFirstColumnProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataSourceLabelsInFirstColumnProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bLabelsInFirstRow = true; + if( ! (rOuterValue >>= bLabelsInFirstRow) ) + throw lang::IllegalArgumentException("Property DataSourceLabelsInFirstRow requires value of type boolean", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + bool bNewValue = bLabelsInFirstRow; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( !DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + return; + + if( bUseColumns && bNewValue != bHasCategories ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns, bFirstCellAsLabel, bNewValue ); + } + else if( !bUseColumns && bNewValue != bFirstCellAsLabel ) + { + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bUseColumns , bNewValue, bHasCategories ); + } +} + +Any WrappedDataSourceLabelsInFirstColumnProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + bool bLabelsInFirstColumn = true; + if( bUseColumns ) + bLabelsInFirstColumn = bHasCategories; + else + bLabelsInFirstColumn = bFirstCellAsLabel; + + m_aOuterValue <<= bLabelsInFirstColumn; + } + return m_aOuterValue; +} + +Any WrappedDataSourceLabelsInFirstColumnProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_LEGEND +class WrappedHasLegendProperty : public WrappedProperty +{ +public: + explicit WrappedHasLegendProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasLegendProperty::WrappedHasLegendProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("HasLegend",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasLegendProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasLegend requires value of type boolean", nullptr, 0 ); + + try + { + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( *m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext,bNewValue ); + if(xLegend.is()) + { + bool bOldValue = true; + Any aAOld = xLegend->getPropertyValue("Show"); + aAOld >>= bOldValue; + if( bOldValue != bNewValue ) + xLegend->setPropertyValue("Show", uno::Any( bNewValue )); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasLegendProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + rtl::Reference< Legend > xLegend = + LegendHelper::getLegend( *m_spChart2ModelContact->getDocumentModel() ); + if( xLegend.is()) + aRet = xLegend->getPropertyValue("Show"); + else + aRet <<= false; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasLegendProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_MAIN_TITLE +class WrappedHasMainTitleProperty : public WrappedProperty +{ +public: + explicit WrappedHasMainTitleProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasMainTitleProperty::WrappedHasMainTitleProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("HasMainTitle",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasMainTitleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasMainTitle requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + TitleHelper::createTitle( TitleHelper::MAIN_TITLE, "main-title", m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + else + TitleHelper::removeTitle( TitleHelper::MAIN_TITLE, m_spChart2ModelContact->getDocumentModel() ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasMainTitleProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + aRet <<= TitleHelper::getTitle( TitleHelper::MAIN_TITLE, m_spChart2ModelContact->getDocumentModel() ).is(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasMainTitleProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DOCUMENT_HAS_SUB_TITLE +class WrappedHasSubTitleProperty : public WrappedProperty +{ +public: + explicit WrappedHasSubTitleProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedHasSubTitleProperty::WrappedHasSubTitleProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("HasSubTitle",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedHasSubTitleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException("Property HasSubTitle requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + TitleHelper::createTitle( TitleHelper::SUB_TITLE, "", m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + else + TitleHelper::removeTitle( TitleHelper::SUB_TITLE, m_spChart2ModelContact->getDocumentModel() ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedHasSubTitleProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + try + { + aRet <<= TitleHelper::getTitle( TitleHelper::SUB_TITLE, m_spChart2ModelContact->getDocumentModel() ).is(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aRet; +} + +Any WrappedHasSubTitleProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +ChartDocumentWrapper::ChartDocumentWrapper( + const Reference< uno::XComponentContext > & xContext ) : + m_spChart2ModelContact( std::make_shared( xContext ) ), + m_bUpdateAddIn( true ), + m_bIsDisposed( false ) +{ +} + +ChartDocumentWrapper::~ChartDocumentWrapper() +{ + stopAllComponentListening(); +} + +// ____ XInterface (for new interfaces) ____ +uno::Any SAL_CALL ChartDocumentWrapper::queryInterface( const uno::Type& aType ) +{ + if( m_xDelegator.is()) + // calls queryAggregation if the delegator doesn't know aType + return m_xDelegator->queryInterface( aType ); + else + return queryAggregation( aType ); +} + +// ____ chart::XChartDocument (old API wrapper) ____ +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getTitle() +{ + if( !m_xTitle.is() ) + { + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xTitle = new TitleWrapper( TitleHelper::MAIN_TITLE, m_spChart2ModelContact ); + } + return m_xTitle; +} + +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getSubTitle() +{ + if( !m_xSubTitle.is() ) + { + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xSubTitle = new TitleWrapper( TitleHelper::SUB_TITLE, m_spChart2ModelContact ); + } + return m_xSubTitle; +} + +Reference< drawing::XShape > SAL_CALL ChartDocumentWrapper::getLegend() +{ + if( ! m_xLegend.is()) + { + m_xLegend = new LegendWrapper( m_spChart2ModelContact ); + } + + return m_xLegend; +} + +Reference< beans::XPropertySet > SAL_CALL ChartDocumentWrapper::getArea() +{ + if( ! m_xArea.is()) + { + m_xArea.set( new AreaWrapper( m_spChart2ModelContact ) ); + } + + return m_xArea; +} + +Reference< XDiagram > SAL_CALL ChartDocumentWrapper::getDiagram() +{ + if( !m_xDiagram.is() ) + { + try + { + m_xDiagram = new DiagramWrapper( m_spChart2ModelContact ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return m_xDiagram; +} + +void SAL_CALL ChartDocumentWrapper::setDiagram( const Reference< XDiagram >& xDiagram ) +{ + uno::Reference< util::XRefreshable > xAddIn( xDiagram, uno::UNO_QUERY ); + if( xAddIn.is() ) + { + setAddIn( xAddIn ); + } + else if( xDiagram.is() && xDiagram != m_xDiagram ) + { + // set new wrapped diagram at new chart. This requires the old + // diagram given as parameter to implement the new interface. If + // this is not possible throw an exception + Reference< chart2::XDiagramProvider > xNewDiaProvider( xDiagram, uno::UNO_QUERY_THROW ); + Reference< chart2::XDiagram > xNewDia( xNewDiaProvider->getDiagram()); + + try + { + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xChartDoc.is() ) + { + // set the new diagram + xChartDoc->setFirstDiagram( xNewDia ); + m_xDiagram = xDiagram; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +Reference< XChartData > SAL_CALL ChartDocumentWrapper::getData() +{ + if( !m_xChartData.is() ) + { + m_xChartData.set( new ChartDataWrapper( m_spChart2ModelContact ) ); + } + //@todo: check hasInternalDataProvider also in else? + + return m_xChartData; +} + +void SAL_CALL ChartDocumentWrapper::attachData( const Reference< XChartData >& xNewData ) +{ + if( !xNewData.is() ) + return; + + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_xChartData.set( new ChartDataWrapper( m_spChart2ModelContact, xNewData ) ); +} + +// ____ XModel ____ +sal_Bool SAL_CALL ChartDocumentWrapper::attachResource( + const OUString& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->attachResource( URL, Arguments ); + return false; +} + +OUString SAL_CALL ChartDocumentWrapper::getURL() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getURL(); + return OUString(); +} + +Sequence< beans::PropertyValue > SAL_CALL ChartDocumentWrapper::getArgs() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getArgs(); + return Sequence< beans::PropertyValue >(); +} + +void SAL_CALL ChartDocumentWrapper::connectController( const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->connectController( Controller ); +} + +void SAL_CALL ChartDocumentWrapper::disconnectController( + const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->disconnectController( Controller ); +} + +void SAL_CALL ChartDocumentWrapper::lockControllers() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->lockControllers(); +} + +void SAL_CALL ChartDocumentWrapper::unlockControllers() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->unlockControllers(); +} + +sal_Bool SAL_CALL ChartDocumentWrapper::hasControllersLocked() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->hasControllersLocked(); + return false; +} + +Reference< frame::XController > SAL_CALL ChartDocumentWrapper::getCurrentController() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getCurrentController(); + return nullptr; +} + +void SAL_CALL ChartDocumentWrapper::setCurrentController( + const Reference< frame::XController >& Controller ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->setCurrentController( Controller ); +} + +Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::getCurrentSelection() +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + return xModel->getCurrentSelection(); + return nullptr; +} + +// ____ XComponent ____ +void SAL_CALL ChartDocumentWrapper::dispose() +{ + if( m_bIsDisposed ) + throw lang::DisposedException("ChartDocumentWrapper is disposed", + static_cast< ::cppu::OWeakObject* >( this )); + + m_bIsDisposed = true; + + try + { + Reference< lang::XComponent > xFormerDelegator( m_xDelegator, uno::UNO_QUERY ); + DisposeHelper::DisposeAndClear( m_xTitle ); + DisposeHelper::DisposeAndClear( m_xSubTitle ); + DisposeHelper::DisposeAndClear( m_xLegend ); + DisposeHelper::DisposeAndClear( m_xChartData ); + DisposeHelper::DisposeAndClear( m_xDiagram ); + DisposeHelper::DisposeAndClear( m_xArea ); + m_xChartView.set( nullptr ); + m_xShapeFactory.set( nullptr ); + m_xDelegator.set( nullptr ); + + clearWrappedPropertySet(); + m_spChart2ModelContact->clear(); + impl_resetAddIn(); + + stopAllComponentListening(); + + try + { + if( xFormerDelegator.is()) + xFormerDelegator->dispose(); + } + catch (const lang::DisposedException&) + { + // this is ok, don't panic + } + } + catch (const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartDocumentWrapper::impl_resetAddIn() +{ + Reference< util::XRefreshable > xAddIn( m_xAddIn ); + m_xAddIn.set( nullptr ); + + if( !xAddIn.is() ) + return; + + try + { + //make sure that the add-in does not hold a references to us anymore: + Reference< lang::XComponent > xComp( xAddIn, uno::UNO_QUERY ); + if( xComp.is()) + xComp->dispose(); + else + { + uno::Reference< lang::XInitialization > xInit( xAddIn, uno::UNO_QUERY ); + if( xInit.is() ) + { + uno::Any aParam; + uno::Reference< css::chart::XChartDocument > xDoc; + aParam <<= xDoc; + uno::Sequence< uno::Any > aSeq( &aParam, 1 ); + xInit->initialize( aSeq ); + } + } + } + catch (const uno::RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartDocumentWrapper::setBaseDiagram( const OUString& rBaseDiagram ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + m_aBaseDiagram = rBaseDiagram; + + uno::Reference< XDiagram > xDiagram( ChartDocumentWrapper::createInstance( rBaseDiagram ), uno::UNO_QUERY ); + if( xDiagram.is() ) + setDiagram( xDiagram ); +} + +void ChartDocumentWrapper::setAddIn( const Reference< util::XRefreshable >& xAddIn ) +{ + if( m_xAddIn == xAddIn ) + return; + + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + impl_resetAddIn(); + m_xAddIn = xAddIn; + // initialize AddIn with this as chart document + uno::Reference< lang::XInitialization > xInit( m_xAddIn, uno::UNO_QUERY ); + if( xInit.is() ) + { + uno::Any aParam; + uno::Reference< XChartDocument > xDoc(this); + aParam <<= xDoc; + uno::Sequence< uno::Any > aSeq( &aParam, 1 ); + xInit->initialize( aSeq ); + } +} + +void ChartDocumentWrapper::setUpdateAddIn( bool bUpdateAddIn ) +{ + m_bUpdateAddIn = bUpdateAddIn; +} + +Reference< drawing::XShapes > ChartDocumentWrapper::getAdditionalShapes() const +{ + // get additional non-chart shapes for XML export + uno::Reference< drawing::XShapes > xFoundShapes; + rtl::Reference xDrawPage( impl_getDrawPage() ); + + if( !xDrawPage.is() ) + return xFoundShapes; + + uno::Reference xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + + // iterate 'flat' over all top-level objects + // and determine all that are no chart objects + std::vector< uno::Reference< drawing::XShape > > aShapeVector; + sal_Int32 nSubCount = xDrawPage->getCount(); + uno::Reference< drawing::XShape > xShape; + for( sal_Int32 nS = 0; nS < nSubCount; nS++ ) + { + if( xDrawPage->getByIndex( nS ) >>= xShape ) + { + if( xShape.is() && xChartRoot!=xShape ) + aShapeVector.push_back( xShape ); + } + } + + if( !aShapeVector.empty() ) + { + // create a shape collection + xFoundShapes = drawing::ShapeCollection::create( + comphelper::getProcessComponentContext()); + + OSL_ENSURE( xFoundShapes.is(), "Couldn't create a shape collection!" ); + if( xFoundShapes.is()) + { + for (auto const& shape : aShapeVector) + xFoundShapes->add(shape); + } + } + + return xFoundShapes; +} + +void SAL_CALL ChartDocumentWrapper::addEventListener( const Reference< lang::XEventListener >& xListener ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->addEventListener( xListener ); +} + +void SAL_CALL ChartDocumentWrapper::removeEventListener( const Reference< lang::XEventListener >& aListener ) +{ + rtl::Reference< ChartModel > xModel( m_spChart2ModelContact->getDocumentModel() ); + if( xModel.is() ) + xModel->removeEventListener( aListener ); +} + +// ____ XDrawPageSupplier ____ +uno::Reference< drawing::XDrawPage > SAL_CALL ChartDocumentWrapper::getDrawPage() +{ + return impl_getDrawPage(); +} + +rtl::Reference ChartDocumentWrapper::impl_getDrawPage() const +{ + return m_spChart2ModelContact->getDrawPage(); +} + +namespace { + +uno::Reference< lang::XMultiServiceFactory > getShapeFactory(const uno::Reference& xChartView) +{ + auto pProvider = comphelper::getFromUnoTunnel(xChartView); + if( pProvider ) + return pProvider->getDrawModelWrapper()->getShapeFactory(); + + return uno::Reference< lang::XMultiServiceFactory >(); +} + +} + +// ____ XMultiServiceFactory ____ +uno::Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::createInstance( + const OUString& aServiceSpecifier ) +{ + uno::Reference< uno::XInterface > xResult; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( !xChartDoc.is() ) + return xResult; + + bool bServiceFound = false; + tServiceNameMap & rMap = lcl_getStaticServiceNameMap(); + + tServiceNameMap::const_iterator aIt( rMap.find( aServiceSpecifier )); + if( aIt != rMap.end()) + { + bool bCreateDiagram = false; + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = + xChartDoc->getTypeManager(); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + + switch( (*aIt).second ) + { + case SERVICE_NAME_AREA_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Area"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_BAR_DIAGRAM: + if( xChartTypeManager.is()) + { + // this is for bar and column (the latter is the default if + // no "Vertical=false" property was set) + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Column"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_DONUT_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Donut"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_LINE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Line"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_NET_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Net"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_FILLED_NET_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.FilledNet"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_PIE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Pie"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_STOCK_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.StockLowHighClose"); + bCreateDiagram = true; + } + break; + case SERVICE_NAME_XY_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.ScatterLineSymbol"); + bCreateDiagram = true; + } + break; + + case SERVICE_NAME_BUBBLE_DIAGRAM: + if( xChartTypeManager.is()) + { + xTemplate = + xChartTypeManager->createTemplate("com.sun.star.chart2.template.Bubble"); + bCreateDiagram = true; + } + break; + + case SERVICE_NAME_DASH_TABLE: + case SERVICE_NAME_GRADIENT_TABLE: + case SERVICE_NAME_HATCH_TABLE: + case SERVICE_NAME_BITMAP_TABLE: + case SERVICE_NAME_TRANSP_GRADIENT_TABLE: + case SERVICE_NAME_MARKER_TABLE: + xResult.set( xChartDoc->createInstance( aIt->first ), uno::UNO_QUERY ); + break; + + case SERVICE_NAME_NAMESPACE_MAP: + break; + case SERVICE_NAME_EXPORT_GRAPHIC_STORAGE_RESOLVER: + break; + case SERVICE_NAME_IMPORT_GRAPHIC_STORAGE_RESOLVER: + break; + } + + if( bCreateDiagram && xTemplate.is() ) + { + try + { + uno::Reference< chart2::XDiagram > xDia( xChartDoc->getFirstDiagram()); + if( xDia.is()) + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDoc ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + rtl::Reference< ::chart::ChartTypeManager > xTemplateManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateWithService( + DiagramHelper::getTemplateForDiagram( xDiagram, xTemplateManager )); + if( aTemplateWithService.xChartTypeTemplate.is()) + aTemplateWithService.xChartTypeTemplate->resetStyles2( xDiagram );//#i109371# + xTemplate->changeDiagram( xDiagram ); + if( AllSettings::GetMathLayoutRTL() ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + else + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + xDia.set( xTemplate->createDiagramByDataSource( + uno::Reference< chart2::data::XDataSource >(), + uno::Sequence< beans::PropertyValue >())); + xChartDoc->setFirstDiagram( xDia ); + } + + xResult = static_cast< ::cppu::OWeakObject* >( new DiagramWrapper( m_spChart2ModelContact )); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + bServiceFound = true; + } + else if( aServiceSpecifier == "com.sun.star.comp.chart2.DataSeriesWrapper" ) + { + Reference< beans::XPropertySet > xDataSeries( new DataSeriesPointWrapper( m_spChart2ModelContact ) ); + xResult.set( xDataSeries ); + bServiceFound = true; + } + else if( aServiceSpecifier == CHART_VIEW_SERVICE_NAME ) + { + if( !m_xChartView.is() ) + { + rtl::Reference<::chart::ChartModel> pChartModel = new ::chart::ChartModel(m_spChart2ModelContact->m_xContext); + rtl::Reference xChartView = new ::chart::ChartView(m_spChart2ModelContact->m_xContext, *pChartModel); + + try + { + m_xChartView = xChartView; + + Sequence< Any > aArguments{ Any(Reference(this)), + Any(true) }; // bRefreshAddIn + xChartView->initialize(aArguments); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + xResult.set( static_cast(m_xChartView.get()) ); + bServiceFound = true; + } + else + { + // try to create a shape + try + { + if( !m_xShapeFactory.is() && m_xChartView.is() ) + { + m_xShapeFactory = getShapeFactory( static_cast(m_xChartView.get()) ); + } + else + { + rtl::Reference pModel = m_spChart2ModelContact->getDocumentModel(); + if(pModel) + { + m_xChartView = pModel->getChartView(); + m_xShapeFactory = getShapeFactory( static_cast(m_xChartView.get()) ); + } + } + + if( m_xShapeFactory.is() ) + { + xResult = m_xShapeFactory->createInstance( aServiceSpecifier ); + bServiceFound = true; + } + } + catch (const uno::Exception&) + { + // couldn't create shape + } + } + + // finally, try to create an addin + if( !bServiceFound ) + { + try + { + Reference< lang::XMultiServiceFactory > xFact( + m_spChart2ModelContact->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW ); + uno::Reference< util::XRefreshable > xAddIn( + xFact->createInstance( aServiceSpecifier ), uno::UNO_QUERY ); + if( xAddIn.is() ) + { + xResult = xAddIn; + } + } + catch (const uno::Exception&) + { + // couldn't create service + } + } + + return xResult; +} + +uno::Reference< uno::XInterface > SAL_CALL ChartDocumentWrapper::createInstanceWithArguments( + const OUString& ServiceSpecifier, + const uno::Sequence< uno::Any >& Arguments ) +{ + OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" ); + + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > SAL_CALL ChartDocumentWrapper::getAvailableServiceNames() +{ + return comphelper::mapKeysToSequence( lcl_getStaticServiceNameMap() ); +} + +// ____ XAggregation ____ +void SAL_CALL ChartDocumentWrapper::setDelegator( + const uno::Reference< uno::XInterface >& rDelegator ) +{ + if( m_bIsDisposed ) + { + if( rDelegator.is() ) + throw lang::DisposedException("ChartDocumentWrapper is disposed", + static_cast< ::cppu::OWeakObject* >( this )); + return; + } + + if( rDelegator.is()) + { + m_xDelegator = rDelegator; + ChartModel* pChartModel = dynamic_cast(rDelegator.get()); + assert(pChartModel); + m_spChart2ModelContact->setDocumentModel( pChartModel ); + } + else + { + // this is a sort of dispose() from the new model,so release resources here + try + { + dispose(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +uno::Any SAL_CALL ChartDocumentWrapper::queryAggregation( const uno::Type& rType ) +{ + return ChartDocumentWrapper_Base::queryInterface( rType ); +} + +// ____ ::utl::OEventListenerAdapter ____ +void ChartDocumentWrapper::_disposing( const lang::EventObject& rSource ) +{ + if( rSource.Source == m_xTitle ) + m_xTitle.set( nullptr ); + else if( rSource.Source == m_xSubTitle ) + m_xSubTitle.set( nullptr ); + else if( rSource.Source == m_xLegend ) + m_xLegend.set( nullptr ); + else if( rSource.Source == m_xChartData ) + m_xChartData.set( nullptr ); + else if( rSource.Source == m_xDiagram ) + m_xDiagram.set( nullptr ); + else if( rSource.Source == m_xArea ) + m_xArea.set( nullptr ); + else if( rSource.Source == m_xAddIn ) + m_xAddIn.set( nullptr ); + else if( rSource.Source == static_cast(m_xChartView.get()) ) + m_xChartView.set( nullptr ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > ChartDocumentWrapper::getInnerPropertySet() +{ + return nullptr; +} +const Sequence< beans::Property >& ChartDocumentWrapper::getPropertySequence() +{ + return *StaticChartDocumentWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > ChartDocumentWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + aWrappedProperties.emplace_back( new WrappedDataSourceLabelsInFirstRowProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedDataSourceLabelsInFirstColumnProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasLegendProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasMainTitleProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedHasSubTitleProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAddInProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedBaseDiagramProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedAdditionalShapesProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedRefreshAddInAllowedProperty( *this ) ); + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("NullDate",Any() ) ); // i99104 + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("EnableComplexChartTypes", uno::Any(true) ) ); + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("EnableDataTableDialog", uno::Any(true) ) ); + + return aWrappedProperties; +} + +OUString SAL_CALL ChartDocumentWrapper::getImplementationName() +{ + return CHART_CHARTAPIWRAPPER_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartDocumentWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartDocumentWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDocument", + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartDocumentWrapper_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::wrapper::ChartDocumentWrapper(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx new file mode 100644 index 000000000..40e4df69c --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.cxx @@ -0,0 +1,899 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DataSeriesPointWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "WrappedCharacterHeightProperty.hxx" +#include +#include +#include "WrappedStatisticProperties.hxx" +#include "WrappedSymbolProperties.hxx" +#include "WrappedDataCaptionProperties.hxx" +#include "WrappedSeriesAreaOrLineProperty.hxx" +#include "WrappedScaleTextProperties.hxx" +#include "WrappedNumberFormatProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::chart::wrapper; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Any; + +namespace +{ + +enum +{ + //data point properties + PROP_SERIES_DATAPOINT_SOLIDTYPE, + PROP_SERIES_DATAPOINT_SEGMENT_OFFSET, + PROP_SERIES_DATAPOINT_PERCENT_DIAGONAL, + PROP_SERIES_DATAPOINT_LABEL_SEPARATOR, + PROP_SERIES_NUMBERFORMAT, + PROP_SERIES_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_SERIES_PERCENTAGE_NUMBERFORMAT, + PROP_SERIES_DATAPOINT_TEXT_WORD_WRAP, + PROP_SERIES_DATAPOINT_LABEL_PLACEMENT, + //other series properties + PROP_SERIES_ATTACHED_AXIS, + PROP_SERIES_SHOW_CUSTOM_LEADERLINES, + PROP_SERIES_DATAPOINT_TEXT_ROTATION, + PROP_SERIES_DATAPOINT_LABEL_BORDER_STYLE, + PROP_SERIES_DATAPOINT_LABEL_BORDER_WIDTH, + PROP_SERIES_DATAPOINT_LABEL_BORDER_COLOR, + PROP_SERIES_DATAPOINT_LABEL_BORDER_TRANS, + PROP_SERIES_DATAPOINT_LABEL_FILL_STYLE, + PROP_SERIES_DATAPOINT_LABEL_FILL_COLOR, + PROP_SERIES_DATAPOINT_LABEL_FILL_BACKGROUND, + PROP_SERIES_DATAPOINT_LABEL_FILL_HATCH_NAME +}; + +void lcl_AddPropertiesToVector_PointProperties( + std::vector< Property > & rOutProperties ) +{ + //service chart::Chart3DBarProperties + rOutProperties.emplace_back( "SolidType", + PROP_SERIES_DATAPOINT_SOLIDTYPE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SegmentOffset", + PROP_SERIES_DATAPOINT_SEGMENT_OFFSET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "D3DPercentDiagonal", + PROP_SERIES_DATAPOINT_PERCENT_DIAGONAL, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelSeparator", + PROP_SERIES_DATAPOINT_LABEL_SEPARATOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_SERIES_NUMBERFORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_SERIES_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "PercentageNumberFormat", + PROP_SERIES_PERCENTAGE_NUMBERFORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextWordWrap", + PROP_SERIES_DATAPOINT_TEXT_WORD_WRAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelPlacement", + PROP_SERIES_DATAPOINT_LABEL_PLACEMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_SERIES_DATAPOINT_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_STYLE, + PROP_SERIES_DATAPOINT_LABEL_BORDER_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_STYLE, + PROP_SERIES_DATAPOINT_LABEL_FILL_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_COLOR, + PROP_SERIES_DATAPOINT_LABEL_FILL_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_BACKGROUND, + PROP_SERIES_DATAPOINT_LABEL_FILL_BACKGROUND, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_HATCH_NAME, + PROP_SERIES_DATAPOINT_LABEL_FILL_HATCH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_WIDTH, + PROP_SERIES_DATAPOINT_LABEL_BORDER_WIDTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_COLOR, + PROP_SERIES_DATAPOINT_LABEL_BORDER_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_TRANS, + PROP_SERIES_DATAPOINT_LABEL_BORDER_TRANS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void lcl_AddPropertiesToVector_SeriesOnly( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Axis", + PROP_SERIES_ATTACHED_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ShowCustomLeaderLines", + PROP_SERIES_SHOW_CUSTOM_LEADERLINES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +uno::Sequence< Property > lcl_GetPropertySequence( DataSeriesPointWrapper::eType _eType ) +{ + std::vector< css::beans::Property > aProperties; + + lcl_AddPropertiesToVector_PointProperties( aProperties ); + if( _eType == DataSeriesPointWrapper::DATA_SERIES ) + { + lcl_AddPropertiesToVector_SeriesOnly( aProperties ); + WrappedStatisticProperties::addProperties( aProperties ); + } + WrappedSymbolProperties::addProperties( aProperties ); //for series and points + WrappedDataCaptionProperties::addProperties( aProperties ); //for series and points + + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); +} + +struct StaticSeriesWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence( DataSeriesPointWrapper::DATA_SERIES ) ); + return &aPropSeq; + } +}; + +struct StaticSeriesWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticSeriesWrapperPropertyArray_Initializer > +{ +}; + +struct StaticPointWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence( DataSeriesPointWrapper::DATA_POINT ) ); + return &aPropSeq; + } +}; + +struct StaticPointWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticPointWrapperPropertyArray_Initializer > +{ +}; + +//PROP_SERIES_ATTACHED_AXIS +class WrappedAttachedAxisProperty : public ::chart::WrappedProperty +{ +public: + explicit WrappedAttachedAxisProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +WrappedAttachedAxisProperty::WrappedAttachedAxisProperty( + const std::shared_ptr& spChart2ModelContact ) + : WrappedProperty("Axis",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +Any WrappedAttachedAxisProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= css::chart::ChartAxisAssign::PRIMARY_Y; + return aRet; +} + +Any WrappedAttachedAxisProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + + uno::Reference< chart2::XDataSeries > xDataSeries( xInnerPropertySet, uno::UNO_QUERY ); + bool bAttachedToMainAxis = ::chart::DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + if( bAttachedToMainAxis ) + aRet <<= css::chart::ChartAxisAssign::PRIMARY_Y; + else + aRet <<= css::chart::ChartAxisAssign::SECONDARY_Y; + return aRet; +} + +void WrappedAttachedAxisProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + uno::Reference< chart2::XDataSeries > xDataSeries( xInnerPropertySet, uno::UNO_QUERY ); + + sal_Int32 nChartAxisAssign = css::chart::ChartAxisAssign::PRIMARY_Y; + if( ! (rOuterValue >>= nChartAxisAssign) ) + throw lang::IllegalArgumentException("Property Axis requires value of type sal_Int32", nullptr, 0 ); + + bool bNewAttachedToMainAxis = nChartAxisAssign == css::chart::ChartAxisAssign::PRIMARY_Y; + bool bOldAttachedToMainAxis = ::chart::DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + + if( bNewAttachedToMainAxis != bOldAttachedToMainAxis) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + ::chart::DiagramHelper::attachSeriesToAxis( bNewAttachedToMainAxis, xDataSeries, xDiagram, m_spChart2ModelContact->m_xContext, false ); + } +} + +class WrappedSegmentOffsetProperty : public ::chart::WrappedProperty +{ +public: + WrappedSegmentOffsetProperty(); + +protected: + virtual Any convertInnerToOuterValue( const Any& rInnerValue ) const override; + virtual Any convertOuterToInnerValue( const Any& rOuterValue ) const override; +}; + +WrappedSegmentOffsetProperty::WrappedSegmentOffsetProperty() : + WrappedProperty("SegmentOffset","Offset") +{} + +Any WrappedSegmentOffsetProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + // convert new double offset to former integer segment-offset + double fOffset = 0; + Any aResult( rInnerValue ); + + if( rInnerValue >>= fOffset ) + aResult <<= static_cast< sal_Int32 >( ::rtl::math::round( fOffset * 100.0 )); + + return aResult; +} + +Any WrappedSegmentOffsetProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + // convert former integer segment-offset to new double offset + sal_Int32 nOffset = 0; + Any aResult( rOuterValue ); + + if( rOuterValue >>= nOffset ) + aResult <<= static_cast< double >( nOffset ) / 100.0; + + return aResult; +} + +class WrappedLineColorProperty : public WrappedSeriesAreaOrLineProperty +{ +public: + explicit WrappedLineColorProperty( DataSeriesPointWrapper* pDataSeriesPointWrapper ); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; + mutable Any m_aDefaultValue; +}; + +WrappedLineColorProperty::WrappedLineColorProperty( + DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedSeriesAreaOrLineProperty("LineColor","BorderColor","Color", pDataSeriesPointWrapper ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) + , m_aDefaultValue(uno::Any(sal_Int32( 0x0099ccff ))) // blue 8 +{ +} + +void WrappedLineColorProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyValue( rOuterValue, xInnerPropertySet ); +} + +void WrappedLineColorProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyToDefault( xInnerPropertyState ); +} + +Any WrappedLineColorProperty::getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( m_pDataSeriesPointWrapper && !m_pDataSeriesPointWrapper->isSupportingAreaProperties() ) + return m_aDefaultValue; + else + return WrappedSeriesAreaOrLineProperty::getPropertyDefault( xInnerPropertyState ); +} + +class WrappedLineStyleProperty : public WrappedSeriesAreaOrLineProperty +{ +public: + explicit WrappedLineStyleProperty( DataSeriesPointWrapper* pDataSeriesPointWrapper ); + + virtual void setPropertyValue( const Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; +}; + +WrappedLineStyleProperty::WrappedLineStyleProperty( + DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedSeriesAreaOrLineProperty("LineStyle","BorderStyle", "LineStyle", pDataSeriesPointWrapper ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) +{ +} + +void WrappedLineStyleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aNewValue(rOuterValue); + if( m_pDataSeriesPointWrapper && m_pDataSeriesPointWrapper->isLinesForbidden() ) + { + aNewValue <<= drawing::LineStyle_NONE; + } + WrappedSeriesAreaOrLineProperty::setPropertyValue( aNewValue, xInnerPropertySet ); +} + +void WrappedLineStyleProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( !m_pDataSeriesPointWrapper || !m_pDataSeriesPointWrapper->isLinesForbidden() ) + WrappedSeriesAreaOrLineProperty::setPropertyToDefault( xInnerPropertyState ); +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +DataSeriesPointWrapper::DataSeriesPointWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_eType( DATA_SERIES ) + , m_nSeriesIndexInNewAPI( -1 ) + , m_nPointIndex( -1 ) + , m_bLinesAllowed(true) +{ + //need initialize call afterwards +} + +void SAL_CALL DataSeriesPointWrapper::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + OSL_PRECOND(aArguments.hasElements(),"need at least 1 argument to initialize the DataSeriesPointWrapper: series reference + optional datapoint index"); + + m_nSeriesIndexInNewAPI = -1;//ignored in this case + m_nPointIndex = -1; + if( aArguments.hasElements() ) + { + uno::Reference xTmp; + aArguments[0] >>= xTmp; + auto p = dynamic_cast(xTmp.get()); + assert(p); + m_xDataSeries = p; + if( aArguments.getLength() >= 2 ) + aArguments[1] >>= m_nPointIndex; + } + + if( !m_xDataSeries.is() ) + throw uno::Exception( + "DataSeries index invalid", static_cast< ::cppu::OWeakObject * >( this )); + + //todo: check upper border of point index + + if( m_nPointIndex >= 0 ) + m_eType = DATA_POINT; + else + m_eType = DATA_SERIES; +} + +DataSeriesPointWrapper::DataSeriesPointWrapper(eType _eType, + sal_Int32 nSeriesIndexInNewAPI , + sal_Int32 nPointIndex, //ignored for series + const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_eType( _eType ) + , m_nSeriesIndexInNewAPI( nSeriesIndexInNewAPI ) + , m_nPointIndex( (_eType == DATA_POINT) ? nPointIndex : -1 ) + , m_bLinesAllowed( false ) +{ +} + +DataSeriesPointWrapper::~DataSeriesPointWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL DataSeriesPointWrapper::dispose() +{ + uno::Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + m_xDataSeries.clear(); + clearWrappedPropertySet(); +} + +void SAL_CALL DataSeriesPointWrapper::addEventListener( + const uno::Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL DataSeriesPointWrapper::removeEventListener( + const uno::Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// ____ XEventListener ____ +void SAL_CALL DataSeriesPointWrapper::disposing( const lang::EventObject& /*Source*/ ) +{ +} + +bool DataSeriesPointWrapper::isSupportingAreaProperties() +{ + rtl::Reference< DataSeries > xSeries( getDataSeries() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< ::chart::ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + return ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ); +} + +rtl::Reference< DataSeries > DataSeriesPointWrapper::getDataSeries() +{ + rtl::Reference< DataSeries > xSeries = m_xDataSeries; + if( !xSeries.is() ) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + if( m_nSeriesIndexInNewAPI >= 0 && o3tl::make_unsigned(m_nSeriesIndexInNewAPI) < aSeriesList.size() ) + xSeries = aSeriesList[m_nSeriesIndexInNewAPI]; + } + + return xSeries; +} + +Reference< beans::XPropertySet > DataSeriesPointWrapper::getDataPointProperties() +{ + Reference< beans::XPropertySet > xPointProp; + + rtl::Reference< DataSeries > xSeries( getDataSeries() ); + + // may throw an IllegalArgumentException + if( xSeries.is() ) + xPointProp = xSeries->getDataPointByIndex( m_nPointIndex ); + + return xPointProp; +} + +//ReferenceSizePropertyProvider +void DataSeriesPointWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + { + if( xProp->getPropertyValue("ReferencePageSize").hasValue() ) + xProp->setPropertyValue("ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any DataSeriesPointWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + aRet = xProp->getPropertyValue("ReferencePageSize"); + return aRet; +} +awt::Size DataSeriesPointWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +// WrappedPropertySet + +//XPropertyState +beans::PropertyState SAL_CALL DataSeriesPointWrapper::getPropertyState( const OUString& rPropertyName ) +{ + beans::PropertyState aState( beans::PropertyState_DIRECT_VALUE ); + try + { + if (rPropertyName == "SymbolBitmap" || rPropertyName == "SymbolBitmapURL") + { + uno::Any aAny = WrappedPropertySet::getPropertyValue("SymbolType"); + sal_Int32 nVal = css::chart::ChartSymbolType::NONE; + if (aAny >>= nVal) + { + if (nVal != css::chart::ChartSymbolType::BITMAPURL) + return beans::PropertyState::PropertyState_DEFAULT_VALUE; + } + } + + if( m_eType == DATA_SERIES ) + aState = WrappedPropertySet::getPropertyState( rPropertyName ); + else + { + if( rPropertyName == "FillColor") + { + rtl::Reference< DataSeries > xSeriesProp = getDataSeries(); + bool bVaryColorsByPoint = false; + if( xSeriesProp.is() && (xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) + && bVaryColorsByPoint ) + return beans::PropertyState_DIRECT_VALUE; + } + else if( rPropertyName == "Lines" + || rPropertyName == "SymbolType" + || rPropertyName == "SymbolSize" ) + return WrappedPropertySet::getPropertyState( rPropertyName ); + + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + if( aDefault==aValue ) + aState = beans::PropertyState_DEFAULT_VALUE; + } + } + catch( const beans::UnknownPropertyException& ) + { + throw; + } + catch( const uno::RuntimeException& ) + { + throw; + } + catch( const lang::WrappedTargetException& e ) + { + css::uno::Any a(e.TargetException); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference(), a); + } + catch( const uno::Exception& e ) + { + css::uno::Any a(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + "wrapped Exception " + e.Message, + css::uno::Reference(), a); + } + return aState; +} + +void SAL_CALL DataSeriesPointWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + if( m_eType == DATA_SERIES ) + WrappedPropertySet::setPropertyToDefault( rPropertyName ); + else + { + //for data points the default is given by the series + setPropertyValue( rPropertyName, getPropertyDefault( rPropertyName ) ); + } +} +Any SAL_CALL DataSeriesPointWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + Any aRet; + try + { + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( nHandle > 0 ) + { + //always take the series current value as default for points + rtl::Reference< DataSeries > xInnerPropertySet = getDataSeries(); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyValue(xInnerPropertySet); + else + aRet = xInnerPropertySet->getPropertyValue( rPropertyName ); + } + } + } + catch( const beans::UnknownPropertyException& ) + { + aRet = WrappedPropertySet::getPropertyDefault( rPropertyName ); + } + return aRet; +} + +Reference< beans::XPropertySet > DataSeriesPointWrapper::getInnerPropertySet() +{ + if( m_eType == DATA_SERIES ) + return getDataSeries(); + return getDataPointProperties(); +} + +const Sequence< beans::Property >& DataSeriesPointWrapper::getPropertySequence() +{ + if( m_eType == DATA_SERIES ) + return *StaticSeriesWrapperPropertyArray::get(); + else + return *StaticPointWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > DataSeriesPointWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + + if( m_eType == DATA_SERIES ) + { + WrappedStatisticProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + aWrappedProperties.emplace_back( new WrappedAttachedAxisProperty( m_spChart2ModelContact ) ); + + aWrappedProperties.emplace_back( new WrappedNumberFormatProperty(m_spChart2ModelContact) ); + aWrappedProperties.emplace_back( new WrappedLinkNumberFormatProperty ); + } + + WrappedSymbolProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + WrappedDataCaptionProperties::addWrappedPropertiesForSeries( aWrappedProperties, m_spChart2ModelContact ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + //add unnamed line properties (different inner names here) + + aWrappedProperties.emplace_back( new WrappedProperty("FillColor","Color") ); + aWrappedProperties.emplace_back( new WrappedLineStyleProperty( this ) ); + aWrappedProperties.emplace_back( new WrappedLineColorProperty( this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineDashName","BorderDashName","LineDashName", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineTransparence","BorderTransparency","Transparency", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineWidth","BorderWidth","LineWidth", this ) ); + aWrappedProperties.emplace_back( new WrappedSeriesAreaOrLineProperty("LineCap","LineCap","LineCap", this ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillStyle","FillStyle" ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillTransparence","Transparency") ); + + aWrappedProperties.emplace_back( new WrappedIgnoreProperty("LineJoint", uno::Any( drawing::LineJoint_ROUND ) ) ); + aWrappedProperties.emplace_back( new WrappedProperty("FillTransparenceGradientName","TransparencyGradientName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillGradientName","GradientName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillGradientStepCount","GradientStepCount") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillHatchName","HatchName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapName","FillBitmapName") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBackground","FillBackground") ); + + //bitmap properties + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapMode","FillBitmapMode") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapSizeX","FillBitmapSizeX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapSizeY","FillBitmapSizeY") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapLogicalSize","FillBitmapLogicalSize") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapOffsetX","FillBitmapOffsetX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapOffsetY","FillBitmapOffsetY") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapRectanglePoint","FillBitmapRectanglePoint") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapPositionOffsetX","FillBitmapPositionOffsetX") ); + aWrappedProperties.emplace_back( new WrappedProperty("FillBitmapPositionOffsetY","FillBitmapPositionOffsetY") ); + + aWrappedProperties.emplace_back( new WrappedProperty("SolidType","Geometry3D") ); + aWrappedProperties.emplace_back( new WrappedSegmentOffsetProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty("D3DPercentDiagonal","PercentDiagonal") ); + + aWrappedProperties.emplace_back( new WrappedTextRotationProperty() ); + + return aWrappedProperties; +} + +void SAL_CALL DataSeriesPointWrapper::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + if(rPropertyName == "Lines") + { + if( ! (rValue >>= m_bLinesAllowed) ) + throw lang::IllegalArgumentException("Property Lines requires value of type sal_Bool", nullptr, 0 ); + } + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + static const sal_Int32 nErrorCategoryHandle = getInfoHelper().getHandleByName("ErrorCategory"); + if( nErrorCategoryHandle == nHandle ) + { + css::chart::ChartErrorCategory aNewValue = css::chart::ChartErrorCategory_NONE; + rValue >>= aNewValue; + Any aLow, aHigh; + bool bSetHighAndLowValues = false; + switch(aNewValue) + { + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + aHigh = getPropertyValue("ConstantErrorHigh"); + aLow = getPropertyValue("ConstantErrorLow"); + bSetHighAndLowValues = true; + break; + case css::chart::ChartErrorCategory_PERCENT: + aHigh = aLow = getPropertyValue("PercentageError"); + bSetHighAndLowValues = true; + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + aHigh = aLow = getPropertyValue("ErrorMargin"); + bSetHighAndLowValues = true; + break; + default: + break; + } + + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); + + if(bSetHighAndLowValues) + { + switch(aNewValue) + { + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + setPropertyValue("ConstantErrorHigh",aHigh); + setPropertyValue("ConstantErrorLow",aLow); + break; + case css::chart::ChartErrorCategory_PERCENT: + setPropertyValue("PercentageError",aHigh); + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + setPropertyValue("ErrorMargin",aHigh); + break; + default: + break; + } + } + } + else + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); +} + +Any SAL_CALL DataSeriesPointWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + if( m_eType == DATA_POINT ) + { + if( rPropertyName == "FillColor" ) + { + rtl::Reference< DataSeries > xSeriesProp = getDataSeries(); + bool bVaryColorsByPoint = false; + if( xSeriesProp.is() && (xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) + && bVaryColorsByPoint ) + { + uno::Reference< beans::XPropertyState > xPointState( DataSeriesPointWrapper::getDataPointProperties(), uno::UNO_QUERY ); + if( xPointState.is() && xPointState->getPropertyState("Color") == beans::PropertyState_DEFAULT_VALUE ) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme() ); + if( xColorScheme.is() ) + return uno::Any( xColorScheme->getColorByIndex( m_nPointIndex ) ); + } + } + } + } + } + return WrappedPropertySet::getPropertyValue( rPropertyName ); +} + +OUString SAL_CALL DataSeriesPointWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.DataSeries"; +} + +sal_Bool SAL_CALL DataSeriesPointWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataSeriesPointWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartDataRowProperties", + "com.sun.star.chart.ChartDataPointProperties", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx new file mode 100644 index 000000000..8936ec418 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DataSeriesPointWrapper.hxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "ReferenceSizePropertyProvider.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::chart2 { class XDataSeries; } +namespace chart { class DataSeries; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class DataSeriesPointWrapper final : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XServiceInfo + , css::lang::XInitialization + , css::lang::XComponent + , css::lang::XEventListener + > + , public ReferenceSizePropertyProvider + +{ +public: + enum eType + { + DATA_SERIES, + DATA_POINT + }; + + //this constructor needs an initialize call afterwards + explicit DataSeriesPointWrapper(const std::shared_ptr& spChart2ModelContact); + + DataSeriesPointWrapper(eType eType + , sal_Int32 nSeriesIndexInNewAPI + , sal_Int32 nPointIndex //ignored for series + , const std::shared_ptr& spChart2ModelContact); + + virtual ~DataSeriesPointWrapper() override; + + bool isSupportingAreaProperties(); + bool isLinesForbidden() const { return !m_bLinesAllowed;} + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ___lang::XInitialization___ + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + +private: + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //own methods + rtl::Reference< ::chart::DataSeries > getDataSeries(); + css::uno::Reference< css::beans::XPropertySet > getDataPointProperties(); + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + eType m_eType; + sal_Int32 m_nSeriesIndexInNewAPI; + sal_Int32 m_nPointIndex; + + bool m_bLinesAllowed; + + //this should only be used, if the DataSeriesPointWrapper is initialized via the XInitialize interface + //because a big change in the chartmodel may lead to a dataseriespointer that is not connected to the model anymore + //with the indices instead we can always get the new dataseries + rtl::Reference< ::chart::DataSeries > m_xDataSeries; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx new file mode 100644 index 000000000..85df10b87 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DiagramWrapper.cxx @@ -0,0 +1,1918 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DiagramWrapper.hxx" +#include +#include "DataSeriesPointWrapper.hxx" +#include "AxisWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include "WallFloorWrapper.hxx" +#include "MinMaxLineWrapper.hxx" +#include "UpDownBarWrapper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "WrappedAxisAndGridExistenceProperties.hxx" +#include "WrappedStatisticProperties.hxx" +#include "WrappedSymbolProperties.hxx" +#include "WrappedDataCaptionProperties.hxx" +#include "WrappedSplineProperties.hxx" +#include "WrappedStockProperties.hxx" +#include "WrappedSceneProperty.hxx" +#include +#include +#include "WrappedAutomaticPositionProperties.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::chart::wrapper; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; +using ::com::sun::star::chart::XAxis; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS, + PROP_DIAGRAM_PERCENT_STACKED, + PROP_DIAGRAM_STACKED, + PROP_DIAGRAM_THREE_D, + PROP_DIAGRAM_SOLIDTYPE, + PROP_DIAGRAM_DEEP, + PROP_DIAGRAM_VERTICAL, + PROP_DIAGRAM_NUMBER_OF_LINES, + PROP_DIAGRAM_STACKED_BARS_CONNECTED, + PROP_DIAGRAM_DATAROW_SOURCE, + + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + + PROP_DIAGRAM_SORT_BY_X_VALUES, + + PROP_DIAGRAM_STARTING_ANGLE, + + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + PROP_DIAGRAM_PERSPECTIVE, + PROP_DIAGRAM_ROTATION_HORIZONTAL, + PROP_DIAGRAM_ROTATION_VERTICAL, + + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + + PROP_DIAGRAM_HAS_X_AXIS, + PROP_DIAGRAM_HAS_X_AXIS_DESCR, + PROP_DIAGRAM_HAS_X_AXIS_TITLE, + PROP_DIAGRAM_HAS_X_AXIS_GRID, + PROP_DIAGRAM_HAS_X_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_Y_AXIS, + PROP_DIAGRAM_HAS_Y_AXIS_DESCR, + PROP_DIAGRAM_HAS_Y_AXIS_TITLE, + PROP_DIAGRAM_HAS_Y_AXIS_GRID, + PROP_DIAGRAM_HAS_Y_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_Z_AXIS, + PROP_DIAGRAM_HAS_Z_AXIS_DESCR, + PROP_DIAGRAM_HAS_Z_AXIS_TITLE, + PROP_DIAGRAM_HAS_Z_AXIS_GRID, + PROP_DIAGRAM_HAS_Z_AXIS_HELP_GRID, + + PROP_DIAGRAM_HAS_SECOND_X_AXIS, + PROP_DIAGRAM_HAS_SECOND_X_AXIS_DESCR, + + PROP_DIAGRAM_HAS_SECOND_Y_AXIS, + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_DESCR, + + PROP_DIAGRAM_HAS_SECOND_X_AXIS_TITLE, + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_TITLE, + + PROP_DIAGRAM_AUTOMATIC_SIZE, + PROP_DIAGRAM_DATATABLEHBORDER, + PROP_DIAGRAM_DATATABLEVBORDER, + PROP_DIAGRAM_DATATABLEOUTLINE, + PROP_DIAGRAM_EXTERNALDATA +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AttributedDataPoints", + PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS, + cppu::UnoType >>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // see com.sun.star.chart.StackableDiagram + rOutProperties.emplace_back( "Percent", + PROP_DIAGRAM_PERCENT_STACKED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Stacked", + PROP_DIAGRAM_STACKED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Dim3D", + PROP_DIAGRAM_THREE_D, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // see com.sun.star.chart.Chart3DBarProperties + rOutProperties.emplace_back( "SolidType", + PROP_DIAGRAM_SOLIDTYPE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // see com.sun.star.chart.BarDiagram + rOutProperties.emplace_back( "Deep", + PROP_DIAGRAM_DEEP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Vertical", + PROP_DIAGRAM_VERTICAL, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "NumberOfLines", + PROP_DIAGRAM_NUMBER_OF_LINES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackedBarsConnected", + PROP_DIAGRAM_STACKED_BARS_CONNECTED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DataRowSource", + PROP_DIAGRAM_DATAROW_SOURCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GroupBarsPerAxis", + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "IncludeHiddenCells", + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //new for XY charts + rOutProperties.emplace_back( CHART_UNONAME_SORT_BY_XVALUES, + PROP_DIAGRAM_SORT_BY_X_VALUES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //for pie and donut charts + rOutProperties.emplace_back( "StartingAngle", + PROP_DIAGRAM_STARTING_ANGLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //new for 3D charts + rOutProperties.emplace_back( "RightAngledAxes", + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Perspective", + PROP_DIAGRAM_PERSPECTIVE, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationHorizontal", + PROP_DIAGRAM_ROTATION_HORIZONTAL, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationVertical", + PROP_DIAGRAM_ROTATION_VERTICAL, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + // XAxisXSupplier + rOutProperties.emplace_back( "HasXAxis", + PROP_DIAGRAM_HAS_X_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisDescription", + PROP_DIAGRAM_HAS_X_AXIS_DESCR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisTitle", + PROP_DIAGRAM_HAS_X_AXIS_TITLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisGrid", + PROP_DIAGRAM_HAS_X_AXIS_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasXAxisHelpGrid", + PROP_DIAGRAM_HAS_X_AXIS_HELP_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XAxisYSupplier + rOutProperties.emplace_back( "HasYAxis", + PROP_DIAGRAM_HAS_Y_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisDescription", + PROP_DIAGRAM_HAS_Y_AXIS_DESCR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisTitle", + PROP_DIAGRAM_HAS_Y_AXIS_TITLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisGrid", + PROP_DIAGRAM_HAS_Y_AXIS_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasYAxisHelpGrid", + PROP_DIAGRAM_HAS_Y_AXIS_HELP_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XAxisZSupplier + rOutProperties.emplace_back( "HasZAxis", + PROP_DIAGRAM_HAS_Z_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisDescription", + PROP_DIAGRAM_HAS_Z_AXIS_DESCR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisTitle", + PROP_DIAGRAM_HAS_Z_AXIS_TITLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisGrid", + PROP_DIAGRAM_HAS_Z_AXIS_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasZAxisHelpGrid", + PROP_DIAGRAM_HAS_Z_AXIS_HELP_GRID, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XTwoAxisXSupplier + rOutProperties.emplace_back( "HasSecondaryXAxis", + PROP_DIAGRAM_HAS_SECOND_X_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryXAxisDescription", + PROP_DIAGRAM_HAS_SECOND_X_AXIS_DESCR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XTwoAxisYSupplier + rOutProperties.emplace_back( "HasSecondaryYAxis", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryYAxisDescription", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_DESCR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // XSecondAxisTitleSupplier + rOutProperties.emplace_back( "HasSecondaryXAxisTitle", + PROP_DIAGRAM_HAS_SECOND_X_AXIS_TITLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "HasSecondaryYAxisTitle", + PROP_DIAGRAM_HAS_SECOND_Y_AXIS_TITLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MissingValueTreatment", + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "AutomaticSize", + PROP_DIAGRAM_AUTOMATIC_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableHBorder", + PROP_DIAGRAM_DATATABLEHBORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableVBorder", + PROP_DIAGRAM_DATATABLEVBORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableOutline", + PROP_DIAGRAM_DATATABLEOUTLINE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ExternalData", + PROP_DIAGRAM_EXTERNALDATA, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +struct StaticDiagramWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::SceneProperties::AddPropertiesToVector( aProperties ); + WrappedStatisticProperties::addProperties( aProperties ); + WrappedSymbolProperties::addProperties( aProperties ); + WrappedDataCaptionProperties::addProperties( aProperties ); + WrappedSplineProperties::addProperties( aProperties ); + WrappedStockProperties::addProperties( aProperties ); + WrappedAutomaticPositionProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticDiagramWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticDiagramWrapperPropertyArray_Initializer > +{ +}; + +bool lcl_isXYChart( const rtl::Reference< ::chart::Diagram >& rDiagram ) +{ + bool bRet = false; + rtl::Reference< ::chart::ChartType > xChartType( ::chart::DiagramHelper::getChartTypeByIndex( rDiagram, 0 ) ); + if( xChartType.is() ) + { + OUString aChartType( xChartType->getChartType() ); + if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + bRet = true; + } + return bRet; +} + +sal_Int32 lcl_getNewAPIIndexForOldAPIIndex( + sal_Int32 nOldAPIIndex + , const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + sal_Int32 nNewAPIIndex = nOldAPIIndex; + + if( lcl_isXYChart( xDiagram ) ) + { + if( nNewAPIIndex >= 1 ) + nNewAPIIndex -= 1; + } + + std::vector< rtl::Reference< ::chart::DataSeries > > aSeriesList = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( nNewAPIIndex >= static_cast(aSeriesList.size()) ) + nNewAPIIndex = -1; + + return nNewAPIIndex; +} + +OUString lcl_getDiagramType( std::u16string_view rTemplateServiceName ) +{ + static const OUStringLiteral aPrefix(u"com.sun.star.chart2.template."); + + if( o3tl::starts_with(rTemplateServiceName, aPrefix) ) + { + const std::u16string_view aName( rTemplateServiceName.substr( aPrefix.getLength())); + + // "Area" "StackedArea" "PercentStackedArea" "ThreeDArea" + // "StackedThreeDArea" "PercentStackedThreeDArea" + if( aName.find( u"Area" ) != std::u16string_view::npos ) + return "com.sun.star.chart.AreaDiagram"; + + // "Pie" "PieAllExploded" "ThreeDPie" "ThreeDPieAllExploded" + if( aName.find( u"Pie" ) != std::u16string_view::npos ) + return "com.sun.star.chart.PieDiagram"; + + // "Column" "StackedColumn" "PercentStackedColumn" "ThreeDColumnDeep" + // "ThreeDColumnFlat" "StackedThreeDColumnFlat" + // "PercentStackedThreeDColumnFlat" "Bar" "StackedBar" + // "PercentStackedBar" "ThreeDBarDeep" "ThreeDBarFlat" + // "StackedThreeDBarFlat" "PercentStackedThreeDBarFlat" "ColumnWithLine" + // "StackedColumnWithLine" + if( aName.find( u"Column" ) != std::u16string_view::npos || aName.find( u"Bar" ) != std::u16string_view::npos ) + return "com.sun.star.chart.BarDiagram"; + + // "Donut" "DonutAllExploded" "ThreeDDonut" "ThreeDDonutAllExploded" + if( aName.find( u"Donut" ) != std::u16string_view::npos ) + return "com.sun.star.chart.DonutDiagram"; + + // "ScatterLineSymbol" "ScatterLine" "ScatterSymbol" "ThreeDScatter" + if( aName.find( u"Scatter" ) != std::u16string_view::npos ) + return "com.sun.star.chart.XYDiagram"; + + // "FilledNet" "StackedFilledNet" "PercentStackedFilledNet" + if( aName.find( u"FilledNet" ) != std::u16string_view::npos ) + return "com.sun.star.chart.FilledNetDiagram"; + + // "Net" "NetSymbol" "NetLine" "StackedNet" "StackedNetSymbol" + // "StackedNetLine" "PercentStackedNet" "PercentStackedNetSymbol" + // "PercentStackedNetLine" + if( aName.find( u"Net" ) != std::u16string_view::npos ) + return "com.sun.star.chart.NetDiagram"; + + // "StockLowHighClose" "StockOpenLowHighClose" "StockVolumeLowHighClose" + // "StockVolumeOpenLowHighClose" + if( aName.find( u"Stock" ) != std::u16string_view::npos ) + return "com.sun.star.chart.StockDiagram"; + + if( aName.find( u"Bubble" ) != std::u16string_view::npos ) + return "com.sun.star.chart.BubbleDiagram"; + + // Note: this must be checked after Bar, Net and Scatter + + // "Symbol" "StackedSymbol" "PercentStackedSymbol" "Line" "StackedLine" + // "PercentStackedLine" "LineSymbol" "StackedLineSymbol" + // "PercentStackedLineSymbol" "ThreeDLine" "StackedThreeDLine" + // "PercentStackedThreeDLine" "ThreeDLineDeep" + if( aName.find( u"Line" ) != std::u16string_view::npos || aName.find( u"Symbol" ) != std::u16string_view::npos ) + return "com.sun.star.chart.LineDiagram"; + + OSL_FAIL( "unknown template" ); + } + + return OUString(); +} + +typedef std::map< OUString, OUString > tMakeStringStringMap; + +const tMakeStringStringMap& lcl_getChartTypeNameMap() +{ + static tMakeStringStringMap g_aChartTypeNameMap{ + {"com.sun.star.chart2.LineChartType", "com.sun.star.chart.LineDiagram"}, + {"com.sun.star.chart2.AreaChartType", "com.sun.star.chart.AreaDiagram"}, + {"com.sun.star.chart2.ColumnChartType", "com.sun.star.chart.BarDiagram"}, + {"com.sun.star.chart2.PieChartType", "com.sun.star.chart.PieDiagram"}, + {"com.sun.star.chart2.DonutChartType", "com.sun.star.chart.DonutDiagram"}, + {"com.sun.star.chart2.ScatterChartType", "com.sun.star.chart.XYDiagram"}, + {"com.sun.star.chart2.FilledNetChartType", "com.sun.star.chart.FilledNetDiagram"}, + {"com.sun.star.chart2.NetChartType", "com.sun.star.chart.NetDiagram"}, + {"com.sun.star.chart2.CandleStickChartType", "com.sun.star.chart.StockDiagram"}, + {"com.sun.star.chart2.BubbleChartType", "com.sun.star.chart.BubbleDiagram"} + }; + return g_aChartTypeNameMap; +} + +OUString lcl_getOldChartTypeName( const OUString & rNewChartTypeName ) +{ + OUString aOld(rNewChartTypeName); + + const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap(); + tMakeStringStringMap::const_iterator aIt( rMap.find( rNewChartTypeName )); + if( aIt != rMap.end()) + { + aOld = aIt->second; + } + return aOld; +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +DiagramWrapper::DiagramWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +DiagramWrapper::~DiagramWrapper() +{} + +// ____ XDiagram ____ +OUString SAL_CALL DiagramWrapper::getDiagramType() +{ + OUString aRet; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xChartDoc.is() && xDiagram.is() ) + { + Reference< beans::XPropertySet > xChartDocProp( static_cast(xChartDoc.get()), uno::UNO_QUERY ); + if( xChartDocProp.is() ) + { + uno::Reference< util::XRefreshable > xAddIn; + if( xChartDocProp->getPropertyValue( "AddIn" ) >>= xAddIn ) + { + uno::Reference< lang::XServiceName > xServiceName( xAddIn, uno::UNO_QUERY ); + if( xServiceName.is()) + return xServiceName->getServiceName(); + } + } + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + aRet = lcl_getDiagramType( aTemplateAndService.sServiceName ); + } + + if( aRet.isEmpty()) + { + // none of the standard templates matched + // use first chart type + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + if( xChartType.is() ) + { + aRet = xChartType->getChartType(); + if( !aRet.isEmpty() ) + aRet = lcl_getOldChartTypeName( aRet ); + } + if( aRet.isEmpty()) + aRet = "com.sun.star.chart.BarDiagram"; + } + + return aRet; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDataRowProperties( sal_Int32 nRow ) +{ + if( nRow < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + sal_Int32 nNewAPIIndex = lcl_getNewAPIIndexForOldAPIIndex( nRow, m_spChart2ModelContact->getDiagram() ); + if( nNewAPIIndex < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + Reference< beans::XPropertySet > xRet( new DataSeriesPointWrapper( + DataSeriesPointWrapper::DATA_SERIES, nNewAPIIndex, 0, m_spChart2ModelContact ) ); + return xRet; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDataPointProperties( sal_Int32 nCol, sal_Int32 nRow ) +{ + if( nCol < 0 || nRow < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + sal_Int32 nNewAPIIndex = lcl_getNewAPIIndexForOldAPIIndex( nRow, m_spChart2ModelContact->getDiagram() ); + if( nNewAPIIndex < 0 ) + throw lang::IndexOutOfBoundsException("DataSeries index invalid", + static_cast< ::cppu::OWeakObject * >( this )); + + //todo: check borders of point index + + Reference< beans::XPropertySet > xRet( new DataSeriesPointWrapper( + DataSeriesPointWrapper::DATA_POINT, nNewAPIIndex, nCol, m_spChart2ModelContact ) ); + + return xRet; +} + +// ____ XShape (base of XDiagram) ____ +awt::Point SAL_CALL DiagramWrapper::getPosition() +{ + awt::Point aPosition = ToPoint( m_spChart2ModelContact->GetDiagramRectangleIncludingAxes() ); + return aPosition; +} + +void SAL_CALL DiagramWrapper::setPosition( const awt::Point& aPosition ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( !xProp.is() ) + return; + + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = double(aPosition.Y)/double(aPageSize.Height); + if( aRelativePosition.Primary < 0 || aRelativePosition.Secondary < 0 || aRelativePosition.Primary > 1 || aRelativePosition.Secondary > 1 ) + { + OSL_FAIL("DiagramWrapper::setPosition called with a position out of range -> automatic values are taken instead" ); + uno::Any aEmpty; + xProp->setPropertyValue( "RelativePosition", aEmpty ); + return; + } + xProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + xProp->setPropertyValue( "PosSizeExcludeAxes", uno::Any(false) ); +} + +awt::Size SAL_CALL DiagramWrapper::getSize() +{ + awt::Size aSize = ToSize( m_spChart2ModelContact->GetDiagramRectangleIncludingAxes() ); + return aSize; +} + +void SAL_CALL DiagramWrapper::setSize( const awt::Size& aSize ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( !xProp.is() ) + return; + + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativeSize aRelativeSize; + aRelativeSize.Primary = double(aSize.Width)/double(aPageSize.Width); + aRelativeSize.Secondary = double(aSize.Height)/double(aPageSize.Height); + + if( aRelativeSize.Primary > 1 || aRelativeSize.Secondary > 1 ) + { + OSL_FAIL("DiagramWrapper::setSize called with sizes bigger than page -> automatic values are taken instead" ); + uno::Any aEmpty; + xProp->setPropertyValue( "RelativeSize", aEmpty ); + return; + } + + xProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + xProp->setPropertyValue( "PosSizeExcludeAxes", uno::Any(false) ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL DiagramWrapper::getShapeType() +{ + return "com.sun.star.chart.Diagram"; +} + +// ____ XDiagramPositioning ____ + +void SAL_CALL DiagramWrapper::setAutomaticDiagramPositioning() +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + xDiaProps->setPropertyValue( "RelativeSize", Any() ); + xDiaProps->setPropertyValue( "RelativePosition", Any() ); + } +} +sal_Bool SAL_CALL DiagramWrapper::isAutomaticDiagramPositioning( ) +{ + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + Any aRelativeSize( xDiaProps->getPropertyValue( "RelativeSize" ) ); + Any aRelativePosition( xDiaProps->getPropertyValue( "RelativePosition" ) ); + if( aRelativeSize.hasValue() && aRelativePosition.hasValue() ) + return false; + } + return true; +} +void SAL_CALL DiagramWrapper::setDiagramPositionExcludingAxes( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + DiagramHelper::setDiagramPositioning( m_spChart2ModelContact->getDocumentModel(), rPositionRect ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + xDiaProps->setPropertyValue("PosSizeExcludeAxes", uno::Any(true) ); +} +sal_Bool SAL_CALL DiagramWrapper::isExcludingDiagramPositioning() +{ + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + { + Any aRelativeSize( xDiaProps->getPropertyValue( "RelativeSize" ) ); + Any aRelativePosition( xDiaProps->getPropertyValue( "RelativePosition" ) ); + if( aRelativeSize.hasValue() && aRelativePosition.hasValue() ) + { + bool bPosSizeExcludeAxes = false; + xDiaProps->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes; + return bPosSizeExcludeAxes; + } + } + return false; +} +awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionExcludingAxes( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleExcludingAxes(); +} +void SAL_CALL DiagramWrapper::setDiagramPositionIncludingAxes( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + DiagramHelper::setDiagramPositioning( m_spChart2ModelContact->getDocumentModel(), rPositionRect ); + uno::Reference< beans::XPropertySet > xDiaProps( getDiagram(), uno::UNO_QUERY ); + if( xDiaProps.is() ) + xDiaProps->setPropertyValue("PosSizeExcludeAxes", uno::Any(false) ); +} +awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionIncludingAxes( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleIncludingAxes(); +} +void SAL_CALL DiagramWrapper::setDiagramPositionIncludingAxesAndAxisTitles( const awt::Rectangle& rPositionRect ) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + awt::Rectangle aRect( m_spChart2ModelContact->SubstractAxisTitleSizes(rPositionRect) ); + DiagramWrapper::setDiagramPositionIncludingAxes( aRect ); +} +css::awt::Rectangle SAL_CALL DiagramWrapper::calculateDiagramPositionIncludingAxesAndAxisTitles( ) +{ + return m_spChart2ModelContact->GetDiagramRectangleIncludingTitle(); +} + +// ____ XAxisSupplier ____ +Reference< XAxis > SAL_CALL DiagramWrapper::getAxis( sal_Int32 nDimensionIndex ) +{ + Reference< XAxis > xAxis; + if(!nDimensionIndex) + { + if( !m_xXAxis.is() ) + m_xXAxis = new AxisWrapper( AxisWrapper::X_AXIS, m_spChart2ModelContact ); + xAxis = m_xXAxis; + } + else if(nDimensionIndex==1) + { + if( !m_xYAxis.is() ) + m_xYAxis = new AxisWrapper( AxisWrapper::Y_AXIS, m_spChart2ModelContact ); + xAxis = m_xYAxis; + } + else if(nDimensionIndex==2) + { + if( !m_xZAxis.is() ) + m_xZAxis = new AxisWrapper( AxisWrapper::Z_AXIS, m_spChart2ModelContact ); + xAxis = m_xZAxis; + } + return xAxis; +} + +Reference< XAxis > SAL_CALL DiagramWrapper::getSecondaryAxis( sal_Int32 nDimensionIndex ) +{ + Reference< XAxis > xAxis; + if(!nDimensionIndex) + { + if( !m_xSecondXAxis.is() ) + m_xSecondXAxis = new AxisWrapper( AxisWrapper::SECOND_X_AXIS, m_spChart2ModelContact ); + xAxis = m_xSecondXAxis; + } + else if(nDimensionIndex==1) + { + if( !m_xSecondYAxis.is() ) + m_xSecondYAxis = new AxisWrapper( AxisWrapper::SECOND_Y_AXIS, m_spChart2ModelContact ); + xAxis = m_xSecondYAxis; + } + return xAxis; +} + +// ____ XAxisZSupplier ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getZAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(2) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getZAxis() +{ + if( ! m_xZAxis.is()) + m_xZAxis = new AxisWrapper( AxisWrapper::Z_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xZAxis, uno::UNO_QUERY ); +} + +// ____ XTwoAxisXSupplier ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getSecondaryXAxis() +{ + if( ! m_xSecondXAxis.is()) + m_xSecondXAxis = new AxisWrapper( AxisWrapper::SECOND_X_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xSecondXAxis, uno::UNO_QUERY ); +} + +// ____ XAxisXSupplier (base of XTwoAxisXSupplier) ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getXAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXAxis() +{ + if( ! m_xXAxis.is()) + m_xXAxis = new AxisWrapper( AxisWrapper::X_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xXAxis, uno::UNO_QUERY ); +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getXHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(0) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +// ____ XTwoAxisYSupplier ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getSecondaryYAxis() +{ + if( ! m_xSecondYAxis.is()) + m_xSecondYAxis = new AxisWrapper( AxisWrapper::SECOND_Y_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xSecondYAxis, uno::UNO_QUERY ); +} + +// ____ XAxisYSupplier (base of XTwoAxisYSupplier) ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getYAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYAxis() +{ + if( ! m_xYAxis.is()) + m_xYAxis = new AxisWrapper( AxisWrapper::Y_AXIS, m_spChart2ModelContact ); + return Reference< beans::XPropertySet >( m_xYAxis, uno::UNO_QUERY ); +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYMainGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet = xAxis->getMajorGrid(); + return xRet; +} + +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getYHelpGrid() +{ + Reference< beans::XPropertySet > xRet; + Reference< XAxis > xAxis( getAxis(1) ); + if( xAxis.is() ) + xRet = xAxis->getMinorGrid(); + return xRet; +} + +// ____ XSecondAxisTitleSupplier ____ +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getSecondXAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getSecondaryAxis(0) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +Reference< drawing::XShape > SAL_CALL DiagramWrapper::getSecondYAxisTitle() +{ + Reference< drawing::XShape > xRet; + Reference< XAxis > xAxis( getSecondaryAxis(1) ); + if( xAxis.is() ) + xRet.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xRet; +} + +// ____ XStatisticDisplay ____ +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getUpBar() +{ + if( !m_xUpBarWrapper.is() ) + { + m_xUpBarWrapper = new UpDownBarWrapper( true, m_spChart2ModelContact ); + } + return m_xUpBarWrapper; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getDownBar() +{ + if( !m_xDownBarWrapper.is() ) + { + m_xDownBarWrapper = new UpDownBarWrapper( false, m_spChart2ModelContact ); + } + return m_xDownBarWrapper; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getMinMaxLine() +{ + if( !m_xMinMaxLineWrapper.is() ) + { + m_xMinMaxLineWrapper = new MinMaxLineWrapper( m_spChart2ModelContact ); + } + return m_xMinMaxLineWrapper; +} + +// ____ X3DDisplay ____ +Reference< beans::XPropertySet > SAL_CALL DiagramWrapper::getWall() +{ + if( !m_xWall.is() ) + { + m_xWall = new WallFloorWrapper( true, m_spChart2ModelContact ); + } + return m_xWall; +} + +Reference< + beans::XPropertySet > SAL_CALL DiagramWrapper::getFloor() +{ + if( !m_xFloor.is() ) + { + m_xFloor = new WallFloorWrapper( false, m_spChart2ModelContact ); + } + return m_xFloor; +} + +// ____ X3DDefaultSetter ____ +void SAL_CALL DiagramWrapper::set3DSettingsToDefault() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->set3DSettingsToDefault(); +} + +void SAL_CALL DiagramWrapper::setDefaultRotation() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->setDefaultRotation(); +} + +void SAL_CALL DiagramWrapper::setDefaultIllumination() +{ + rtl::Reference< ::chart::Diagram > x3DDefaultSetter( m_spChart2ModelContact->getDiagram() ); + if( x3DDefaultSetter.is() ) + x3DDefaultSetter->setDefaultIllumination(); +} + +// ____ XComponent ____ +void SAL_CALL DiagramWrapper::dispose() +{ + m_aEventListenerContainer.disposeAndClear( lang::EventObject( static_cast< ::cppu::OWeakObject* >( this ))); + + MutexGuard aGuard( m_aMutex); + + DisposeHelper::DisposeAndClear( m_xXAxis ); + DisposeHelper::DisposeAndClear( m_xYAxis ); + DisposeHelper::DisposeAndClear( m_xZAxis ); + DisposeHelper::DisposeAndClear( m_xSecondXAxis ); + DisposeHelper::DisposeAndClear( m_xSecondYAxis ); + DisposeHelper::DisposeAndClear( m_xWall ); + DisposeHelper::DisposeAndClear( m_xFloor ); + DisposeHelper::DisposeAndClear( m_xMinMaxLineWrapper ); + DisposeHelper::DisposeAndClear( m_xUpBarWrapper ); + DisposeHelper::DisposeAndClear( m_xDownBarWrapper ); + + clearWrappedPropertySet(); +} + +void SAL_CALL DiagramWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL DiagramWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +namespace { + +//PROP_DIAGRAM_DATAROW_SOURCE +class WrappedDataRowSourceProperty : public WrappedProperty +{ +public: + explicit WrappedDataRowSourceProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDataRowSourceProperty::WrappedDataRowSourceProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("DataRowSource",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDataRowSourceProperty::getPropertyDefault( nullptr ); +} + +void WrappedDataRowSourceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + css::chart::ChartDataRowSource eChartDataRowSource = css::chart::ChartDataRowSource_ROWS; + if( ! (rOuterValue >>= eChartDataRowSource) ) + { + sal_Int32 nNew = sal_Int32(css::chart::ChartDataRowSource_ROWS); + if( !(rOuterValue >>= nNew) ) + throw lang::IllegalArgumentException( "Property DataRowSource requires css::chart::ChartDataRowSource value", nullptr, 0 ); + eChartDataRowSource = css::chart::ChartDataRowSource(nNew); + } + + m_aOuterValue = rOuterValue; + + bool bNewUseColumns = eChartDataRowSource == css::chart::ChartDataRowSource_COLUMNS; + + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + if( bUseColumns != bNewUseColumns ) + { + aSequenceMapping.realloc(0); + DataSourceHelper::setRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aSequenceMapping, bNewUseColumns , bFirstCellAsLabel , bHasCategories); + } + } +} + +Any WrappedDataRowSourceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aRangeString; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + + if( DataSourceHelper::detectRangeSegmentation( + m_spChart2ModelContact->getDocumentModel(), aRangeString, aSequenceMapping, bUseColumns + , bFirstCellAsLabel, bHasCategories ) ) + { + css::chart::ChartDataRowSource eChartDataRowSource = css::chart::ChartDataRowSource_ROWS; + if(bUseColumns) + eChartDataRowSource = css::chart::ChartDataRowSource_COLUMNS; + + m_aOuterValue <<= eChartDataRowSource; + } + + return m_aOuterValue; +} + +Any WrappedDataRowSourceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= css::chart::ChartDataRowSource_COLUMNS; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_STACKED +//PROP_DIAGRAM_DEEP +//PROP_DIAGRAM_PERCENT_STACKED +class WrappedStackingProperty : public WrappedProperty +{ +public: + WrappedStackingProperty(StackMode eStackMode, const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: //methods + bool detectInnerValue( StackMode& eInnerStackMode ) const; + +private: //member +std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + const StackMode m_eStackMode; + mutable Any m_aOuterValue; +}; + +} + +WrappedStackingProperty::WrappedStackingProperty(StackMode eStackMode, const std::shared_ptr& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eStackMode( eStackMode ) +{ + switch( m_eStackMode ) + { + case StackMode::YStacked: + m_aOuterName = "Stacked"; + break; + case StackMode::YStackedPercent: + m_aOuterName = "Percent"; + break; + case StackMode::ZStacked: + m_aOuterName = "Deep"; + break; + default: + OSL_FAIL( "unexpected stack mode" ); + break; + } +} + +bool WrappedStackingProperty::detectInnerValue( StackMode& eStackMode ) const +{ + bool bHasDetectableInnerValue = false; + bool bIsAmbiguous = false; + eStackMode = DiagramHelper::getStackMode( m_spChart2ModelContact->getDiagram() + , bHasDetectableInnerValue, bIsAmbiguous ); + return bHasDetectableInnerValue; +} + +void WrappedStackingProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Stacking Properties require boolean values", nullptr, 0 ); + + StackMode eInnerStackMode; + bool bHasDetectableInnerValue = detectInnerValue( eInnerStackMode ); + + if( !bHasDetectableInnerValue ) + { + m_aOuterValue = rOuterValue; + return; + } + + if( bNewValue && eInnerStackMode == m_eStackMode ) + return; + if( !bNewValue && eInnerStackMode != m_eStackMode ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + StackMode eNewStackMode = bNewValue ? m_eStackMode : StackMode::NONE; + DiagramHelper::setStackMode( xDiagram, eNewStackMode ); + } +} + +Any WrappedStackingProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + StackMode eInnerStackMode; + if( detectInnerValue( eInnerStackMode ) ) + { + bool bValue = (eInnerStackMode == m_eStackMode); + return Any(bValue); + } + return m_aOuterValue; +} + +Any WrappedStackingProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_THREE_D +class WrappedDim3DProperty : public WrappedProperty +{ +public: + explicit WrappedDim3DProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedDim3DProperty::WrappedDim3DProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("Dim3D",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedDim3DProperty::getPropertyDefault( nullptr ); +} + +void WrappedDim3DProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNew3D = false; + if( ! (rOuterValue >>= bNew3D) ) + throw lang::IllegalArgumentException( "Property Dim3D requires boolean value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bOld3D = DiagramHelper::getDimension( xDiagram ) == 3; + if( bOld3D != bNew3D ) + DiagramHelper::setDimension( xDiagram, bNew3D ? 3 : 2 ); +} + +Any WrappedDim3DProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool b3D = DiagramHelper::getDimension( xDiagram ) == 3; + m_aOuterValue <<= b3D; + } + return m_aOuterValue; +} + +Any WrappedDim3DProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_VERTICAL +class WrappedVerticalProperty : public WrappedProperty +{ +public: + explicit WrappedVerticalProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedVerticalProperty::WrappedVerticalProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("Vertical",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedVerticalProperty::getPropertyDefault( nullptr ); +} + +void WrappedVerticalProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewVertical = false; + if( ! (rOuterValue >>= bNewVertical) ) + throw lang::IllegalArgumentException( "Property Vertical requires boolean value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bFound = false; + bool bAmbiguous = false; + bool bOldVertical = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + if( bFound && ( bOldVertical != bNewVertical || bAmbiguous ) ) + DiagramHelper::setVertical( xDiagram, bNewVertical ); +} + +Any WrappedVerticalProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bFound = false; + bool bAmbiguous = false; + bool bVertical = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + if( bFound ) + m_aOuterValue <<= bVertical; + } + return m_aOuterValue; +} + +Any WrappedVerticalProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_NUMBER_OF_LINES +class WrappedNumberOfLinesProperty : public WrappedProperty +{ +public: + explicit WrappedNumberOfLinesProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: //methods + bool detectInnerValue( uno::Any& rInnerValue ) const; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedNumberOfLinesProperty::WrappedNumberOfLinesProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("NumberOfLines",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_aOuterValue( getPropertyDefault(nullptr) ) +{ +} + +bool WrappedNumberOfLinesProperty::detectInnerValue( uno::Any& rInnerValue ) const +{ + sal_Int32 nNumberOfLines = 0; + bool bHasDetectableInnerValue = false; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.ColumnWithLine" ) + { + try + { + uno::Reference< beans::XPropertySet > xProp( static_cast(aTemplateAndService.xChartTypeTemplate.get()), uno::UNO_QUERY ); + xProp->getPropertyValue( m_aOuterName ) >>= nNumberOfLines; + bHasDetectableInnerValue = true; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + if(bHasDetectableInnerValue) + rInnerValue <<= nNumberOfLines; + return bHasDetectableInnerValue; +} + +void WrappedNumberOfLinesProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewValue; + if( ! (rOuterValue >>= nNewValue) ) + throw lang::IllegalArgumentException( "property NumberOfLines requires sal_Int32 value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + sal_Int32 nDimension = ::chart::DiagramHelper::getDimension( xDiagram ); + if( !(xChartDoc.is() && xDiagram.is() && nDimension == 2) ) + return; + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + rtl::Reference< ChartTypeTemplate > xTemplate; + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.ColumnWithLine" ) + { + if( nNewValue != 0 ) + { + xTemplate = aTemplateAndService.xChartTypeTemplate; + try + { + sal_Int32 nOldValue = 0; + uno::Reference< beans::XPropertySet > xProp( static_cast(xTemplate.get()), uno::UNO_QUERY ); + xProp->getPropertyValue( m_aOuterName ) >>= nOldValue; + if( nOldValue == nNewValue ) + return; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + xTemplate = xChartTypeManager->createTemplate("com.sun.star.chart2.template.Column"); + } + } + else if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.Column" ) + { + if( nNewValue == 0 ) + return; + xTemplate = xChartTypeManager->createTemplate( "com.sun.star.chart2.template.ColumnWithLine" ); + } + + if(!xTemplate.is()) + return; + + try + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + uno::Reference< beans::XPropertySet > xProp( static_cast(xTemplate.get()), uno::UNO_QUERY ); + xProp->setPropertyValue( "NumberOfLines", uno::Any(nNewValue) ); + xTemplate->changeDiagram( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedNumberOfLinesProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + if( !detectInnerValue( aRet ) ) + aRet = m_aOuterValue; + return aRet; +} + +Any WrappedNumberOfLinesProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= sal_Int32( 0 ); + return aRet; +} + +namespace { + +//PROP_DIAGRAM_ATTRIBUTED_DATA_POINTS +class WrappedAttributedDataPointsProperty : public WrappedProperty +{ +public: + explicit WrappedAttributedDataPointsProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedAttributedDataPointsProperty::WrappedAttributedDataPointsProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("AttributedDataPoints",OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedAttributedDataPointsProperty::getPropertyDefault( nullptr ); +} + +void WrappedAttributedDataPointsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + uno::Sequence< uno::Sequence< sal_Int32 > > aNewValue; + if( ! (rOuterValue >>= aNewValue) ) + throw lang::IllegalArgumentException( "Property AttributedDataPoints requires value of type uno::Sequence< uno::Sequence< sal_Int32 > >", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + + if( !xDiagram ) + return; + + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 i = 0; + for (auto const& series : aSeriesVector) + { + uno::Any aVal; + if( i < aNewValue.getLength() ) + aVal <<= aNewValue[i]; + else + { + //set empty sequence + uno::Sequence< sal_Int32 > aSeq; + aVal <<= aSeq; + } + series->setPropertyValue( "AttributedDataPoints", aVal ); + ++i; + } +} + +Any WrappedAttributedDataPointsProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + + if( xDiagram ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + uno::Sequence< uno::Sequence< sal_Int32 > > aResult( aSeriesVector.size() ); + auto aResultRange = asNonConstRange(aResult); + sal_Int32 i = 0; + for (auto const& series : aSeriesVector) + { + uno::Any aVal( + series->getPropertyValue("AttributedDataPoints")); + uno::Sequence< sal_Int32 > aSeq; + if( aVal >>= aSeq ) + aResultRange[ i ] = aSeq; + ++i; + } + m_aOuterValue <<= aResult; + } + return m_aOuterValue; +} + +Any WrappedAttributedDataPointsProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + uno::Sequence< uno::Sequence< sal_Int32 > > aSeq; + aRet <<= aSeq; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_SOLIDTYPE +class WrappedSolidTypeProperty : public WrappedProperty +{ +public: + explicit WrappedSolidTypeProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable Any m_aOuterValue; +}; + +} + +WrappedSolidTypeProperty::WrappedSolidTypeProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty( "SolidType", OUString() ) + , m_spChart2ModelContact( spChart2ModelContact ) +{ + m_aOuterValue = WrappedSolidTypeProperty::getPropertyDefault( nullptr ); +} + +void WrappedSolidTypeProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewSolidType = css::chart::ChartSolidType::RECTANGULAR_SOLID; + if( ! (rOuterValue >>= nNewSolidType) ) + throw lang::IllegalArgumentException( "Property SolidType requires integer value", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + bool bFound = false; + bool bAmbiguous = false; + sal_Int32 nOldSolidType = DiagramHelper::getGeometry3D( xDiagram, bFound, bAmbiguous ); + if( bFound && ( nOldSolidType != nNewSolidType || bAmbiguous ) ) + DiagramHelper::setGeometry3D( xDiagram, nNewSolidType ); +} + +Any WrappedSolidTypeProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bFound = false; + bool bAmbiguous = false; + sal_Int32 nGeometry = DiagramHelper::getGeometry3D( xDiagram, bFound, bAmbiguous ); + if( bFound ) + m_aOuterValue <<= nGeometry; + } + return m_aOuterValue; +} + +Any WrappedSolidTypeProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( css::chart::ChartSolidType::RECTANGULAR_SOLID ); +} + +namespace { + +class WrappedAutomaticSizeProperty : public WrappedProperty +{ +public: + WrappedAutomaticSizeProperty(); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; +}; + +} + +WrappedAutomaticSizeProperty::WrappedAutomaticSizeProperty() + : WrappedProperty( "AutomaticSize", OUString() ) +{ +} + +void WrappedAutomaticSizeProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property AutomaticSize requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + { + Any aRelativeSize( xInnerPropertySet->getPropertyValue( "RelativeSize" ) ); + if( aRelativeSize.hasValue() ) + xInnerPropertySet->setPropertyValue( "RelativeSize", Any() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedAutomaticSizeProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + Any aRelativeSize( xInnerPropertySet->getPropertyValue( "RelativeSize" ) ); + if( !aRelativeSize.hasValue() ) + aRet <<= true; + } + return aRet; +} + +Any WrappedAutomaticSizeProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +//PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS +class WrappedIncludeHiddenCellsProperty : public WrappedProperty +{ +public: + explicit WrappedIncludeHiddenCellsProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue(const Reference& xInnerPropertySet) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedIncludeHiddenCellsProperty::WrappedIncludeHiddenCellsProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedProperty("IncludeHiddenCells","IncludeHiddenCells") + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedIncludeHiddenCellsProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property IncludeHiddenCells requires boolean value", nullptr, 0 ); + + ChartModelHelper::setIncludeHiddenCells( bNewValue, *m_spChart2ModelContact->getDocumentModel() ); +} + +Any WrappedIncludeHiddenCellsProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bValue = ChartModelHelper::isIncludeHiddenCells( m_spChart2ModelContact->getDocumentModel() ); + return uno::Any(bValue); +} + +// ____ XDiagramProvider ____ +Reference< chart2::XDiagram > SAL_CALL DiagramWrapper::getDiagram() +{ + return m_spChart2ModelContact->getDiagram(); +} + +void SAL_CALL DiagramWrapper::setDiagram( + const Reference< chart2::XDiagram >& /*xDiagram*/ ) +{ + //@todo: remove this method from interface + OSL_FAIL("DiagramWrapper::setDiagram is not implemented, should be removed and not be called" ); +} + +Reference< beans::XPropertySet > DiagramWrapper::getInnerPropertySet() +{ + return m_spChart2ModelContact->getDiagram(); +} + +const Sequence< beans::Property >& DiagramWrapper::getPropertySequence() +{ + return *StaticDiagramWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > DiagramWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + WrappedAxisAndGridExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAxisTitleExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAxisLabelExistenceProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedSceneProperty::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedIgnoreProperties::addIgnoreFillProperties( aWrappedProperties ); + WrappedIgnoreProperties::addIgnoreLineProperties( aWrappedProperties ); + WrappedStatisticProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedSymbolProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedDataCaptionProperties::addWrappedPropertiesForDiagram( aWrappedProperties, m_spChart2ModelContact ); + WrappedSplineProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedStockProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + + aWrappedProperties.emplace_back( new WrappedDataRowSourceProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::YStacked,m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::YStackedPercent, m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedStackingProperty( StackMode::ZStacked, m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedDim3DProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedVerticalProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedNumberOfLinesProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAttributedDataPointsProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedProperty( "StackedBarsConnected", "ConnectBars" ) ); + aWrappedProperties.emplace_back( new WrappedSolidTypeProperty( m_spChart2ModelContact ) ); + aWrappedProperties.emplace_back( new WrappedAutomaticSizeProperty() ); + aWrappedProperties.emplace_back( new WrappedIncludeHiddenCellsProperty( m_spChart2ModelContact ) ); + + return aWrappedProperties; +} + +OUString SAL_CALL DiagramWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Diagram"; +} + +sal_Bool SAL_CALL DiagramWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DiagramWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.Diagram", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.chart.StackableDiagram", + "com.sun.star.chart.ChartAxisXSupplier", + "com.sun.star.chart.ChartAxisYSupplier", + "com.sun.star.chart.ChartAxisZSupplier", + "com.sun.star.chart.ChartTwoAxisXSupplier", + "com.sun.star.chart.ChartTwoAxisYSupplier" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx b/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx new file mode 100644 index 000000000..bef53a739 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/DiagramWrapper.hxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::lang { class XEventListener; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class DiagramWrapper : public cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::chart::XDiagram + , css::chart::XAxisSupplier + , css::chart::XAxisZSupplier + , css::chart::XTwoAxisXSupplier // : XAxisXSupplier + , css::chart::XTwoAxisYSupplier // : XAxisYSupplier + , css::chart::XStatisticDisplay + , css::chart::X3DDisplay + , css::chart::X3DDefaultSetter + , css::lang::XServiceInfo + , css::lang::XComponent + , css::chart::XDiagramPositioning + , css::chart2::XDiagramProvider + , css::chart::XSecondAxisTitleSupplier + > +{ +public: + explicit DiagramWrapper(const std::shared_ptr& spChart2ModelContact); + virtual ~DiagramWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + // ____ XDiagram ____ + virtual OUString SAL_CALL getDiagramType() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDataRowProperties( sal_Int32 nRow ) override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDataPointProperties( sal_Int32 nCol, sal_Int32 nRow ) override; + + // ____ XShape (base of XDiagram) ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XAxisSupplier ____ + virtual css::uno::Reference< + css::chart::XAxis > SAL_CALL getAxis( sal_Int32 nDimensionIndex ) override; + virtual css::uno::Reference< + css::chart::XAxis > SAL_CALL getSecondaryAxis( sal_Int32 nDimensionIndex ) override; + + // ____ XAxisZSupplier ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getZAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZMainGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZHelpGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getZAxis() override; + + // ____ XTwoAxisXSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getSecondaryXAxis() override; + + // ____ XAxisXSupplier (base of XTwoAxisXSupplier) ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getXAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXAxis() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXMainGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getXHelpGrid() override; + + // ____ XTwoAxisYSupplier ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getSecondaryYAxis() override; + + // ____ XAxisYSupplier (base of XTwoAxisYSupplier) ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getYAxisTitle() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYAxis() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYHelpGrid() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getYMainGrid() override; + + // ____ XSecondAxisTitleSupplier ____ + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getSecondXAxisTitle() override; + virtual css::uno::Reference< + css::drawing::XShape > SAL_CALL getSecondYAxisTitle() override; + + // ____ XStatisticDisplay ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getUpBar() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getDownBar() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getMinMaxLine() override; + + // ____ X3DDisplay ____ + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getWall() override; + virtual css::uno::Reference< + css::beans::XPropertySet > SAL_CALL getFloor() override; + + // ____ X3DDefaultSetter ____ + virtual void SAL_CALL set3DSettingsToDefault() override; + virtual void SAL_CALL setDefaultRotation() override; + virtual void SAL_CALL setDefaultIllumination() override; + + // ____ XDiagramPositioning ____ + virtual void SAL_CALL setAutomaticDiagramPositioning( ) override; + virtual sal_Bool SAL_CALL isAutomaticDiagramPositioning( ) override; + virtual void SAL_CALL setDiagramPositionExcludingAxes( const css::awt::Rectangle& PositionRect ) override; + virtual sal_Bool SAL_CALL isExcludingDiagramPositioning( ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionExcludingAxes( ) override; + virtual void SAL_CALL setDiagramPositionIncludingAxes( const css::awt::Rectangle& PositionRect ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionIncludingAxes( ) override; + virtual void SAL_CALL setDiagramPositionIncludingAxesAndAxisTitles( const css::awt::Rectangle& PositionRect ) override; + virtual css::awt::Rectangle SAL_CALL calculateDiagramPositionIncludingAxesAndAxisTitles( ) override; + + // ____ XDiagramProvider ____ + virtual css::uno::Reference< css::chart2::XDiagram > SAL_CALL getDiagram() override; + virtual void SAL_CALL setDiagram( const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + css::uno::Reference< + css::chart::XAxis > m_xXAxis; + css::uno::Reference< + css::chart::XAxis > m_xYAxis; + css::uno::Reference< + css::chart::XAxis > m_xZAxis; + css::uno::Reference< + css::chart::XAxis > m_xSecondXAxis; + css::uno::Reference< + css::chart::XAxis > m_xSecondYAxis; + + css::uno::Reference< + css::beans::XPropertySet > m_xWall; + css::uno::Reference< + css::beans::XPropertySet > m_xFloor; + + css::uno::Reference< + css::beans::XPropertySet > m_xMinMaxLineWrapper; + css::uno::Reference< + css::beans::XPropertySet > m_xUpBarWrapper; + css::uno::Reference< + css::beans::XPropertySet > m_xDownBarWrapper; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/GridWrapper.cxx b/chart2/source/controller/chartapiwrapper/GridWrapper.cxx new file mode 100644 index 000000000..b2474e236 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/GridWrapper.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "GridWrapper.hxx" +#include +#include "Chart2ModelContact.hxx" +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticGridWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticGridWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticGridWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +GridWrapper::GridWrapper(tGridType eType, const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) + , m_eType(eType) +{ +} + +GridWrapper::~GridWrapper() +{} + +void GridWrapper::getDimensionAndSubGridBool( tGridType eType, sal_Int32& rnDimensionIndex, bool& rbSubGrid ) +{ + rnDimensionIndex = 1; + rbSubGrid = false; + + switch( eType ) + { + case X_MAJOR_GRID: + rnDimensionIndex = 0; rbSubGrid = false; break; + case Y_MAJOR_GRID: + rnDimensionIndex = 1; rbSubGrid = false; break; + case Z_MAJOR_GRID: + rnDimensionIndex = 2; rbSubGrid = false; break; + case X_MINOR_GRID: + rnDimensionIndex = 0; rbSubGrid = true; break; + case Y_MINOR_GRID: + rnDimensionIndex = 1; rbSubGrid = true; break; + case Z_MINOR_GRID: + rnDimensionIndex = 2; rbSubGrid = true; break; + } +} + +// ____ XComponent ____ +void SAL_CALL GridWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + clearWrappedPropertySet(); +} + +void SAL_CALL GridWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL GridWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet + +Reference< beans::XPropertySet > GridWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + try + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 /*nCooSysIndex*/ ) ); + + sal_Int32 nDimensionIndex = 1; + bool bSubGrid = false; + getDimensionAndSubGridBool( m_eType, nDimensionIndex, bSubGrid ); + + sal_Int32 nSubGridIndex = bSubGrid ? 0 : -1; + xRet.set( AxisHelper::getGridProperties( xCooSys , nDimensionIndex, MAIN_AXIS_INDEX, nSubGridIndex ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xRet; +} + +const Sequence< beans::Property >& GridWrapper::getPropertySequence() +{ + return *StaticGridWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > GridWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedDefaultProperty( "LineColor", "LineColor", uno::Any( sal_Int32( 0x000000) ) ) ); // black + + return aWrappedProperties; +} + +OUString SAL_CALL GridWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Grid"; +} + +sal_Bool SAL_CALL GridWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL GridWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartGrid", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.LineProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/GridWrapper.hxx b/chart2/source/controller/chartapiwrapper/GridWrapper.hxx new file mode 100644 index 000000000..0a16368e9 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/GridWrapper.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class GridWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + enum tGridType + { + X_MAJOR_GRID, + Y_MAJOR_GRID, + Z_MAJOR_GRID, + X_MINOR_GRID, + Y_MINOR_GRID, + Z_MINOR_GRID + }; + + GridWrapper(tGridType eType, const std::shared_ptr& spChart2ModelContact); + virtual ~GridWrapper() override; + + static void getDimensionAndSubGridBool( tGridType eType, sal_Int32& rnDimensionIndex, bool& rbSubGrid ); + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + tGridType m_eType; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx new file mode 100644 index 000000000..e91416821 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/LegendWrapper.cxx @@ -0,0 +1,422 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "LegendWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "WrappedCharacterHeightProperty.hxx" +#include +#include +#include "WrappedAutomaticPositionProperties.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ +namespace { + +class WrappedLegendAlignmentProperty : public WrappedProperty +{ +public: + WrappedLegendAlignmentProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + +protected: + virtual Any convertInnerToOuterValue( const Any& rInnerValue ) const override; + virtual Any convertOuterToInnerValue( const Any& rOuterValue ) const override; +}; + +} + +WrappedLegendAlignmentProperty::WrappedLegendAlignmentProperty() + : ::chart::WrappedProperty( "Alignment", "AnchorPosition" ) +{ +} + +Any WrappedLegendAlignmentProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + if( xInnerPropertySet.is() ) + { + bool bShowLegend = true; + xInnerPropertySet->getPropertyValue( "Show" ) >>= bShowLegend; + if(!bShowLegend) + { + aRet <<= css::chart::ChartLegendPosition_NONE; + } + else + { + aRet = xInnerPropertySet->getPropertyValue( m_aInnerName ); + aRet = convertInnerToOuterValue( aRet ); + } + } + return aRet; +} + +void WrappedLegendAlignmentProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if(!xInnerPropertySet.is()) + return; + + bool bNewShowLegend = true; + bool bOldShowLegend = true; + { + css::chart::ChartLegendPosition eOuterPos(css::chart::ChartLegendPosition_NONE); + if( (rOuterValue >>= eOuterPos) && eOuterPos == css::chart::ChartLegendPosition_NONE ) + bNewShowLegend = false; + xInnerPropertySet->getPropertyValue( "Show" ) >>= bOldShowLegend; + } + if(bNewShowLegend!=bOldShowLegend) + { + xInnerPropertySet->setPropertyValue( "Show", uno::Any(bNewShowLegend) ); + } + if(!bNewShowLegend) + return; + + //set corresponding LegendPosition + Any aInnerValue = convertOuterToInnerValue( rOuterValue ); + xInnerPropertySet->setPropertyValue( m_aInnerName, aInnerValue ); + + //correct LegendExpansion + chart2::LegendPosition eNewInnerPos(chart2::LegendPosition_LINE_END); + if( aInnerValue >>= eNewInnerPos ) + { + css::chart::ChartLegendExpansion eNewExpansion = + ( eNewInnerPos == chart2::LegendPosition_LINE_END || + eNewInnerPos == chart2::LegendPosition_LINE_START ) + ? css::chart::ChartLegendExpansion_HIGH + : css::chart::ChartLegendExpansion_WIDE; + + css::chart::ChartLegendExpansion eOldExpansion( css::chart::ChartLegendExpansion_HIGH ); + bool bExpansionWasSet( + xInnerPropertySet->getPropertyValue( "Expansion" ) >>= eOldExpansion ); + + if( !bExpansionWasSet || (eOldExpansion != eNewExpansion)) + xInnerPropertySet->setPropertyValue( "Expansion", uno::Any( eNewExpansion )); + } + + //correct RelativePosition + Any aRelativePosition( xInnerPropertySet->getPropertyValue("RelativePosition") ); + if(aRelativePosition.hasValue()) + { + xInnerPropertySet->setPropertyValue( "RelativePosition", Any() ); + } +} + +Any WrappedLegendAlignmentProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + css::chart::ChartLegendPosition ePos = css::chart::ChartLegendPosition_NONE; + + chart2::LegendPosition eNewPos; + if( rInnerValue >>= eNewPos ) + { + switch( eNewPos ) + { + case chart2::LegendPosition_LINE_START: + ePos = css::chart::ChartLegendPosition_LEFT; + break; + case chart2::LegendPosition_LINE_END: + ePos = css::chart::ChartLegendPosition_RIGHT; + break; + case chart2::LegendPosition_PAGE_START: + ePos = css::chart::ChartLegendPosition_TOP; + break; + case chart2::LegendPosition_PAGE_END: + ePos = css::chart::ChartLegendPosition_BOTTOM; + break; + + default: + ePos = css::chart::ChartLegendPosition_NONE; + break; + } + } + return uno::Any( ePos ); +} +Any WrappedLegendAlignmentProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + chart2::LegendPosition eNewPos = chart2::LegendPosition_LINE_END; + + css::chart::ChartLegendPosition ePos; + if( rOuterValue >>= ePos ) + { + switch( ePos ) + { + case css::chart::ChartLegendPosition_LEFT: + eNewPos = chart2::LegendPosition_LINE_START; + break; + case css::chart::ChartLegendPosition_RIGHT: + eNewPos = chart2::LegendPosition_LINE_END; + break; + case css::chart::ChartLegendPosition_TOP: + eNewPos = chart2::LegendPosition_PAGE_START; + break; + case css::chart::ChartLegendPosition_BOTTOM: + eNewPos = chart2::LegendPosition_PAGE_END; + break; + default: // NONE + break; + } + } + + return uno::Any( eNewPos ); +} +} + +namespace +{ + +enum +{ + PROP_LEGEND_ALIGNMENT, + PROP_LEGEND_EXPANSION +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Alignment", + PROP_LEGEND_ALIGNMENT, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Expansion", + PROP_LEGEND_EXPANSION, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticLegendWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedAutomaticPositionProperties::addProperties( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticLegendWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticLegendWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +LegendWrapper::LegendWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact(spChart2ModelContact) + , m_aEventListenerContainer(m_aMutex) +{ +} + +LegendWrapper::~LegendWrapper() +{ +} + +// ____ XShape ____ +awt::Point SAL_CALL LegendWrapper::getPosition() +{ + return m_spChart2ModelContact->GetLegendPosition(); +} + +void SAL_CALL LegendWrapper::setPosition( const awt::Point& aPosition ) +{ + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( xProp.is() ) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = aPageSize.Width == 0 ? 0 : double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = aPageSize.Height == 0 ? 0 : double(aPosition.Y)/double(aPageSize.Height); + xProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } +} + +awt::Size SAL_CALL LegendWrapper::getSize() +{ + return m_spChart2ModelContact->GetLegendSize(); +} + +void SAL_CALL LegendWrapper::setSize( const awt::Size& aSize ) +{ + Reference< beans::XPropertySet > xProp( getInnerPropertySet() ); + if( xProp.is() ) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + awt::Rectangle aPageRectangle( 0,0,aPageSize.Width,aPageSize.Height); + + awt::Point aPos( getPosition() ); + awt::Rectangle aNewPositionAndSize(aPos.X,aPos.Y,aSize.Width,aSize.Height); + + PositionAndSizeHelper::moveObject( OBJECTTYPE_LEGEND + , xProp, aNewPositionAndSize, awt::Rectangle(), aPageRectangle ); + } +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL LegendWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartLegend"; +} + +// ____ XComponent ____ +void SAL_CALL LegendWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL LegendWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL LegendWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//ReferenceSizePropertyProvider +void LegendWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + { + if( xProp->getPropertyValue( "ReferencePageSize" ).hasValue() ) + xProp->setPropertyValue( "ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any LegendWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp = getInnerPropertySet(); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "ReferencePageSize" ); + + return aRet; +} +awt::Size LegendWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > LegendWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + xRet.set( xDiagram->getLegend(), uno::UNO_QUERY ); + OSL_ENSURE(xRet.is(),"LegendWrapper::getInnerPropertySet() is NULL"); + return xRet; +} + +const Sequence< beans::Property >& LegendWrapper::getPropertySequence() +{ + return *StaticLegendWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > LegendWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedLegendAlignmentProperty() ); + aWrappedProperties.emplace_back( new WrappedProperty( "Expansion", "Expansion")); + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + //same problem as for wall: the defaults in the old chart are different for different charttypes, so we need to export explicitly + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("FillStyle", "FillStyle")); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty("FillColor", "FillColor")); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL LegendWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Legend"; +} + +sal_Bool SAL_CALL LegendWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LegendWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartLegend", + "com.sun.star.drawing.Shape", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx b/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx new file mode 100644 index 000000000..128c5fbcf --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/LegendWrapper.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "ReferenceSizePropertyProvider.hxx" +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class LegendWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > + , public ReferenceSizePropertyProvider +{ +public: + explicit LegendWrapper(const std::shared_ptr& spChart2ModelContact); + virtual ~LegendWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx new file mode 100644 index 000000000..3520dacb5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.cxx @@ -0,0 +1,384 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "MinMaxLineWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +struct StaticMinMaxLineWrapperDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +}; + +struct StaticMinMaxLineWrapperDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticMinMaxLineWrapperDefaults_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticMinMaxLineWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticMinMaxLineWrapperPropertyArray_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( *StaticMinMaxLineWrapperPropertyArray::get() ); + return &aPropHelper; + } +}; + +struct StaticMinMaxLineWrapperInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticMinMaxLineWrapperInfoHelper_Initializer > +{ +}; + +struct StaticMinMaxLineWrapperInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticMinMaxLineWrapperInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticMinMaxLineWrapperInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticMinMaxLineWrapperInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +MinMaxLineWrapper::MinMaxLineWrapper(const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_aWrappedLineJointProperty( "LineJoint", uno::Any( drawing::LineJoint_NONE )) +{ +} + +MinMaxLineWrapper::~MinMaxLineWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL MinMaxLineWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +void SAL_CALL MinMaxLineWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL MinMaxLineWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL MinMaxLineWrapper::getPropertySetInfo() +{ + return *StaticMinMaxLineWrapperInfo::get(); +} + +void SAL_CALL MinMaxLineWrapper::setPropertyValue( const OUString& rPropertyName, const uno::Any& rValue ) +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + const std::vector< rtl::Reference< ChartType > > & aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq( xType->getDataSeries2() ); + if(!aSeriesSeq.empty()) + { + if(aSeriesSeq[0].is()) + { + if( rPropertyName == "LineColor" ) + aSeriesSeq[0]->setPropertyValue( "Color", rValue ); + else if( rPropertyName == "LineTransparence" ) + aSeriesSeq[0]->setPropertyValue( "Transparency", rValue ); + else if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + m_aWrappedLineJointProperty.setPropertyValue( rValue, aSeriesSeq[0] ); + else + aSeriesSeq[0]->setPropertyValue( rPropertyName, rValue ); + return; + } + } + } + } +} +uno::Any SAL_CALL MinMaxLineWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + + rtl::Reference< DataSeries > xPropSet; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq( xType->getDataSeries2() ); + if(!aSeriesSeq.empty()) + { + xPropSet = aSeriesSeq[0]; + break; + } + } + } + if(xPropSet.is()) + { + if( rPropertyName == "LineColor" ) + aRet = xPropSet->getPropertyValue( "Color" ); + else if( rPropertyName == "LineTransparence" ) + aRet = xPropSet->getPropertyValue( "Transparency" ); + else if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + aRet = m_aWrappedLineJointProperty.getPropertyValue( xPropSet ); + else + aRet = xPropSet->getPropertyValue( rPropertyName ); + + } + return aRet; +} + +void SAL_CALL MinMaxLineWrapper::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +//XMultiPropertySet +//getPropertySetInfo() already declared in XPropertySet +void SAL_CALL MinMaxLineWrapper::setPropertyValues( const uno::Sequence< OUString >& rNameSeq, const uno::Sequence< uno::Any >& rValueSeq ) +{ + sal_Int32 nMinCount = std::min( rValueSeq.getLength(), rNameSeq.getLength() ); + for(sal_Int32 nN=0; nN SAL_CALL MinMaxLineWrapper::getPropertyValues( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN& /* aPropertyNames */, + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::removePropertiesChangeListener( + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL MinMaxLineWrapper::firePropertiesChangeEvent( + const uno::Sequence< OUString >& /* aPropertyNames */, + const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} + +//XPropertyState +beans::PropertyState SAL_CALL MinMaxLineWrapper::getPropertyState( const OUString& rPropertyName ) +{ + if( rPropertyName == m_aWrappedLineJointProperty.getOuterName() ) + return beans::PropertyState_DEFAULT_VALUE; + + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + + if( aDefault == aValue ) + return beans::PropertyState_DEFAULT_VALUE; + + return beans::PropertyState_DIRECT_VALUE; +} +uno::Sequence< beans::PropertyState > SAL_CALL MinMaxLineWrapper::getPropertyStates( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< beans::PropertyState > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nNgetHandleByName( rPropertyName ) ) ); + if( aFound == rStaticDefaults.end() ) + return uno::Any(); + return (*aFound).second; +} + +//XMultiPropertyStates +//getPropertyStates() already declared in XPropertyState +void SAL_CALL MinMaxLineWrapper::setAllPropertiesToDefault( ) +{ + const Sequence< beans::Property >& rPropSeq = *StaticMinMaxLineWrapperPropertyArray::get(); + for(beans::Property const & prop : rPropSeq) + { + setPropertyToDefault( prop.Name ); + } +} +void SAL_CALL MinMaxLineWrapper::setPropertiesToDefault( const uno::Sequence< OUString >& rNameSeq ) +{ + for(OUString const & s : rNameSeq) + { + setPropertyToDefault( s ); + } +} +uno::Sequence< uno::Any > SAL_CALL MinMaxLineWrapper::getPropertyDefaults( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN SAL_CALL MinMaxLineWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartLine", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.LineProperties" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx new file mode 100644 index 000000000..33cabe174 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/MinMaxLineWrapper.hxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class MinMaxLineWrapper : public cppu::BaseMutex + , public ::cppu::WeakImplHelper + < css::lang::XComponent + , css::lang::XServiceInfo + , css::beans::XPropertySet + , css::beans::XMultiPropertySet + , css::beans::XPropertyState + , css::beans::XMultiPropertyStates + > +{ +public: + explicit MinMaxLineWrapper(const std::shared_ptr& spChart2ModelContact); + virtual ~MinMaxLineWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + //XMultiPropertySet + //getPropertySetInfo() already declared in XPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + //getPropertyStates() already declared in XPropertyState + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + WrappedIgnoreProperty m_aWrappedLineJointProperty; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx b/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx new file mode 100644 index 000000000..4451c3cce --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/ReferenceSizePropertyProvider.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart::wrapper +{ +class ReferenceSizePropertyProvider +{ +public: + virtual void updateReferenceSize() = 0; + virtual css::uno::Any getReferenceSize() = 0; + virtual css::awt::Size getCurrentSizeForReference() = 0; + +protected: + ~ReferenceSizePropertyProvider() {} +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx new file mode 100644 index 000000000..d9039d879 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.cxx @@ -0,0 +1,510 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "TitleWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "WrappedCharacterHeightProperty.hxx" +#include "WrappedTextRotationProperty.hxx" +#include "WrappedAutomaticPositionProperties.hxx" +#include "WrappedScaleTextProperties.hxx" + +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ +namespace { + +class WrappedTitleStringProperty : public WrappedProperty +{ +public: + explicit WrappedTitleStringProperty( const Reference< uno::XComponentContext >& xContext ); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + Reference< uno::XComponentContext > m_xContext; +}; + +} + +WrappedTitleStringProperty::WrappedTitleStringProperty( const Reference< uno::XComponentContext >& xContext ) + : ::chart::WrappedProperty( "String", OUString() ) + , m_xContext( xContext ) +{ +} + +void WrappedTitleStringProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Reference< chart2::XTitle > xTitle(xInnerPropertySet,uno::UNO_QUERY); + if(xTitle.is()) + { + OUString aString; + rOuterValue >>= aString; + TitleHelper::setCompleteString( aString, xTitle, m_xContext ); + } +} +Any WrappedTitleStringProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + Reference< chart2::XTitle > xTitle(xInnerPropertySet,uno::UNO_QUERY); + if(xTitle.is()) + { + const Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + + OUStringBuffer aBuf; + for( Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + aBuf.append( formattedStr->getString()); + } + aRet <<= aBuf.makeStringAndClear(); + } + return aRet; +} +Any WrappedTitleStringProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( OUString() );//default title is an empty String +} + +namespace { + +class WrappedStackedTextProperty : public WrappedProperty +{ +public: + WrappedStackedTextProperty(); +}; + +} + +WrappedStackedTextProperty::WrappedStackedTextProperty() + : ::chart::WrappedProperty( "StackedText", "StackCharacters" ) +{ +} + +}// end namespace chart + +namespace +{ + +enum +{ + PROP_TITLE_STRING, + PROP_TITLE_TEXT_ROTATION, + PROP_TITLE_TEXT_STACKED +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "String", + PROP_TITLE_STRING, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_TITLE_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackedText", + PROP_TITLE_TEXT_STACKED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticTitleWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + ::chart::wrapper::WrappedAutomaticPositionProperties::addProperties( aProperties ); + ::chart::wrapper::WrappedScaleTextProperties::addProperties( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticTitleWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticTitleWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +TitleWrapper::TitleWrapper( ::chart::TitleHelper::eTitleType eTitleType, + const std::shared_ptr& spChart2ModelContact ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_eTitleType(eTitleType) +{ + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + if( !getTitleObject().is() ) //#i83831# create an empty title at the model, thus references to properties can be mapped correctly + TitleHelper::createTitle( m_eTitleType, OUString(), m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); +} + +TitleWrapper::~TitleWrapper() +{ +} + +// ____ XShape ____ +awt::Point SAL_CALL TitleWrapper::getPosition() +{ + return m_spChart2ModelContact->GetTitlePosition( getTitleObject() ); +} + +void SAL_CALL TitleWrapper::setPosition( const awt::Point& aPosition ) +{ + Reference< beans::XPropertySet > xPropertySet( getInnerPropertySet() ); + if(xPropertySet.is()) + { + awt::Size aPageSize( m_spChart2ModelContact->GetPageSize() ); + + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + aRelativePosition.Primary = double(aPosition.X)/double(aPageSize.Width); + aRelativePosition.Secondary = double(aPosition.Y)/double(aPageSize.Height); + xPropertySet->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } +} + +awt::Size SAL_CALL TitleWrapper::getSize() +{ + return m_spChart2ModelContact->GetTitleSize( getTitleObject() ); +} + +void SAL_CALL TitleWrapper::setSize( const awt::Size& /*aSize*/ ) +{ + OSL_FAIL( "trying to set size of title" ); +} + +// ____ XShapeDescriptor (base of XShape) ____ +OUString SAL_CALL TitleWrapper::getShapeType() +{ + return "com.sun.star.chart.ChartTitle"; +} + +// ____ XComponent ____ +void SAL_CALL TitleWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL TitleWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL TitleWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +Reference< beans::XPropertySet > TitleWrapper::getFirstCharacterPropertySet() +{ + Reference< beans::XPropertySet > xProp; + + Reference< chart2::XTitle > xTitle( getTitleObject() ); + if( xTitle.is()) + { + Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + if( aStrings.hasElements() ) + xProp.set( aStrings[0], uno::UNO_QUERY ); + } + + return xProp; +} + +void TitleWrapper::getFastCharacterPropertyValue( sal_Int32 nHandle, Any& rValue ) +{ + OSL_ASSERT( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && + nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); + + Reference< beans::XPropertySet > xProp = getFirstCharacterPropertySet(); + Reference< beans::XFastPropertySet > xFastProp( xProp, uno::UNO_QUERY ); + if(xProp.is()) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + if( pWrappedProperty ) + { + rValue = pWrappedProperty->getPropertyValue( xProp ); + } + else if( xFastProp.is() ) + { + rValue = xFastProp->getFastPropertyValue( nHandle ); + } + } + +} + +void TitleWrapper::setFastCharacterPropertyValue( + sal_Int32 nHandle, const Any& rValue ) +{ + OSL_ASSERT( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && + nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); + + Reference< chart2::XTitle > xTitle( getTitleObject() ); + if( !xTitle.is()) + return; + + const Sequence< Reference< chart2::XFormattedString > > aStrings( xTitle->getText()); + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + + for( Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + Reference< beans::XFastPropertySet > xFastPropertySet( formattedStr, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xPropSet( xFastPropertySet, uno::UNO_QUERY ); + + if( pWrappedProperty ) + pWrappedProperty->setPropertyValue( rValue, xPropSet ); + else if( xFastPropertySet.is() ) + xFastPropertySet->setFastPropertyValue( nHandle, rValue ); + } +} + +// WrappedPropertySet + +void SAL_CALL TitleWrapper::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + setFastCharacterPropertyValue( nHandle, rValue ); + } + else + WrappedPropertySet::setPropertyValue( rPropertyName, rValue ); +} + +Any SAL_CALL TitleWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + getFastCharacterPropertyValue( nHandle, aRet ); + else + aRet = WrappedPropertySet::getPropertyValue( rPropertyName ); + return aRet; +} + +beans::PropertyState SAL_CALL TitleWrapper::getPropertyState( const OUString& rPropertyName ) +{ + beans::PropertyState aState( beans::PropertyState_DIRECT_VALUE ); + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + if( xPropState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aState = pWrappedProperty->getPropertyState( xPropState ); + else + aState = xPropState->getPropertyState( rPropertyName ); + } + } + else + aState = WrappedPropertySet::getPropertyState( rPropertyName ); + + return aState; +} +void SAL_CALL TitleWrapper::setPropertyToDefault( const OUString& rPropertyName ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Any aDefault = getPropertyDefault( rPropertyName ); + setFastCharacterPropertyValue( nHandle, aDefault ); + } + else + WrappedPropertySet::setPropertyToDefault( rPropertyName ); +} +Any SAL_CALL TitleWrapper::getPropertyDefault( const OUString& rPropertyName ) +{ + Any aRet; + + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertyState > xPropState( getFirstCharacterPropertySet(), uno::UNO_QUERY ); + if( xPropState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyDefault(xPropState); + else + aRet = xPropState->getPropertyDefault( rPropertyName ); + } + } + else + aRet = WrappedPropertySet::getPropertyDefault( rPropertyName ); + + return aRet; +} + +void SAL_CALL TitleWrapper::addPropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& xListener ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + if( xPropSet.is() ) + xPropSet->addPropertyChangeListener( rPropertyName, xListener ); + } + else + WrappedPropertySet::addPropertyChangeListener( rPropertyName, xListener ); +} +void SAL_CALL TitleWrapper::removePropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& xListener ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + if( CharacterProperties::IsCharacterPropertyHandle( nHandle ) ) + { + Reference< beans::XPropertySet > xPropSet = getFirstCharacterPropertySet(); + if( xPropSet.is() ) + xPropSet->removePropertyChangeListener( rPropertyName, xListener ); + } + else + WrappedPropertySet::removePropertyChangeListener( rPropertyName, xListener ); +} + +//ReferenceSizePropertyProvider +void TitleWrapper::updateReferenceSize() +{ + Reference< beans::XPropertySet > xProp( getTitleObject(), uno::UNO_QUERY ); + if( xProp.is() ) + { + if( xProp->getPropertyValue( "ReferencePageSize" ).hasValue() ) + xProp->setPropertyValue( "ReferencePageSize", uno::Any( + m_spChart2ModelContact->GetPageSize() )); + } +} +Any TitleWrapper::getReferenceSize() +{ + Any aRet; + Reference< beans::XPropertySet > xProp( getTitleObject(), uno::UNO_QUERY ); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "ReferencePageSize" ); + + return aRet; +} +awt::Size TitleWrapper::getCurrentSizeForReference() +{ + return m_spChart2ModelContact->GetPageSize(); +} + +Reference< chart2::XTitle > TitleWrapper::getTitleObject() +{ + return TitleHelper::getTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ); +} + +// WrappedPropertySet + +Reference< beans::XPropertySet > TitleWrapper::getInnerPropertySet() +{ + return Reference< beans::XPropertySet >( getTitleObject(), uno::UNO_QUERY ); +} + +const Sequence< beans::Property >& TitleWrapper::getPropertySequence() +{ + return *StaticTitleWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > TitleWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + aWrappedProperties.emplace_back( new WrappedTitleStringProperty( m_spChart2ModelContact->m_xContext ) ); + aWrappedProperties.emplace_back( new WrappedTextRotationProperty( true ) ); + aWrappedProperties.emplace_back( new WrappedStackedTextProperty() ); + WrappedCharacterHeightProperty::addWrappedProperties( aWrappedProperties, this ); + WrappedAutomaticPositionProperties::addWrappedProperties( aWrappedProperties ); + WrappedScaleTextProperties::addWrappedProperties( aWrappedProperties, m_spChart2ModelContact ); + + return aWrappedProperties; +} + +OUString SAL_CALL TitleWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.Title"; +} + +sal_Bool SAL_CALL TitleWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL TitleWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartTitle", + "com.sun.star.drawing.Shape", + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.style.CharacterProperties" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx b/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx new file mode 100644 index 000000000..5cc3ed477 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/TitleWrapper.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "ReferenceSizePropertyProvider.hxx" +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::chart2 { class XTitle; } + +namespace chart::wrapper +{ + +class TitleWrapper final : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::drawing::XShape + , css::lang::XComponent + , css::lang::XServiceInfo + > + , public ReferenceSizePropertyProvider +{ +public: + TitleWrapper( ::chart::TitleHelper::eTitleType eTitleType, + const std::shared_ptr& spChart2ModelContact ); + virtual ~TitleWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //ReferenceSizePropertyProvider + virtual void updateReferenceSize() override; + virtual css::uno::Any getReferenceSize() override; + virtual css::awt::Size getCurrentSizeForReference() override; + +private: + // ____ XShape ____ + virtual css::awt::Point SAL_CALL getPosition() override; + virtual void SAL_CALL setPosition( const css::awt::Point& aPosition ) override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL setSize( const css::awt::Size& aSize ) override; + + // ____ XShapeDescriptor (base of XShape) ____ + virtual OUString SAL_CALL getShapeType() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // character properties have to be handled differently (via the XFormattedString elements) + void getFastCharacterPropertyValue( sal_Int32 nHandle, css::uno::Any& rValue ); + /// @throws css::uno::Exception + void setFastCharacterPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ); + + // ____ WrappedPropertySet ____ + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + + css::uno::Reference< css::beans::XPropertySet > getFirstCharacterPropertySet(); + + css::uno::Reference< css::chart2::XTitle > getTitleObject(); + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + ::chart::TitleHelper::eTitleType m_eTitleType; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx new file mode 100644 index 000000000..c1bde1473 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.cxx @@ -0,0 +1,356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "UpDownBarWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace +{ + +struct StaticUpDownBarWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticUpDownBarWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticUpDownBarWrapperPropertyArray_Initializer > +{ +}; + +struct StaticUpDownBarWrapperInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( *StaticUpDownBarWrapperPropertyArray::get() ); + return &aPropHelper; + } +}; + +struct StaticUpDownBarWrapperInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticUpDownBarWrapperInfoHelper_Initializer > +{ +}; + +struct StaticUpDownBarWrapperInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticUpDownBarWrapperInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticUpDownBarWrapperInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticUpDownBarWrapperInfo_Initializer > +{ +}; + +struct StaticUpDownBarWrapperDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + } +}; + +struct StaticUpDownBarWrapperDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticUpDownBarWrapperDefaults_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +UpDownBarWrapper::UpDownBarWrapper( + bool bUp, const std::shared_ptr& spChart2ModelContact) + : m_spChart2ModelContact( spChart2ModelContact ) + , m_aEventListenerContainer( m_aMutex ) + , m_aPropertySetName( bUp ? OUString( "WhiteDay" ) : OUString( "BlackDay" )) +{ +} + +UpDownBarWrapper::~UpDownBarWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL UpDownBarWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); +} + +void SAL_CALL UpDownBarWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL UpDownBarWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL UpDownBarWrapper::getPropertySetInfo() +{ + return *StaticUpDownBarWrapperInfo::get(); +} +void SAL_CALL UpDownBarWrapper::setPropertyValue( const OUString& rPropertyName, const uno::Any& rValue ) +{ + Reference< beans::XPropertySet > xPropSet; + + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + xType->getPropertyValue( m_aPropertySetName ) >>= xPropSet; + } + } + if(xPropSet.is()) + xPropSet->setPropertyValue( rPropertyName, rValue ); +} +uno::Any SAL_CALL UpDownBarWrapper::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + + Reference< beans::XPropertySet > xPropSet; + + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( rtl::Reference const & xType : aTypes ) + { + if( xType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + xType->getPropertyValue( m_aPropertySetName ) >>= xPropSet; + } + } + if(xPropSet.is()) + aRet = xPropSet->getPropertyValue( rPropertyName ); + return aRet; +} + +void SAL_CALL UpDownBarWrapper::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< beans::XPropertyChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener >& /*aListener*/ ) +{ + OSL_FAIL("not implemented"); +} + +//XMultiPropertySet +//getPropertySetInfo() already declared in XPropertySet +void SAL_CALL UpDownBarWrapper::setPropertyValues( const uno::Sequence< OUString >& rNameSeq, const uno::Sequence< uno::Any >& rValueSeq ) +{ + sal_Int32 nMinCount = std::min( rValueSeq.getLength(), rNameSeq.getLength() ); + for(sal_Int32 nN=0; nN SAL_CALL UpDownBarWrapper::getPropertyValues( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN& /* aPropertyNames */, const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL UpDownBarWrapper::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */, const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} + +//XPropertyState +beans::PropertyState SAL_CALL UpDownBarWrapper::getPropertyState( const OUString& rPropertyName ) +{ + uno::Any aDefault( getPropertyDefault( rPropertyName ) ); + uno::Any aValue( getPropertyValue( rPropertyName ) ); + + if( aDefault == aValue ) + return beans::PropertyState_DEFAULT_VALUE; + + return beans::PropertyState_DIRECT_VALUE; +} +uno::Sequence< beans::PropertyState > SAL_CALL UpDownBarWrapper::getPropertyStates( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< beans::PropertyState > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nNgetHandleByName( rPropertyName ) ) ); + if( aFound == rStaticDefaults.end() ) + return uno::Any(); + return (*aFound).second; +} + +//XMultiPropertyStates +//getPropertyStates() already declared in XPropertyState +void SAL_CALL UpDownBarWrapper::setAllPropertiesToDefault( ) +{ + const Sequence< beans::Property >& rPropSeq = *StaticUpDownBarWrapperPropertyArray::get(); + for(beans::Property const & prop : rPropSeq) + { + setPropertyToDefault( prop.Name ); + } +} +void SAL_CALL UpDownBarWrapper::setPropertiesToDefault( const uno::Sequence< OUString >& rNameSeq ) +{ + for(OUString const & s : rNameSeq) + { + setPropertyToDefault( s ); + } +} +uno::Sequence< uno::Any > SAL_CALL UpDownBarWrapper::getPropertyDefaults( const uno::Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN SAL_CALL UpDownBarWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.chart.ChartArea", + "com.sun.star.drawing.LineProperties", + "com.sun.star.drawing.FillProperties", + "com.sun.star.xml.UserDefinedAttributesSupplier" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx new file mode 100644 index 000000000..63e1c44db --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/UpDownBarWrapper.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class UpDownBarWrapper : public cppu::BaseMutex + , public ::cppu::WeakImplHelper + < css::lang::XComponent + , css::lang::XServiceInfo + , css::beans::XPropertySet + , css::beans::XMultiPropertySet + , css::beans::XPropertyState + , css::beans::XMultiPropertyStates + > +{ +public: + UpDownBarWrapper(bool bUp, const std::shared_ptr& spChart2ModelContact); + virtual ~UpDownBarWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< + css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< + css::lang::XEventListener >& aListener ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + //XMultiPropertySet + //getPropertySetInfo() already declared in XPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + //getPropertyStates() already declared in XPropertyState + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + OUString m_aPropertySetName; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx new file mode 100644 index 000000000..9131bec9b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.cxx @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WallFloorWrapper.hxx" +#include "Chart2ModelContact.hxx" +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +struct StaticWallFloorWrapperPropertyArray_Initializer +{ + Sequence< Property >* operator()() + { + static Sequence< Property > aPropSeq( lcl_GetPropertySequence() ); + return &aPropSeq; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticWallFloorWrapperPropertyArray : public rtl::StaticAggregate< Sequence< Property >, StaticWallFloorWrapperPropertyArray_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart::wrapper +{ + +WallFloorWrapper::WallFloorWrapper( bool bWall, + const std::shared_ptr& spChart2ModelContact ) : + m_spChart2ModelContact( spChart2ModelContact ), + m_aEventListenerContainer( m_aMutex ), + m_bWall( bWall ) + +{ +} + +WallFloorWrapper::~WallFloorWrapper() +{ +} + +// ____ XComponent ____ +void SAL_CALL WallFloorWrapper::dispose() +{ + Reference< uno::XInterface > xSource( static_cast< ::cppu::OWeakObject* >( this ) ); + m_aEventListenerContainer.disposeAndClear( lang::EventObject( xSource ) ); + + MutexGuard aGuard( m_aMutex); + clearWrappedPropertySet(); +} + +void SAL_CALL WallFloorWrapper::addEventListener( + const Reference< lang::XEventListener >& xListener ) +{ + m_aEventListenerContainer.addInterface( xListener ); +} + +void SAL_CALL WallFloorWrapper::removeEventListener( + const Reference< lang::XEventListener >& aListener ) +{ + m_aEventListenerContainer.removeInterface( aListener ); +} + +// WrappedPropertySet +Reference< beans::XPropertySet > WallFloorWrapper::getInnerPropertySet() +{ + Reference< beans::XPropertySet > xRet; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + if( m_bWall ) + xRet.set( xDiagram->getWall() ); + else + xRet.set( xDiagram->getFloor() ); + } + + return xRet; +} + +const Sequence< beans::Property >& WallFloorWrapper::getPropertySequence() +{ + return *StaticWallFloorWrapperPropertyArray::get(); +} + +std::vector< std::unique_ptr > WallFloorWrapper::createWrappedProperties() +{ + std::vector< std::unique_ptr > aWrappedProperties; + + // use direct state always, so that in XML the value is always + // exported. Because in the old chart the defaults is as follows: + // Floor: SOLID (new and old model default), Wall: NONE, except for some chart types (line, scatter) + if( m_bWall ) + aWrappedProperties.emplace_back( new WrappedDirectStateProperty( "FillStyle", "FillStyle" )); + aWrappedProperties.emplace_back( new WrappedDirectStateProperty( "FillColor", "FillColor" )); + + return aWrappedProperties; +} + +OUString SAL_CALL WallFloorWrapper::getImplementationName() +{ + return "com.sun.star.comp.chart.WallOrFloor"; +} + +sal_Bool SAL_CALL WallFloorWrapper::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL WallFloorWrapper::getSupportedServiceNames() +{ + return { + "com.sun.star.xml.UserDefinedAttributesSupplier", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx new file mode 100644 index 000000000..3df4a9f1a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WallFloorWrapper.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class WallFloorWrapper : public ::cppu::ImplInheritanceHelper< + WrappedPropertySet + , css::lang::XComponent + , css::lang::XServiceInfo + > +{ +public: + WallFloorWrapper(bool bWall, const std::shared_ptr& spChart2ModelContact); + virtual ~WallFloorWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + +protected: + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + ::comphelper::OInterfaceContainerHelper3 m_aEventListenerContainer; + + bool m_bWall; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx new file mode 100644 index 000000000..24a6dfb78 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.cxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedAddInProperty.hxx" +#include +#include + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using namespace ::com::sun::star; + +namespace chart::wrapper +{ + +WrappedAddInProperty::WrappedAddInProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "AddIn", OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedAddInProperty::~WrappedAddInProperty() +{ +} + +void WrappedAddInProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Reference< util::XRefreshable > xAddIn; + if( ! (rOuterValue >>= xAddIn) ) + throw lang::IllegalArgumentException( "AddIn properties require type XRefreshable", nullptr, 0 ); + + m_rChartDocumentWrapper.setAddIn( xAddIn ); +} + +Any WrappedAddInProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getAddIn() ); +} + +WrappedBaseDiagramProperty::WrappedBaseDiagramProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "BaseDiagram" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedBaseDiagramProperty::~WrappedBaseDiagramProperty() +{ +} + +void WrappedBaseDiagramProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + OUString aBaseDiagram; + if( ! (rOuterValue >>= aBaseDiagram) ) + throw lang::IllegalArgumentException( "BaseDiagram properties require type OUString", nullptr, 0 ); + + m_rChartDocumentWrapper.setBaseDiagram( aBaseDiagram ); +} + +Any WrappedBaseDiagramProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getBaseDiagram() ); +} + +WrappedAdditionalShapesProperty::WrappedAdditionalShapesProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "AdditionalShapes" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedAdditionalShapesProperty::~WrappedAdditionalShapesProperty() +{ +} + +void WrappedAdditionalShapesProperty::setPropertyValue( const Any& /*rOuterValue*/, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + throw lang::IllegalArgumentException( "AdditionalShapes is a read only property", nullptr, 0 ); +} + +Any WrappedAdditionalShapesProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getAdditionalShapes() ); +} + +WrappedRefreshAddInAllowedProperty::WrappedRefreshAddInAllowedProperty( ChartDocumentWrapper& rChartDocumentWrapper ) + : ::chart::WrappedProperty( "RefreshAddInAllowed" , OUString() ) + , m_rChartDocumentWrapper( rChartDocumentWrapper ) +{ +} +WrappedRefreshAddInAllowedProperty::~WrappedRefreshAddInAllowedProperty() +{ +} + +void WrappedRefreshAddInAllowedProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + bool bUpdateAddIn = true; + if( ! (rOuterValue >>= bUpdateAddIn) ) + throw lang::IllegalArgumentException( "The property RefreshAddInAllowed requires type boolean", nullptr, 0 ); + + m_rChartDocumentWrapper.setUpdateAddIn( bUpdateAddIn ); +} + +Any WrappedRefreshAddInAllowedProperty::getPropertyValue( const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + return uno::Any( m_rChartDocumentWrapper.getUpdateAddIn() ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx new file mode 100644 index 000000000..b87ab15d7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAddInProperty.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart::wrapper { class ChartDocumentWrapper; } + +namespace chart::wrapper +{ + +class WrappedAddInProperty : public WrappedProperty +{ +public: + explicit WrappedAddInProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedAddInProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedBaseDiagramProperty : public WrappedProperty +{ +public: + explicit WrappedBaseDiagramProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedBaseDiagramProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedAdditionalShapesProperty : public WrappedProperty +{ +public: + explicit WrappedAdditionalShapesProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedAdditionalShapesProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + +class WrappedRefreshAddInAllowedProperty : public WrappedProperty +{ +public: + explicit WrappedRefreshAddInAllowedProperty( ChartDocumentWrapper& rChartDocumentWrapper ); + virtual ~WrappedRefreshAddInAllowedProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + ChartDocumentWrapper& m_rChartDocumentWrapper; +}; + + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx new file mode 100644 index 000000000..2bfb5ed42 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.cxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedAutomaticPositionProperties.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedAutomaticPositionProperty : public WrappedProperty +{ +public: + WrappedAutomaticPositionProperty(); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; +}; + +} + +WrappedAutomaticPositionProperty::WrappedAutomaticPositionProperty() + : ::chart::WrappedProperty( "AutomaticPosition" , OUString() ) +{ +} + +void WrappedAutomaticPositionProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = true; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Property AutomaticPosition requires value of type boolean", nullptr, 0 ); + + try + { + if( bNewValue ) + { + Any aRelativePosition( xInnerPropertySet->getPropertyValue( "RelativePosition" ) ); + if( aRelativePosition.hasValue() ) + xInnerPropertySet->setPropertyValue( "RelativePosition", Any() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedAutomaticPositionProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + Any aRelativePosition( xInnerPropertySet->getPropertyValue( "RelativePosition" ) ); + if( !aRelativePosition.hasValue() ) + aRet <<= true; + } + return aRet; +} + +Any WrappedAutomaticPositionProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace +{ +enum +{ + PROP_CHART_AUTOMATIC_POSITION = FAST_PROPERTY_ID_START_CHART_AUTOPOSITION_PROP +}; + +}//anonymous namespace + +void WrappedAutomaticPositionProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AutomaticPosition", + PROP_CHART_AUTOMATIC_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedAutomaticPositionProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList ) +{ + rList.emplace_back( new WrappedAutomaticPositionProperty() ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx new file mode 100644 index 000000000..a98a0aa72 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAutomaticPositionProperties.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace chart +{ +class WrappedProperty; +} +namespace com::sun::star::beans +{ +struct Property; +} + +namespace chart::wrapper +{ +class WrappedAutomaticPositionProperties +{ +public: + static void addProperties(std::vector& rOutProperties); + static void addWrappedProperties(std::vector>& rList); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx new file mode 100644 index 000000000..4280fc4c0 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.cxx @@ -0,0 +1,406 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "WrappedAxisAndGridExistenceProperties.hxx" +#include +#include +#include +#include +#include "Chart2ModelContact.hxx" +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +namespace { + +class WrappedAxisAndGridExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisAndGridExistenceProperty( bool bAxis, bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + bool m_bAxis; + bool m_bMain; + sal_Int32 m_nDimensionIndex; +}; + +} + +void WrappedAxisAndGridExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 0, spChart2ModelContact ) );//x axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, false, 0, spChart2ModelContact ) );//x secondary axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 0, spChart2ModelContact ) );//x grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 0, spChart2ModelContact ) );//x help grid + + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 1, spChart2ModelContact ) );//y axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, false, 1, spChart2ModelContact ) );//y secondary axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 1, spChart2ModelContact ) );//y grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 1, spChart2ModelContact ) );//y help grid + + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( true, true, 2, spChart2ModelContact ) );//z axis + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, true, 2, spChart2ModelContact ) );//z grid + rList.emplace_back( new WrappedAxisAndGridExistenceProperty( false, false, 2, spChart2ModelContact ) );//z help grid +} + +WrappedAxisAndGridExistenceProperty::WrappedAxisAndGridExistenceProperty( bool bAxis, bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr& spChart2ModelContact ) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_bAxis( bAxis ) + , m_bMain( bMain ) + , m_nDimensionIndex( nDimensionIndex ) +{ + switch( m_nDimensionIndex ) + { + case 0: + { + if( m_bAxis ) + { + if( m_bMain ) + m_aOuterName = "HasXAxis"; + else + m_aOuterName = "HasSecondaryXAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasXAxisGrid"; + else + m_aOuterName = "HasXAxisHelpGrid"; + } + } + break; + case 2: + { + if( m_bAxis ) + { + OSL_ENSURE(m_bMain,"there is no secondary z axis at the old api"); + m_bMain = true; + m_aOuterName = "HasZAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasZAxisGrid"; + else + m_aOuterName = "HasZAxisHelpGrid"; + } + } + break; + default: + { + if( m_bAxis ) + { + if( m_bMain ) + m_aOuterName = "HasYAxis"; + else + m_aOuterName = "HasSecondaryYAxis"; + } + else + { + if( m_bMain ) + m_aOuterName = "HasYAxisGrid"; + else + m_aOuterName = "HasYAxisHelpGrid"; + } + } + break; + } +} + +void WrappedAxisAndGridExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( bNewValue ) + { + if( m_bAxis ) + AxisHelper::showAxis( m_nDimensionIndex, m_bMain, xDiagram, m_spChart2ModelContact->m_xContext ); + else + AxisHelper::showGrid( m_nDimensionIndex, 0, m_bMain, xDiagram ); + } + else + { + if( m_bAxis ) + AxisHelper::hideAxis( m_nDimensionIndex, m_bMain, xDiagram ); + else + AxisHelper::hideGrid( m_nDimensionIndex, 0, m_bMain, xDiagram ); + } +} + +Any WrappedAxisAndGridExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + Any aRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if(m_bAxis) + { + bool bShown = AxisHelper::isAxisShown( m_nDimensionIndex, m_bMain, xDiagram ); + aRet <<= bShown; + } + else + { + bool bShown = AxisHelper::isGridShown( m_nDimensionIndex, 0, m_bMain, xDiagram ); + aRet <<= bShown; + } + return aRet; +} + +Any WrappedAxisAndGridExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +class WrappedAxisTitleExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisTitleExistenceProperty( sal_Int32 nTitleIndex + , const std::shared_ptr& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + TitleHelper::eTitleType m_eTitleType; +}; + +} + +void WrappedAxisTitleExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 0, spChart2ModelContact ) );//x axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 1, spChart2ModelContact ) );//y axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 2, spChart2ModelContact ) );//z axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 3, spChart2ModelContact ) );//secondary x axis title + rList.emplace_back( new WrappedAxisTitleExistenceProperty( 4, spChart2ModelContact ) );//secondary y axis title +} + +WrappedAxisTitleExistenceProperty::WrappedAxisTitleExistenceProperty(sal_Int32 nTitleIndex + , const std::shared_ptr& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eTitleType( TitleHelper::Y_AXIS_TITLE ) +{ + switch( nTitleIndex ) + { + case 0: + m_aOuterName = "HasXAxisTitle"; + m_eTitleType = TitleHelper::X_AXIS_TITLE; + break; + case 2: + m_aOuterName = "HasZAxisTitle"; + m_eTitleType = TitleHelper::Z_AXIS_TITLE; + break; + case 3: + m_aOuterName = "HasSecondaryXAxisTitle"; + m_eTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + break; + case 4: + m_aOuterName = "HasSecondaryYAxisTitle"; + m_eTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + break; + default: + m_aOuterName = "HasYAxisTitle"; + m_eTitleType = TitleHelper::Y_AXIS_TITLE; + break; + } +} + +void WrappedAxisTitleExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + if( bNewValue ) + { + TitleHelper::createTitle( m_eTitleType, OUString() + , m_spChart2ModelContact->getDocumentModel(), m_spChart2ModelContact->m_xContext ); + } + else + { + TitleHelper::removeTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ); + } +} + +Any WrappedAxisTitleExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bHasTitle = false; + + Reference< chart2::XTitle > xTitle( TitleHelper::getTitle( m_eTitleType, m_spChart2ModelContact->getDocumentModel() ) ); + if( xTitle.is() && !TitleHelper::getCompleteString( xTitle ).isEmpty() ) + bHasTitle = true; + + Any aRet; + aRet <<= bHasTitle; + return aRet; + +} + +Any WrappedAxisTitleExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace { + +class WrappedAxisLabelExistenceProperty : public WrappedProperty +{ +public: + WrappedAxisLabelExistenceProperty( bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + bool m_bMain; + sal_Int32 m_nDimensionIndex; +}; + +} + +void WrappedAxisLabelExistenceProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 0, spChart2ModelContact ) );//x axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 1, spChart2ModelContact ) );//y axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( true, 2, spChart2ModelContact ) );//z axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( false, 0, spChart2ModelContact ) );//secondary x axis + rList.emplace_back( new WrappedAxisLabelExistenceProperty( false, 1, spChart2ModelContact ) );//secondary y axis +} + +WrappedAxisLabelExistenceProperty::WrappedAxisLabelExistenceProperty(bool bMain, sal_Int32 nDimensionIndex + , const std::shared_ptr& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_bMain( bMain ) + , m_nDimensionIndex( nDimensionIndex ) +{ + switch( m_nDimensionIndex ) + { + case 0: + m_aOuterName = m_bMain ? std::u16string_view(u"HasXAxisDescription") : std::u16string_view(u"HasSecondaryXAxisDescription"); + break; + case 2: + OSL_ENSURE(m_bMain,"there is no description available for a secondary z axis"); + m_aOuterName = "HasZAxisDescription"; + break; + default: + m_aOuterName = m_bMain ? std::u16string_view(u"HasYAxisDescription") : std::u16string_view(u"HasSecondaryYAxisDescription"); + break; + } +} + +void WrappedAxisLabelExistenceProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "Has axis or grid properties require boolean values", nullptr, 0 ); + + bool bOldValue = false; + getPropertyValue( xInnerPropertySet ) >>= bOldValue; + + if( bOldValue == bNewValue ) + return; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< Axis > xProp = AxisHelper::getAxis( m_nDimensionIndex, m_bMain, xDiagram ); + if( !xProp.is() && bNewValue ) + { + //create axis if needed + xProp = AxisHelper::createAxis( m_nDimensionIndex, m_bMain, xDiagram, m_spChart2ModelContact->m_xContext ); + if( xProp.is() ) + xProp->setPropertyValue( "Show", uno::Any( false ) ); + } + if( xProp.is() ) + xProp->setPropertyValue( "DisplayLabels", rOuterValue ); +} + +Any WrappedAxisLabelExistenceProperty::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + Any aRet; + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + rtl::Reference< Axis > xProp = AxisHelper::getAxis( m_nDimensionIndex, m_bMain, xDiagram ); + if( xProp.is() ) + aRet = xProp->getPropertyValue( "DisplayLabels" ); + else + aRet <<= false; + return aRet; +} + +Any WrappedAxisLabelExistenceProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= true; + return aRet; +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx new file mode 100644 index 000000000..c15bee711 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedAxisAndGridExistenceProperties.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedAxisAndGridExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedAxisTitleExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedAxisLabelExistenceProperties +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx new file mode 100644 index 000000000..67ea51b0e --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedCharacterHeightProperty.hxx" +#include +#include "ReferenceSizePropertyProvider.hxx" +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ +WrappedCharacterHeightProperty_Base::WrappedCharacterHeightProperty_Base( + const OUString& rOuterEqualsInnerName + , ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedProperty( rOuterEqualsInnerName, rOuterEqualsInnerName ) + , m_pRefSizePropProvider( pRefSizePropProvider ) +{ +} +WrappedCharacterHeightProperty_Base::~WrappedCharacterHeightProperty_Base() +{ +} + +void WrappedCharacterHeightProperty::addWrappedProperties( std::vector< std::unique_ptr >& rList + , ReferenceSizePropertyProvider* pRefSizePropProvider ) +{ + rList.emplace_back( new WrappedCharacterHeightProperty( pRefSizePropProvider ) ); + rList.emplace_back( new WrappedAsianCharacterHeightProperty( pRefSizePropProvider ) ); + rList.emplace_back( new WrappedComplexCharacterHeightProperty( pRefSizePropProvider ) ); +} + +void WrappedCharacterHeightProperty_Base::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if(xInnerPropertySet.is()) + { + if( m_pRefSizePropProvider ) + m_pRefSizePropProvider->updateReferenceSize(); + xInnerPropertySet->setPropertyValue( m_aInnerName, rOuterValue ); + } +} + +Any WrappedCharacterHeightProperty_Base::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + if( xInnerPropertySet.is() ) + { + aRet = xInnerPropertySet->getPropertyValue( m_aInnerName ); + float fHeight = 0; + if( aRet >>= fHeight ) + { + if( m_pRefSizePropProvider ) + { + awt::Size aReferenceSize; + if( m_pRefSizePropProvider->getReferenceSize() >>= aReferenceSize ) + { + awt::Size aCurrentSize = m_pRefSizePropProvider->getCurrentSizeForReference(); + aRet <<= static_cast< float >( + RelativeSizeHelper::calculate( fHeight, aReferenceSize, aCurrentSize )); + } + } + } + } + return aRet; +} + +Any WrappedCharacterHeightProperty_Base::getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + Any aRet; + if( xInnerPropertyState.is() ) + { + aRet = xInnerPropertyState->getPropertyDefault( m_aInnerName ); + } + return aRet; +} + +beans::PropertyState WrappedCharacterHeightProperty_Base::getPropertyState( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return beans::PropertyState_DIRECT_VALUE; +} + +Any WrappedCharacterHeightProperty_Base::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + OSL_FAIL("should not be used: WrappedCharacterHeightProperty_Base::convertInnerToOuterValue - check if you miss data"); + return rInnerValue; +} +Any WrappedCharacterHeightProperty_Base::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + OSL_FAIL("should not be used: WrappedCharacterHeightProperty_Base::convertOuterToInnerValue - check if you miss data"); + return rOuterValue; +} + +WrappedCharacterHeightProperty::WrappedCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeight", pRefSizePropProvider ) +{ +} +WrappedCharacterHeightProperty::~WrappedCharacterHeightProperty() +{ +} + +WrappedAsianCharacterHeightProperty::WrappedAsianCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeightAsian", pRefSizePropProvider ) +{ +} +WrappedAsianCharacterHeightProperty::~WrappedAsianCharacterHeightProperty() +{ +} + +WrappedComplexCharacterHeightProperty::WrappedComplexCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ) + : WrappedCharacterHeightProperty_Base( "CharHeightComplex", pRefSizePropProvider ) +{ +} +WrappedComplexCharacterHeightProperty::~WrappedComplexCharacterHeightProperty() +{ +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx new file mode 100644 index 000000000..7eee90a2c --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedCharacterHeightProperty.hxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace chart::wrapper +{ + +class ReferenceSizePropertyProvider; + +class WrappedCharacterHeightProperty_Base : public WrappedProperty +{ +public: + WrappedCharacterHeightProperty_Base( const OUString& rOuterEqualsInnerName, ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedCharacterHeightProperty_Base() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::beans::PropertyState getPropertyState( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +protected: + virtual css::uno::Any convertInnerToOuterValue( const css::uno::Any& rInnerValue ) const override; + virtual css::uno::Any convertOuterToInnerValue( const css::uno::Any& rOuterValue ) const override; + +protected: + ReferenceSizePropertyProvider* m_pRefSizePropProvider; +}; + +class WrappedCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedCharacterHeightProperty() override; + + static void addWrappedProperties( std::vector< std::unique_ptr >& rList, ReferenceSizePropertyProvider* pRefSizePropProvider ); +}; + +class WrappedAsianCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedAsianCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedAsianCharacterHeightProperty() override; +}; + +class WrappedComplexCharacterHeightProperty : public WrappedCharacterHeightProperty_Base +{ +public: + explicit WrappedComplexCharacterHeightProperty( ReferenceSizePropertyProvider* pRefSizePropProvider ); + virtual ~WrappedComplexCharacterHeightProperty() override; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx new file mode 100644 index 000000000..d317210c3 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.cxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedDataCaptionProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +class WrappedDataCaptionProperty : public WrappedSeriesOrDiagramProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& aNewValue ) const override; + + explicit WrappedDataCaptionProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +enum +{ + //data caption properties + PROP_CHART_DATAPOINT_DATA_CAPTION = FAST_PROPERTY_ID_START_CHART_DATACAPTION_PROP +}; + +sal_Int32 lcl_LabelToCaption( const chart2::DataPointLabel& rLabel ) +{ + sal_Int32 nCaption=0; + + if( rLabel.ShowNumber ) + nCaption |= css::chart::ChartDataCaption::VALUE; + if( rLabel.ShowNumberInPercent ) + nCaption |= css::chart::ChartDataCaption::PERCENT; + if( rLabel.ShowCategoryName ) + nCaption |= css::chart::ChartDataCaption::TEXT; + if( rLabel.ShowLegendSymbol ) + nCaption |= css::chart::ChartDataCaption::SYMBOL; + if (rLabel.ShowSeriesName) + nCaption |= css::chart::ChartDataCaption::DATA_SERIES; + + return nCaption; +} + +chart2::DataPointLabel lcl_CaptionToLabel( sal_Int32 nCaption ) +{ + chart2::DataPointLabel aLabel(false,false,false,false,false,false); + + if( nCaption & css::chart::ChartDataCaption::VALUE ) + aLabel.ShowNumber = true; + if( nCaption & css::chart::ChartDataCaption::PERCENT ) + aLabel.ShowNumberInPercent = true; + if( nCaption & css::chart::ChartDataCaption::TEXT ) + aLabel.ShowCategoryName = true; + if( nCaption & css::chart::ChartDataCaption::SYMBOL ) + aLabel.ShowLegendSymbol = true; + if( nCaption & css::chart::ChartDataCaption::CUSTOM ) + aLabel.ShowCustomLabel = true; + if( nCaption & css::chart::ChartDataCaption::DATA_SERIES ) + aLabel.ShowSeriesName = true; + + return aLabel; +} + +void lcl_addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + //if !spChart2ModelContact.get() is then the created properties do belong to a single series or single datapoint + //otherwise they do belong to the whole diagram + + rList.emplace_back( new WrappedDataCaptionProperty( spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedDataCaptionProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "DataCaption", + PROP_CHART_DATAPOINT_DATA_CAPTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedDataCaptionProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedDataCaptionProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +WrappedDataCaptionProperty::WrappedDataCaptionProperty( + const std::shared_ptr& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< sal_Int32 >( "DataCaption" + , uno::Any( sal_Int32(0) ), spChart2ModelContact, ePropertyType ) +{ +} + +sal_Int32 WrappedDataCaptionProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 aRet = 0; + m_aDefaultValue >>= aRet; + chart2::DataPointLabel aLabel; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel ) ) + aRet = lcl_LabelToCaption( aLabel ); + return aRet; +} + +void WrappedDataCaptionProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nCaption ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::DataPointLabel aLabel = lcl_CaptionToLabel( nCaption ); + xSeriesPropertySet->setPropertyValue( CHART_UNONAME_LABEL, uno::Any( aLabel ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx new file mode 100644 index 000000000..a2bcaa302 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedDataCaptionProperties.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedDataCaptionProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx new file mode 100644 index 000000000..8ad57070a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.cxx @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "WrappedGapwidthProperty.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ + +const sal_Int32 DEFAULT_GAPWIDTH = 100; +const sal_Int32 DEFAULT_OVERLAP = 0; + +WrappedBarPositionProperty_Base::WrappedBarPositionProperty_Base( + const OUString& rOuterName + , const OUString& rInnerSequencePropertyName + , sal_Int32 nDefaultValue + , const std::shared_ptr& spChart2ModelContact ) + : WrappedDefaultProperty( rOuterName, OUString(), uno::Any( nDefaultValue ) ) + , m_nDimensionIndex(0) + , m_nAxisIndex(0) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_nDefaultValue( nDefaultValue ) + , m_InnerSequencePropertyName( rInnerSequencePropertyName ) +{ +} + +void WrappedBarPositionProperty_Base::setDimensionAndAxisIndex( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + m_nDimensionIndex = nDimensionIndex; + m_nAxisIndex = nAxisIndex; +} + +WrappedBarPositionProperty_Base::~WrappedBarPositionProperty_Base() +{ +} + +void WrappedBarPositionProperty_Base::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + sal_Int32 nNewValue = 0; + if( ! (rOuterValue >>= nNewValue) ) + throw lang::IllegalArgumentException( "GapWidth and Overlap property require value of type sal_Int32", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( !xDiagram.is() ) + return; + + if( m_nDimensionIndex!=1 ) + return; + + const std::vector< rtl::Reference< ChartType > > aChartTypeList( DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & chartType : aChartTypeList ) + { + try + { + Sequence< sal_Int32 > aBarPositionSequence; + chartType->getPropertyValue( m_InnerSequencePropertyName ) >>= aBarPositionSequence; + + tools::Long nOldLength = aBarPositionSequence.getLength(); + if( nOldLength <= m_nAxisIndex ) + aBarPositionSequence.realloc( m_nAxisIndex+1 ); + auto pBarPositionSequence = aBarPositionSequence.getArray(); + for( sal_Int32 i=nOldLength; isetPropertyValue( m_InnerSequencePropertyName, uno::Any( aBarPositionSequence ) ); + } + catch( uno::Exception& e ) + { + //the above properties are not supported by all charttypes (only by column and bar) + //in that cases this exception is ok + e.Context.is();//to have debug information without compilation warnings + } + } +} + +Any WrappedBarPositionProperty_Base::getPropertyValue( const Reference< beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() ) + { + bool bInnerValueDetected = false; + sal_Int32 nInnerValue = m_nDefaultValue; + + if( m_nDimensionIndex==1 ) + { + std::vector< rtl::Reference< ChartType > > aChartTypeList( DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( std::size_t nN = 0; nN < aChartTypeList.size() && !bInnerValueDetected; nN++ ) + { + try + { + Sequence< sal_Int32 > aBarPositionSequence; + aChartTypeList[nN]->getPropertyValue( m_InnerSequencePropertyName ) >>= aBarPositionSequence; + if( m_nAxisIndex < aBarPositionSequence.getLength() ) + { + nInnerValue = aBarPositionSequence[m_nAxisIndex]; + bInnerValueDetected = true; + } + } + catch( uno::Exception& e ) + { + //the above properties are not supported by all charttypes (only by column and bar) + //in that cases this exception is ok + e.Context.is();//to have debug information without compilation warnings + } + } + } + if( bInnerValueDetected ) + { + m_aOuterValue <<= nInnerValue; + } + } + return m_aOuterValue; +} + +WrappedGapwidthProperty::WrappedGapwidthProperty( + const std::shared_ptr& spChart2ModelContact) + : WrappedBarPositionProperty_Base( "GapWidth", "GapwidthSequence", DEFAULT_GAPWIDTH, spChart2ModelContact ) +{ +} +WrappedGapwidthProperty::~WrappedGapwidthProperty() +{ +} + +WrappedBarOverlapProperty::WrappedBarOverlapProperty( + const std::shared_ptr& spChart2ModelContact ) + : WrappedBarPositionProperty_Base( "Overlap", "OverlapSequence", DEFAULT_OVERLAP, spChart2ModelContact ) +{ +} +WrappedBarOverlapProperty::~WrappedBarOverlapProperty() +{ +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx new file mode 100644 index 000000000..550b0ce6a --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedGapwidthProperty.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedBarPositionProperty_Base : public WrappedDefaultProperty +{ +public: + WrappedBarPositionProperty_Base( + const OUString& rOuterName + , const OUString& rInnerSequencePropertyName + , sal_Int32 nDefaultValue + , const std::shared_ptr& spChart2ModelContact ); + virtual ~WrappedBarPositionProperty_Base() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + void setDimensionAndAxisIndex( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + +protected: + sal_Int32 m_nDimensionIndex; + sal_Int32 m_nAxisIndex; + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + + sal_Int32 m_nDefaultValue; + OUString m_InnerSequencePropertyName; + + mutable css::uno::Any m_aOuterValue; +}; + +class WrappedGapwidthProperty : public WrappedBarPositionProperty_Base +{ +public: + explicit WrappedGapwidthProperty(const std::shared_ptr& spChart2ModelContact); + virtual ~WrappedGapwidthProperty() override; +}; + +class WrappedBarOverlapProperty : public WrappedBarPositionProperty_Base +{ +public: + explicit WrappedBarOverlapProperty(const std::shared_ptr& spChart2ModelContact); + virtual ~WrappedBarOverlapProperty() override; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx new file mode 100644 index 000000000..1ce277c32 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.cxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedNumberFormatProperty.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +namespace chart::wrapper +{ + +WrappedNumberFormatProperty::WrappedNumberFormatProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedDirectStateProperty( CHART_UNONAME_NUMFMT, CHART_UNONAME_NUMFMT ) + , m_spChart2ModelContact(spChart2ModelContact) +{ +} + +WrappedNumberFormatProperty::~WrappedNumberFormatProperty() +{ +} + +void WrappedNumberFormatProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + sal_Int32 nFormat = 0; + if( ! (rOuterValue >>= nFormat) ) + throw lang::IllegalArgumentException( "Property 'NumberFormat' requires value of type sal_Int32", nullptr, 0 ); + + if(xInnerPropertySet.is()) + xInnerPropertySet->setPropertyValue(getInnerName(), convertOuterToInnerValue(rOuterValue)); +} + +Any WrappedNumberFormatProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::getPropertyValue"); + return Any(); + } + Any aRet( xInnerPropertySet->getPropertyValue(getInnerName())); + if( !aRet.hasValue() ) + { + sal_Int32 nKey = 0; + Reference< chart2::XDataSeries > xSeries( xInnerPropertySet, uno::UNO_QUERY ); + if( xSeries.is() ) + nKey = Chart2ModelContact::getExplicitNumberFormatKeyForSeries( xSeries ); + else + { + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + nKey = m_spChart2ModelContact->getExplicitNumberFormatKeyForAxis( xAxis ); + } + aRet <<= nKey; + } + return aRet; +} + +Any WrappedNumberFormatProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( sal_Int32( 0 ) ); +} + +WrappedLinkNumberFormatProperty::WrappedLinkNumberFormatProperty() : + WrappedDirectStateProperty(CHART_UNONAME_LINK_TO_SRC_NUMFMT, CHART_UNONAME_LINK_TO_SRC_NUMFMT) +{ +} + +WrappedLinkNumberFormatProperty::~WrappedLinkNumberFormatProperty() +{ +} + +void WrappedLinkNumberFormatProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::setPropertyValue"); + return; + } + + xInnerPropertySet->setPropertyValue(getInnerName(), rOuterValue); +} + +Any WrappedLinkNumberFormatProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( !xInnerPropertySet.is() ) + { + OSL_FAIL("missing xInnerPropertySet in WrappedNumberFormatProperty::getPropertyValue"); + return getPropertyDefault(nullptr); + } + + return xInnerPropertySet->getPropertyValue(getInnerName()); +} + +Any WrappedLinkNumberFormatProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return uno::Any( true ); // bLink +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx new file mode 100644 index 000000000..fa4042cea --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedNumberFormatProperty.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + + +class WrappedNumberFormatProperty : public WrappedDirectStateProperty +{ +public: + explicit WrappedNumberFormatProperty(const std::shared_ptr& spChart2ModelContact); + virtual ~WrappedNumberFormatProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + friend class WrappedLinkNumberFormatProperty; +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +class WrappedLinkNumberFormatProperty : public WrappedDirectStateProperty +{ +public: + explicit WrappedLinkNumberFormatProperty(); + virtual ~WrappedLinkNumberFormatProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx new file mode 100644 index 000000000..27e07256e --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.cxx @@ -0,0 +1,587 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedScaleProperty.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::chart::TimeIncrement; + +namespace chart::wrapper +{ + +WrappedScaleProperty::WrappedScaleProperty(tScaleProperty eScaleProperty + , const std::shared_ptr& spChart2ModelContact) + : WrappedProperty(OUString(),OUString()) + , m_spChart2ModelContact( spChart2ModelContact ) + , m_eScaleProperty( eScaleProperty ) +{ + switch( m_eScaleProperty ) + { + case SCALE_PROP_MAX: + m_aOuterName = "Max"; + break; + case SCALE_PROP_MIN: + m_aOuterName = "Min"; + break; + case SCALE_PROP_ORIGIN: + m_aOuterName = "Origin"; + break; + case SCALE_PROP_STEPMAIN: + m_aOuterName = "StepMain"; + break; + case SCALE_PROP_STEPHELP: + m_aOuterName = "StepHelp"; + break; + case SCALE_PROP_STEPHELP_COUNT: + m_aOuterName = "StepHelpCount"; + break; + case SCALE_PROP_AUTO_MAX: + m_aOuterName = "AutoMax"; + break; + case SCALE_PROP_AUTO_MIN: + m_aOuterName = "AutoMin"; + break; + case SCALE_PROP_AUTO_ORIGIN: + m_aOuterName = "AutoOrigin"; + break; + case SCALE_PROP_AUTO_STEPMAIN: + m_aOuterName = "AutoStepMain"; + break; + case SCALE_PROP_AUTO_STEPHELP: + m_aOuterName = "AutoStepHelp"; + break; + case SCALE_PROP_AXIS_TYPE: + m_aOuterName = "AxisType"; + break; + case SCALE_PROP_DATE_INCREMENT: + m_aOuterName = "TimeIncrement"; + break; + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + m_aOuterName = "ExplicitTimeIncrement"; + break; + case SCALE_PROP_LOGARITHMIC: + m_aOuterName = "Logarithmic"; + break; + case SCALE_PROP_REVERSEDIRECTION: + m_aOuterName = "ReverseDirection"; + break; + default: + OSL_FAIL("unknown scale property"); + break; + } +} + +WrappedScaleProperty::~WrappedScaleProperty() +{ +} + +void WrappedScaleProperty::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_MAX, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_MIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_ORIGIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPMAIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_STEPHELP_COUNT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MAX, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_MIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_ORIGIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPMAIN, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AUTO_STEPHELP, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_AXIS_TYPE, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_DATE_INCREMENT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_EXPLICIT_DATE_INCREMENT, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_LOGARITHMIC, spChart2ModelContact ) ); + rList.emplace_back( new WrappedScaleProperty( SCALE_PROP_REVERSEDIRECTION, spChart2ModelContact ) ); +} + +void WrappedScaleProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + setPropertyValue( m_eScaleProperty, rOuterValue, xInnerPropertySet ); +} + +Any WrappedScaleProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + return getPropertyValue( m_eScaleProperty, xInnerPropertySet ); +} + +void WrappedScaleProperty::setPropertyValue( tScaleProperty eScaleProperty, const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + m_aOuterValue = rOuterValue; + + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + OSL_ENSURE(xAxis.is(),"need an XAxis"); + if(!xAxis.is()) + return; + + bool bSetScaleData = false; + + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + + bool bBool = false; + switch( eScaleProperty ) + { + case SCALE_PROP_MAX: + { + aScaleData.Maximum = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_MIN: + { + aScaleData.Minimum = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPMAIN: + { + aScaleData.IncrementData.Distance = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + + double fStepHelp = 0; + if( rOuterValue >>= fStepHelp ) + { + double fStepMain = 0; + if( AxisHelper::isLogarithmic(aScaleData.Scaling) ) + { + sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepHelp); + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + } + else if( (fStepHelp != 0.0) && + (aScaleData.IncrementData.Distance >>= fStepMain) ) + { + // approximate interval count + sal_Int32 nIntervalCount = static_cast< sal_Int32 >(fStepMain / fStepHelp);//cppcheck-suppress zerodiv + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + } + } + bSetScaleData = true; + break; + } + case SCALE_PROP_STEPHELP_COUNT: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + sal_Int32 nIntervalCount=0; + if( rOuterValue>>=nIntervalCount ) + pSubIncrements[ 0 ].IntervalCount <<= nIntervalCount; + else + pSubIncrements[ 0 ].IntervalCount = Any(); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_MAX: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Maximum = Any(); + else + aScaleData.Maximum = getPropertyValue( SCALE_PROP_MAX, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_MIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Minimum = Any(); + else + aScaleData.Minimum = getPropertyValue( SCALE_PROP_MIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_STEPMAIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.IncrementData.Distance = Any(); + else + aScaleData.IncrementData.Distance = getPropertyValue( SCALE_PROP_STEPMAIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( !rSubIncrements.hasElements() ) + rSubIncrements.realloc( 1 ); + auto pSubIncrements = rSubIncrements.getArray(); + + if( (rOuterValue >>= bBool) && bBool ) + pSubIncrements[ 0 ].IntervalCount = Any(); + else + pSubIncrements[ 0 ].IntervalCount = getPropertyValue( SCALE_PROP_STEPHELP_COUNT, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_ORIGIN: + { + aScaleData.Origin = rOuterValue; + bSetScaleData = true; + break; + } + case SCALE_PROP_AUTO_ORIGIN: + { + if( (rOuterValue >>= bBool) && bBool ) + aScaleData.Origin = Any(); + else + aScaleData.Origin = getPropertyValue( SCALE_PROP_ORIGIN, xInnerPropertySet ); + bSetScaleData = true; + break; + } + case SCALE_PROP_AXIS_TYPE: + { + sal_Int32 nType = 0; + if( rOuterValue >>= nType ) + { + if( nType == css::chart::ChartAxisType::AUTOMATIC ) + { + aScaleData.AutoDateAxis = true; + if( aScaleData.AxisType == AxisType::DATE ) + aScaleData.AxisType = AxisType::CATEGORY; + } + else if( nType == css::chart::ChartAxisType::CATEGORY ) + { + aScaleData.AutoDateAxis = false; + if( aScaleData.AxisType == AxisType::DATE ) + aScaleData.AxisType = AxisType::CATEGORY; + } + else if( nType == css::chart::ChartAxisType::DATE ) + { + if( aScaleData.AxisType == AxisType::CATEGORY ) + aScaleData.AxisType = AxisType::DATE; + } + bSetScaleData = true; + } + break; + } + case SCALE_PROP_DATE_INCREMENT: + { + TimeIncrement aTimeIncrement; + rOuterValue >>= aTimeIncrement; + aScaleData.TimeIncrement = aTimeIncrement; + bSetScaleData = true; + break; + } + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + //read only property + break; + case SCALE_PROP_LOGARITHMIC: + { + if( rOuterValue >>= bBool ) + { + bool bWasLogarithm = AxisHelper::isLogarithmic( aScaleData.Scaling ); + + // safe comparison between sal_Bool and bool + if( (!bBool) != (!bWasLogarithm) ) + { + if( bBool ) + aScaleData.Scaling = AxisHelper::createLogarithmicScaling( 10.0 ); + else + aScaleData.Scaling = nullptr; + bSetScaleData = true; + } + } + break; + } + case SCALE_PROP_REVERSEDIRECTION: + { + if( rOuterValue >>= bBool ) + { + bool bWasReverse = ( aScaleData.Orientation == AxisOrientation_REVERSE ); + if( (!bBool) != (!bWasReverse) ) // safe comparison between sal_Bool and bool + { + aScaleData.Orientation = bBool ? AxisOrientation_REVERSE : AxisOrientation_MATHEMATICAL; + bSetScaleData = true; + } + } + break; + } + default: + { + OSL_FAIL("unknown scale property"); + break; + } + } + + if( bSetScaleData ) + xAxis->setScaleData( aScaleData ); +} + +Any WrappedScaleProperty::getPropertyValue( tScaleProperty eScaleProperty, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( m_aOuterValue ); + + Reference< chart2::XAxis > xAxis( xInnerPropertySet, uno::UNO_QUERY ); + OSL_ENSURE(xAxis.is(),"need an XAxis"); + if(!xAxis.is()) + return aRet; + + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + + switch( eScaleProperty ) + { + case SCALE_PROP_MAX: + { + aRet = aScaleData.Maximum; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Maximum; + } + break; + } + case SCALE_PROP_MIN: + { + aRet = aScaleData.Minimum; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Minimum; + } + break; + } + + case SCALE_PROP_STEPMAIN: + { + aRet = aScaleData.IncrementData.Distance; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitIncrement.Distance; + } + break; + } + case SCALE_PROP_STEPHELP: + { + // todo: evaluate PostEquidistant + bool bNeedToCalculateExplicitValues = true; + + bool bLogarithmic( AxisHelper::isLogarithmic(aScaleData.Scaling) ); + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( bLogarithmic ) + { + if( rSubIncrements.hasElements() ) + { + sal_Int32 nIntervalCount = 0; + rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount; + aRet <<= double(nIntervalCount); + bNeedToCalculateExplicitValues = false; + } + } + else if( aScaleData.IncrementData.Distance.hasValue() ) + { + if( rSubIncrements.hasElements() ) + { + double fStepMain = 0; + sal_Int32 nIntervalCount = 0; + if( (aScaleData.IncrementData.Distance >>= fStepMain) && + (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) && + nIntervalCount > 0 ) + { + aRet <<= fStepMain / static_cast< double >( nIntervalCount ); + bNeedToCalculateExplicitValues = false; + } + } + else + { + aRet = aScaleData.IncrementData.Distance; + bNeedToCalculateExplicitValues = false; + } + } + + if( bNeedToCalculateExplicitValues ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + + if( !aExplicitIncrement.SubIncrements.empty() && + aExplicitIncrement.SubIncrements[ 0 ].IntervalCount > 0 ) + { + if( bLogarithmic ) + { + if( rSubIncrements.hasElements() ) + { + sal_Int32 nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount; + aRet <<= double(nIntervalCount); + } + } + else + aRet <<= aExplicitIncrement.Distance / + static_cast< double >( + aExplicitIncrement.SubIncrements[ 0 ].IntervalCount ); + } + else + { + if( bLogarithmic ) + aRet <<= 5.0; + else + aRet <<= aExplicitIncrement.Distance; + } + } + break; + } + case SCALE_PROP_STEPHELP_COUNT: + { + sal_Int32 nIntervalCount = 0; + bool bNeedToCalculateExplicitValues = true; + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( rSubIncrements.hasElements() ) + { + if( (rSubIncrements[ 0 ].IntervalCount >>= nIntervalCount) && (nIntervalCount > 0) ) + bNeedToCalculateExplicitValues = false; + } + if( bNeedToCalculateExplicitValues ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement ); + if( !aExplicitIncrement.SubIncrements.empty() ) + nIntervalCount = aExplicitIncrement.SubIncrements[ 0 ].IntervalCount; + } + aRet <<= nIntervalCount; + break; + } + case SCALE_PROP_AUTO_MAX: + { + aRet <<= !aScaleData.Maximum.hasValue(); + break; + } + case SCALE_PROP_AUTO_MIN: + { + aRet <<= !aScaleData.Minimum.hasValue(); + break; + } + case SCALE_PROP_AUTO_STEPMAIN: + { + aRet <<= !aScaleData.IncrementData.Distance.hasValue(); + break; + } + case SCALE_PROP_AUTO_STEPHELP: + { + Sequence< chart2::SubIncrement >& rSubIncrements( aScaleData.IncrementData.SubIncrements ); + if( rSubIncrements.hasElements() ) + aRet <<= !rSubIncrements[ 0 ].IntervalCount.hasValue(); + else + aRet <<= true; + break; + } + case SCALE_PROP_ORIGIN: + { + aRet = aScaleData.Origin; + if( !aRet.hasValue() ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( + xAxis, aExplicitScale, aExplicitIncrement ); + aRet <<= aExplicitScale.Origin; + } + break; + } + case SCALE_PROP_AUTO_ORIGIN: + { + aRet <<= !hasDoubleValue(aScaleData.Origin); + break; + } + case SCALE_PROP_AXIS_TYPE: + { + sal_Int32 nType = css::chart::ChartAxisType::AUTOMATIC; + if( aScaleData.AxisType == AxisType::DATE ) + { + nType = css::chart::ChartAxisType::DATE; + } + else if( aScaleData.AxisType == AxisType::CATEGORY ) + { + if( !aScaleData.AutoDateAxis ) + nType = css::chart::ChartAxisType::CATEGORY; + } + aRet <<= nType; + break; + } + case SCALE_PROP_DATE_INCREMENT: + { + if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis ) + aRet <<= aScaleData.TimeIncrement; + break; + } + case SCALE_PROP_EXPLICIT_DATE_INCREMENT: + { + if( aScaleData.AxisType == AxisType::DATE || aScaleData.AutoDateAxis ) + { + m_spChart2ModelContact->getExplicitValuesForAxis( xAxis, aExplicitScale, aExplicitIncrement ); + if( aExplicitScale.AxisType == AxisType::DATE ) + { + TimeIncrement aTimeIncrement; + aTimeIncrement.MajorTimeInterval <<= aExplicitIncrement.MajorTimeInterval; + aTimeIncrement.MinorTimeInterval <<= aExplicitIncrement.MinorTimeInterval; + aTimeIncrement.TimeResolution <<= aExplicitScale.TimeResolution; + aRet <<= aTimeIncrement; + } + else + aRet <<= aScaleData.TimeIncrement; + } + + break; + } + case SCALE_PROP_LOGARITHMIC: + { + aRet <<= AxisHelper::isLogarithmic(aScaleData.Scaling); + break; + } + case SCALE_PROP_REVERSEDIRECTION: + { + aRet <<= aScaleData.Orientation == AxisOrientation_REVERSE; + break; + } + default: + { + OSL_FAIL("unknown scale property"); + break; + } + } + + return aRet; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx new file mode 100644 index 000000000..64e8071b5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleProperty.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedScaleProperty final : public WrappedProperty +{ +public: + enum tScaleProperty + { + SCALE_PROP_MAX + , SCALE_PROP_MIN + , SCALE_PROP_ORIGIN + , SCALE_PROP_STEPMAIN + , SCALE_PROP_STEPHELP //deprecated property + , SCALE_PROP_STEPHELP_COUNT + , SCALE_PROP_AUTO_MAX + , SCALE_PROP_AUTO_MIN + , SCALE_PROP_AUTO_ORIGIN + , SCALE_PROP_AUTO_STEPMAIN + , SCALE_PROP_AUTO_STEPHELP + , SCALE_PROP_AXIS_TYPE + , SCALE_PROP_DATE_INCREMENT + , SCALE_PROP_EXPLICIT_DATE_INCREMENT + , SCALE_PROP_LOGARITHMIC + , SCALE_PROP_REVERSEDIRECTION + }; + + WrappedScaleProperty(tScaleProperty eScaleProperty, const std::shared_ptr& spChart2ModelContact); + virtual ~WrappedScaleProperty() override; + + static void addWrappedProperties( std::vector< std::unique_ptr >& rList, const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + /// @throws css::beans::UnknownPropertyException + /// @throws css::beans::PropertyVetoException + /// @throws css::lang::IllegalArgumentException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + void setPropertyValue( tScaleProperty eScaleProperty, const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + /// @throws css::beans::UnknownPropertyException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + css::uno::Any getPropertyValue( tScaleProperty eScaleProperty, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + tScaleProperty m_eScaleProperty; + + mutable css::uno::Any m_aOuterValue; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx new file mode 100644 index 000000000..8551915d9 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedScaleTextProperties.hxx" +#include "Chart2ModelContact.hxx" +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedScaleTextProperty : public WrappedProperty +{ +public: + explicit WrappedScaleTextProperty(const std::shared_ptr& spChart2ModelContact); + + virtual void setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual Any getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} + +WrappedScaleTextProperty::WrappedScaleTextProperty(const std::shared_ptr& spChart2ModelContact) + : ::chart::WrappedProperty( "ScaleText" , OUString() ) + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +void WrappedScaleTextProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + static constexpr OUStringLiteral aRefSizeName = u"ReferencePageSize"; + + if( !xInnerPropertySet.is() ) + return; + + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + { + if( rOuterValue.hasValue() ) + throw lang::IllegalArgumentException( "Property ScaleText requires value of type boolean", nullptr, 0 ); + } + + try + { + if( bNewValue ) + { + awt::Size aRefSize( m_spChart2ModelContact->GetPageSize() ); + xInnerPropertySet->setPropertyValue( aRefSizeName, uno::Any( aRefSize ) ); + } + else + xInnerPropertySet->setPropertyValue( aRefSizeName, Any() ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +Any WrappedScaleTextProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet( getPropertyDefault( Reference< beans::XPropertyState >( xInnerPropertySet, uno::UNO_QUERY ) ) ); + if( xInnerPropertySet.is() ) + { + if( xInnerPropertySet->getPropertyValue( "ReferencePageSize" ).hasValue() ) + aRet <<= true; + else + aRet <<= false; + } + + return aRet; +} + +Any WrappedScaleTextProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + Any aRet; + aRet <<= false; + return aRet; +} + +namespace +{ +enum +{ + PROP_CHART_SCALE_TEXT = FAST_PROPERTY_ID_START_SCALE_TEXT_PROP +}; + +}//anonymous namespace + +void WrappedScaleTextProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ScaleText", + PROP_CHART_SCALE_TEXT, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedScaleTextProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedScaleTextProperty( spChart2ModelContact ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx new file mode 100644 index 000000000..958b5f55d --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedScaleTextProperties.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedScaleTextProperties +{ +public: + static void addProperties( std::vector< css::beans::Property >& rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx new file mode 100644 index 000000000..2430dcba7 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.cxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedSceneProperty.hxx" +#include "Chart2ModelContact.hxx" +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper +{ + +void WrappedSceneProperty::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedD3DTransformMatrixProperty( spChart2ModelContact ) ); +} + +WrappedD3DTransformMatrixProperty::WrappedD3DTransformMatrixProperty( + const std::shared_ptr& spChart2ModelContact ) + : WrappedProperty("D3DTransformMatrix","D3DTransformMatrix") + , m_spChart2ModelContact( spChart2ModelContact ) +{ +} + +WrappedD3DTransformMatrixProperty::~WrappedD3DTransformMatrixProperty() +{ +} + +void WrappedD3DTransformMatrixProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( DiagramHelper::isPieOrDonutChart( m_spChart2ModelContact->getDiagram() ) ) + { + drawing::HomogenMatrix aHM; + if( rOuterValue >>= aHM ) + { + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHM ) ) ); + + ::basegfx::B3DHomMatrix aMatrix; + aMatrix.rotate( aRotation.getX(), aRotation.getY(), aRotation.getZ() ); + ::basegfx::B3DHomMatrix aObjectMatrix; + ::basegfx::B3DHomMatrix aNewMatrix = aMatrix*aObjectMatrix; + + aHM = BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aNewMatrix); + + WrappedProperty::setPropertyValue( uno::Any(aHM), xInnerPropertySet ); + return; + } + } + + WrappedProperty::setPropertyValue( rOuterValue, xInnerPropertySet ); +} + +Any WrappedD3DTransformMatrixProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if( DiagramHelper::isPieOrDonutChart( m_spChart2ModelContact->getDiagram() ) ) + { + uno::Any aAMatrix( WrappedProperty::getPropertyValue( xInnerPropertySet ) ); + drawing::HomogenMatrix aHM; + if( aAMatrix >>= aHM ) + { + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHM ) ) ); + + ::basegfx::B3DHomMatrix aMatrix; + aMatrix.rotate( aRotation.getX(), aRotation.getY(), aRotation.getZ() ); + ::basegfx::B3DHomMatrix aObjectMatrix; + ::basegfx::B3DHomMatrix aNewMatrix = aMatrix*aObjectMatrix; + + aHM = BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aNewMatrix); + + return uno::Any(aHM); + } + } + + return WrappedProperty::getPropertyValue( xInnerPropertySet ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx new file mode 100644 index 000000000..7e6679016 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSceneProperty.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include + +namespace chart::wrapper { class Chart2ModelContact; } + +namespace chart::wrapper +{ + +class WrappedSceneProperty +{ +public: + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +class WrappedD3DTransformMatrixProperty : public WrappedProperty +{ +public: + explicit WrappedD3DTransformMatrixProperty( + const std::shared_ptr& spChart2ModelContact); + virtual ~WrappedD3DTransformMatrixProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +private: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx new file mode 100644 index 000000000..88fa72696 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.cxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedSeriesAreaOrLineProperty.hxx" +#include "DataSeriesPointWrapper.hxx" + +namespace chart::wrapper +{ + +WrappedSeriesAreaOrLineProperty::WrappedSeriesAreaOrLineProperty( + const OUString& rOuterName + , const OUString& rInnerAreaTypeName + , const OUString& rInnerLineTypeName + , DataSeriesPointWrapper* pDataSeriesPointWrapper ) + : WrappedProperty( rOuterName, OUString() ) + , m_pDataSeriesPointWrapper( pDataSeriesPointWrapper ) + , m_aInnerAreaTypeName( rInnerAreaTypeName ) + , m_aInnerLineTypeName( rInnerLineTypeName ) +{ +} +WrappedSeriesAreaOrLineProperty::~WrappedSeriesAreaOrLineProperty() +{ +} + +//virtual +OUString WrappedSeriesAreaOrLineProperty::getInnerName() const +{ + if( m_pDataSeriesPointWrapper && !m_pDataSeriesPointWrapper->isSupportingAreaProperties() ) + return m_aInnerLineTypeName; + return m_aInnerAreaTypeName; +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx new file mode 100644 index 000000000..ba77b6939 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesAreaOrLineProperty.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart::wrapper +{ + +class DataSeriesPointWrapper; +class WrappedSeriesAreaOrLineProperty : public WrappedProperty +{ +public: + WrappedSeriesAreaOrLineProperty( const OUString& rOuterName + , const OUString& rInnerAreaTypeName, const OUString& rInnerLineTypeName + , DataSeriesPointWrapper* pDataSeriesPointWrapper ); + virtual ~WrappedSeriesAreaOrLineProperty() override; + + virtual OUString getInnerName() const override; + +private: + DataSeriesPointWrapper* m_pDataSeriesPointWrapper; + OUString m_aInnerAreaTypeName; + OUString m_aInnerLineTypeName; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx new file mode 100644 index 000000000..db9a07b45 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSeriesOrDiagramProperty.hxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "Chart2ModelContact.hxx" +#include +#include + +#include +#include + +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart::wrapper +{ + +enum tSeriesOrDiagramPropertyType +{ + DATA_SERIES, + DIAGRAM +}; + +//PROPERTYTYPE is the type of the outer property + +template< typename PROPERTYTYPE > +class WrappedSeriesOrDiagramProperty : public WrappedProperty +{ +public: + virtual PROPERTYTYPE getValueFromSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet ) const =0; + virtual void setValueToSeries( const css::uno::Reference< css::beans::XPropertySet >& xSeriesPropertySet, const PROPERTYTYPE & aNewValue ) const =0; + + explicit WrappedSeriesOrDiagramProperty( const OUString& rName, const css::uno::Any& rDefaulValue + , const std::shared_ptr& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedProperty(rName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aOuterValue(rDefaulValue) + , m_aDefaultValue(rDefaulValue) + , m_ePropertyType( ePropertyType ) + { + } + + bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const + { + bool bHasDetectableInnerValue = false; + rHasAmbiguousValue = false; + if( m_ePropertyType == DIAGRAM && + m_spChart2ModelContact ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getDiagram() ); + for (auto const& series : aSeriesVector) + { + PROPERTYTYPE aCurValue = getValueFromSeries( series ); + if( !bHasDetectableInnerValue ) + rValue = aCurValue; + else + { + if( rValue != aCurValue ) + { + rHasAmbiguousValue = true; + break; + } + else + rValue = aCurValue; + } + bHasDetectableInnerValue = true; + } + } + return bHasDetectableInnerValue; + } + void setInnerValue( PROPERTYTYPE aNewValue ) const + { + if( m_ePropertyType == DIAGRAM && + m_spChart2ModelContact ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + ::chart::DiagramHelper::getDataSeriesFromDiagram( m_spChart2ModelContact->getDiagram() ); + for (auto const& series : aSeriesVector) + { + setValueToSeries( series, aNewValue ); + } + } + } + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override + { + PROPERTYTYPE aNewValue = PROPERTYTYPE(); + if( ! (rOuterValue >>= aNewValue) ) + throw css::lang::IllegalArgumentException( "statistic property requires different type", nullptr, 0 ); + + if( m_ePropertyType == DIAGRAM ) + { + m_aOuterValue = rOuterValue; + + bool bHasAmbiguousValue = false; + PROPERTYTYPE aOldValue = PROPERTYTYPE(); + if( detectInnerValue( aOldValue, bHasAmbiguousValue ) ) + { + if( bHasAmbiguousValue || aNewValue != aOldValue ) + setInnerValue( aNewValue ); + } + } + else + { + setValueToSeries( xInnerPropertySet, aNewValue ); + } + } + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override + { + if( m_ePropertyType == DIAGRAM ) + { + bool bHasAmbiguousValue = false; + PROPERTYTYPE aValue = PROPERTYTYPE(); + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + if(bHasAmbiguousValue) + m_aOuterValue = m_aDefaultValue; + else + m_aOuterValue <<= aValue; + } + return m_aOuterValue; + } + else + { + css::uno::Any aRet( m_aDefaultValue ); + aRet <<= getValueFromSeries( xInnerPropertySet ); + return aRet; + } + } + + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /* xInnerPropertyState */ ) const override + { + return m_aDefaultValue; + } + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; + tSeriesOrDiagramPropertyType m_ePropertyType; +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx new file mode 100644 index 000000000..102acfb02 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedSplineProperties.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +//PROPERTYTYPE is the type of the outer property + +template< typename PROPERTYTYPE > +class WrappedSplineProperty : public WrappedProperty +{ +public: + explicit WrappedSplineProperty( const OUString& rOuterName, const OUString& rInnerName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr& spChart2ModelContact ) + : WrappedProperty(rOuterName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aOuterValue(rDefaulValue) + , m_aDefaultValue(rDefaulValue) + , m_aOwnInnerName(rInnerName) + { + } + + bool detectInnerValue( PROPERTYTYPE& rValue, bool& rHasAmbiguousValue ) const + { + bool bHasDetectableInnerValue = false; + rHasAmbiguousValue = false; + std::vector< rtl::Reference< ChartType > > aChartTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( sal_Int32 nN = aChartTypes.size(); nN--; ) + { + try + { + Any aSingleValue = convertInnerToOuterValue( aChartTypes[nN]->getPropertyValue(m_aOwnInnerName) ); + PROPERTYTYPE aCurValue = PROPERTYTYPE(); + aSingleValue >>= aCurValue; + if( !bHasDetectableInnerValue ) + rValue = aCurValue; + else + { + if( rValue != aCurValue ) + { + rHasAmbiguousValue = true; + break; + } + else + rValue = aCurValue; + } + bHasDetectableInnerValue = true; + } + catch( uno::Exception & ex ) + { + //spline properties are not supported by all charttypes + //in that cases this exception is ok + ex.Context.is();//to have debug information without compilation warnings + } + } + return bHasDetectableInnerValue; + } + void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const override + { + PROPERTYTYPE aNewValue; + if( ! (rOuterValue >>= aNewValue) ) + throw css::lang::IllegalArgumentException( "spline property requires different type", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + bool bHasAmbiguousValue = false; + PROPERTYTYPE aOldValue = PROPERTYTYPE(); + if( !detectInnerValue( aOldValue, bHasAmbiguousValue ) ) + return; + + if( !(bHasAmbiguousValue || aNewValue != aOldValue) ) + return; + + std::vector< rtl::Reference< ChartType > > aChartTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( m_spChart2ModelContact->getDiagram() ) ); + for( sal_Int32 nN = aChartTypes.size(); nN--; ) + { + try + { + aChartTypes[nN]->setPropertyValue(m_aOwnInnerName,convertOuterToInnerValue(uno::Any(aNewValue))); + } + catch( uno::Exception & ex ) + { + //spline properties are not supported by all charttypes + //in that cases this exception is ok + ex.Context.is();//to have debug information without compilation warnings + } + } + } + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const override + { + bool bHasAmbiguousValue = false; + PROPERTYTYPE aValue; + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + m_aOuterValue <<= aValue; + } + return m_aOuterValue; + } + + css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /*xInnerPropertyState*/ ) const override + { + return m_aDefaultValue; + } + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; + // this inner name is not set as inner name at the base class + const OUString m_aOwnInnerName; +}; + +class WrappedSplineTypeProperty : public WrappedSplineProperty< sal_Int32 > +{ +public: + explicit WrappedSplineTypeProperty(const std::shared_ptr& spChart2ModelContact); + + virtual css::uno::Any convertInnerToOuterValue( const css::uno::Any& rInnerValue ) const override; + virtual css::uno::Any convertOuterToInnerValue( const css::uno::Any& rOuterValue ) const override; +}; + +enum +{ + //spline properties + PROP_CHART_SPLINE_TYPE = FAST_PROPERTY_ID_START_CHART_SPLINE_PROP + , PROP_CHART_SPLINE_ORDER + , PROP_CHART_SPLINE_RESOLUTION +}; + +}//anonymous namespace + +void WrappedSplineProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_TYPE, + PROP_CHART_SPLINE_TYPE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_ORDER, + PROP_CHART_SPLINE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_SPLINE_RESOLUTION, + PROP_CHART_SPLINE_RESOLUTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedSplineProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedSplineTypeProperty( spChart2ModelContact ) ); + rList.emplace_back( + new WrappedSplineProperty( + CHART_UNONAME_SPLINE_ORDER, CHART_UNONAME_SPLINE_ORDER, + uno::Any(sal_Int32(3)), spChart2ModelContact)); + rList.emplace_back( + new WrappedSplineProperty( + CHART_UNONAME_SPLINE_RESOLUTION, CHART_UNONAME_CURVE_RESOLUTION, + uno::Any(sal_Int32(20)), spChart2ModelContact)); +} + +WrappedSplineTypeProperty::WrappedSplineTypeProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedSplineProperty(CHART_UNONAME_SPLINE_TYPE, CHART_UNONAME_CURVE_STYLE, uno::Any(sal_Int32(0)), spChart2ModelContact ) +{ +} + +Any WrappedSplineTypeProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + chart2::CurveStyle aInnerValue = chart2::CurveStyle_LINES; + rInnerValue >>= aInnerValue; + + sal_Int32 nOuterValue; + switch (aInnerValue) + { + case chart2::CurveStyle_CUBIC_SPLINES: + nOuterValue = 1; + break; + case chart2::CurveStyle_B_SPLINES: + nOuterValue = 2; + break; + case chart2::CurveStyle_STEP_START: + nOuterValue = 3; + break; + case chart2::CurveStyle_STEP_END: + nOuterValue = 4; + break; + case chart2::CurveStyle_STEP_CENTER_X: + nOuterValue = 5; + break; + case chart2::CurveStyle_STEP_CENTER_Y: + nOuterValue = 6; + break; + default: + nOuterValue = 0; + } + + return uno::Any(nOuterValue); +} +Any WrappedSplineTypeProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + sal_Int32 nOuterValue=0; + rOuterValue >>= nOuterValue; + + chart2::CurveStyle aInnerValue; + + switch (nOuterValue) + { + case 1: + aInnerValue = chart2::CurveStyle_CUBIC_SPLINES; + break; + case 2: + aInnerValue = chart2::CurveStyle_B_SPLINES; + break; + case 3: + aInnerValue = chart2::CurveStyle_STEP_START; + break; + case 4: + aInnerValue = chart2::CurveStyle_STEP_END; + break; + case 5: + aInnerValue = chart2::CurveStyle_STEP_CENTER_X; + break; + case 6: + aInnerValue = chart2::CurveStyle_STEP_CENTER_Y; + break; + default: + SAL_WARN_IF(nOuterValue != 0, "chart2", "Unknown line style"); + aInnerValue = chart2::CurveStyle_LINES; + } + + return uno::Any(aInnerValue); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx new file mode 100644 index 000000000..686a69297 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedSplineProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx new file mode 100644 index 000000000..2de01cc8b --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx @@ -0,0 +1,1072 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedStatisticProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::chart2::data { class XDataProvider; } + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +Any lcl_getRegressionDefault() +{ + Any aRet; + aRet <<= css::chart::ChartRegressionCurveType_NONE; + return aRet; +} + +css::chart::ChartRegressionCurveType lcl_getRegressionCurveType(SvxChartRegress eRegressionType) +{ + css::chart::ChartRegressionCurveType eRet = css::chart::ChartRegressionCurveType_NONE; + switch(eRegressionType) + { + case SvxChartRegress::Linear: + eRet = css::chart::ChartRegressionCurveType_LINEAR; + break; + case SvxChartRegress::Log: + eRet = css::chart::ChartRegressionCurveType_LOGARITHM; + break; + case SvxChartRegress::Exp: + eRet = css::chart::ChartRegressionCurveType_EXPONENTIAL; + break; + case SvxChartRegress::Power: + eRet = css::chart::ChartRegressionCurveType_POWER; + break; + case SvxChartRegress::Polynomial: + eRet = css::chart::ChartRegressionCurveType_POLYNOMIAL; + break; + /*case SvxChartRegress::MovingAverage: + eRet = css::chart::ChartRegressionCurveType_MOVING_AVERAGE; + break;*/ + default: + eRet = css::chart::ChartRegressionCurveType_NONE; + break; + } + return eRet; +} + +SvxChartRegress lcl_getRegressionType( css::chart::ChartRegressionCurveType eRegressionCurveType ) +{ + SvxChartRegress eRet; + switch (eRegressionCurveType) + { + case css::chart::ChartRegressionCurveType_LINEAR: + eRet = SvxChartRegress::Linear; + break; + case css::chart::ChartRegressionCurveType_LOGARITHM: + eRet = SvxChartRegress::Log; + break; + case css::chart::ChartRegressionCurveType_EXPONENTIAL: + eRet = SvxChartRegress::Exp; + break; + case css::chart::ChartRegressionCurveType_POLYNOMIAL: + //case css::chart::ChartRegressionCurveType_MOVING_AVERAGE: + case css::chart::ChartRegressionCurveType_POWER: + eRet = SvxChartRegress::Power; + break; + default: + eRet = SvxChartRegress::NONE; + break; + } + return eRet; +} + +sal_Int32 lcl_getErrorBarStyle( const uno::Reference< beans::XPropertySet >& xErrorBarProperties ) +{ + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if(xErrorBarProperties.is()) + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nStyle; + return nStyle; +} + +uno::Reference< chart2::data::XDataProvider > lcl_getDataProviderFromContact( + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + uno::Reference< chart2::data::XDataProvider > xResult; + if( spChart2ModelContact) + { + rtl::Reference< ChartModel > xChartDoc( + spChart2ModelContact->getDocumentModel()); + if( xChartDoc.is()) + xResult.set( xChartDoc->getDataProvider()); + } + return xResult; +} + +void lcl_ConvertRangeFromXML( + OUString & rInOutRange, + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + if( !rInOutRange.isEmpty()) + { + uno::Reference< chart2::data::XRangeXMLConversion > xConverter( + lcl_getDataProviderFromContact( spChart2ModelContact ), uno::UNO_QUERY ); + if( xConverter.is()) + { + OUString aResult = xConverter->convertRangeFromXML( rInOutRange ); + rInOutRange = aResult; + } + } +} + +void lcl_ConvertRangeToXML( + OUString & rInOutRange, + const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + if( !rInOutRange.isEmpty()) + { + uno::Reference< chart2::data::XRangeXMLConversion > xConverter( + lcl_getDataProviderFromContact( spChart2ModelContact ), uno::UNO_QUERY ); + if( xConverter.is()) + { + OUString aResult = xConverter->convertRangeToXML( rInOutRange ); + rInOutRange = aResult; + } + } +} + +template< typename PROPERTYTYPE > +class WrappedStatisticProperty : public WrappedSeriesOrDiagramProperty< PROPERTYTYPE > +{ +public: + explicit WrappedStatisticProperty( + const OUString& rName, const Any& rDefaulValue, + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType) + : WrappedSeriesOrDiagramProperty(rName, rDefaulValue, spChart2ModelContact, + ePropertyType) + {} + +protected: + static uno::Reference< beans::XPropertySet > getOrCreateErrorBarProperties( const Reference< beans::XPropertySet >& xSeriesPropertySet ) + { + if(!xSeriesPropertySet.is()) + return nullptr; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties; + if( !xErrorBarProperties.is() ) + { + xErrorBarProperties = new ::chart::ErrorBar; + //default in new and old api are different + xErrorBarProperties->setPropertyValue( "ShowPositiveError" , uno::Any(false) ); + xErrorBarProperties->setPropertyValue( "ShowNegativeError" , uno::Any(false) ); + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any(css::chart::ErrorBarStyle::NONE) ); + xSeriesPropertySet->setPropertyValue( CHART_UNONAME_ERRORBAR_Y , uno::Any( xErrorBarProperties ) ); + } + return xErrorBarProperties; + } + +}; + +//PROP_CHART_STATISTIC_CONST_ERROR_LOW +class WrappedConstantErrorLowProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedConstantErrorLowProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +}//anonymous namespace + +WrappedConstantErrorLowProperty::WrappedConstantErrorLowProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ConstantErrorLow" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedConstantErrorLowProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + xErrorBarProperties->getPropertyValue( "NegativeError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} + +void WrappedConstantErrorLowProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + { + xErrorBarProperties->setPropertyValue( "NegativeError", m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_CONST_ERROR_HIGH +class WrappedConstantErrorHighProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedConstantErrorHighProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedConstantErrorHighProperty::WrappedConstantErrorHighProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ConstantErrorHigh" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedConstantErrorHighProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} + +void WrappedConstantErrorHighProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ABSOLUTE ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_MEAN_VALUE +class WrappedMeanValueProperty : public WrappedStatisticProperty< bool > +{ +public: + virtual bool getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& aNewValue ) const override; + + explicit WrappedMeanValueProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedMeanValueProperty::WrappedMeanValueProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< bool >( "MeanValue", uno::Any( false ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +bool WrappedMeanValueProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + bool bRet = false; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + bRet = RegressionCurveHelper::hasMeanValueLine( xRegCnt ); + return bRet; +} + +void WrappedMeanValueProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& aNewValue ) const +{ + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + { + if(aNewValue) + RegressionCurveHelper::addMeanValueLine( xRegCnt, nullptr ); + else + RegressionCurveHelper::removeMeanValueLine( xRegCnt ); + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_CATEGORY +// deprecated, replaced by ErrorBarStyle +class WrappedErrorCategoryProperty : public WrappedStatisticProperty< css::chart::ChartErrorCategory > +{ +public: + virtual css::chart::ChartErrorCategory getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorCategory& aNewValue ) const override; + + explicit WrappedErrorCategoryProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorCategoryProperty::WrappedErrorCategoryProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartErrorCategory >( "ErrorCategory" + , uno::Any( css::chart::ChartErrorCategory_NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartErrorCategory WrappedErrorCategoryProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartErrorCategory aRet = css::chart::ChartErrorCategory_NONE; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nStyle; + switch(nStyle) + { + case css::chart::ErrorBarStyle::NONE: + aRet = css::chart::ChartErrorCategory_NONE; + break; + case css::chart::ErrorBarStyle::VARIANCE: + aRet = css::chart::ChartErrorCategory_VARIANCE; + break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + aRet = css::chart::ChartErrorCategory_STANDARD_DEVIATION; + break; + case css::chart::ErrorBarStyle::ABSOLUTE: + aRet = css::chart::ChartErrorCategory_CONSTANT_VALUE; + break; + case css::chart::ErrorBarStyle::RELATIVE: + aRet = css::chart::ChartErrorCategory_PERCENT; + break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + aRet = css::chart::ChartErrorCategory_ERROR_MARGIN; + break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + break; + case css::chart::ErrorBarStyle::FROM_DATA: + break; + default: + break; + } + } + return aRet; +} +void WrappedErrorCategoryProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorCategory& aNewValue ) const +{ + if( !xSeriesPropertySet.is() ) + return; + + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + sal_Int32 nNewStyle = css::chart::ErrorBarStyle::NONE; + switch(aNewValue) + { + case css::chart::ChartErrorCategory_NONE: + nNewStyle = css::chart::ErrorBarStyle::NONE; + break; + case css::chart::ChartErrorCategory_VARIANCE: + nNewStyle = css::chart::ErrorBarStyle::VARIANCE; + break; + case css::chart::ChartErrorCategory_STANDARD_DEVIATION: + nNewStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; + break; + case css::chart::ChartErrorCategory_CONSTANT_VALUE: + nNewStyle = css::chart::ErrorBarStyle::ABSOLUTE; + break; + case css::chart::ChartErrorCategory_PERCENT: + nNewStyle = css::chart::ErrorBarStyle::RELATIVE; + break; + case css::chart::ChartErrorCategory_ERROR_MARGIN: + nNewStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; + break; + default: + break; + } + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any(nNewStyle) ); +} + +namespace { + +//PROP_CHART_STATISTIC_PERCENT_ERROR +class WrappedPercentageErrorProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedPercentageErrorProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedPercentageErrorProperty::WrappedPercentageErrorProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "PercentageError" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedPercentageErrorProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::RELATIVE ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} +void WrappedPercentageErrorProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::RELATIVE ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + xErrorBarProperties->setPropertyValue( "NegativeError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_MARGIN +class WrappedErrorMarginProperty : public WrappedStatisticProperty< double > +{ +public: + virtual double getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const override; + + explicit WrappedErrorMarginProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + mutable Any m_aOuterValue; +}; + +} + +WrappedErrorMarginProperty::WrappedErrorMarginProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< double >( "ErrorMargin" + , uno::Any( 0.0 ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +double WrappedErrorMarginProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + double aRet = 0.0; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ERROR_MARGIN ) + xErrorBarProperties->getPropertyValue( "PositiveError" ) >>= aRet; + else + m_aOuterValue >>= aRet; + } + return aRet; +} +void WrappedErrorMarginProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const double& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + m_aOuterValue <<= aNewValue; + if( lcl_getErrorBarStyle( xErrorBarProperties ) == css::chart::ErrorBarStyle::ERROR_MARGIN ) + { + xErrorBarProperties->setPropertyValue( "PositiveError" , m_aOuterValue ); + xErrorBarProperties->setPropertyValue( "NegativeError" , m_aOuterValue ); + } + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_INDICATOR +class WrappedErrorIndicatorProperty : public WrappedStatisticProperty< css::chart::ChartErrorIndicatorType > +{ +public: + virtual css::chart::ChartErrorIndicatorType getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorIndicatorType& aNewValue ) const override; + + explicit WrappedErrorIndicatorProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorIndicatorProperty::WrappedErrorIndicatorProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartErrorIndicatorType >( "ErrorIndicator" + , uno::Any( css::chart::ChartErrorIndicatorType_NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartErrorIndicatorType WrappedErrorIndicatorProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartErrorIndicatorType aRet = css::chart::ChartErrorIndicatorType_NONE; + m_aDefaultValue >>= aRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + bool bPositive = false; + bool bNegative = false; + xErrorBarProperties->getPropertyValue( "ShowPositiveError" ) >>= bPositive; + xErrorBarProperties->getPropertyValue( "ShowNegativeError" ) >>= bNegative; + + if( bPositive && bNegative ) + aRet = css::chart::ChartErrorIndicatorType_TOP_AND_BOTTOM; + else if( bPositive && !bNegative ) + aRet = css::chart::ChartErrorIndicatorType_UPPER; + else if( !bPositive && bNegative ) + aRet = css::chart::ChartErrorIndicatorType_LOWER; + } + return aRet; +} +void WrappedErrorIndicatorProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartErrorIndicatorType& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + bool bPositive = false; + bool bNegative = false; + switch( aNewValue ) + { + case css::chart::ChartErrorIndicatorType_TOP_AND_BOTTOM: + bPositive = true; + bNegative = true; + break; + case css::chart::ChartErrorIndicatorType_UPPER: + bPositive = true; + break; + case css::chart::ChartErrorIndicatorType_LOWER: + bNegative = true; + break; + default: + break; + } + + xErrorBarProperties->setPropertyValue( "ShowPositiveError" , uno::Any(bPositive) ); + xErrorBarProperties->setPropertyValue( "ShowNegativeError" , uno::Any(bNegative) ); +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_BAR_STYLE +// this is the new constant group that replaces the deprecated enum ChartErrorCategory +class WrappedErrorBarStyleProperty : public WrappedStatisticProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nNewValue ) const override; + + explicit WrappedErrorBarStyleProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact1, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarStyleProperty::WrappedErrorBarStyleProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< sal_Int32 >( "ErrorBarStyle" + , uno::Any( css::chart::ErrorBarStyle::NONE ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +sal_Int32 WrappedErrorBarStyleProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 nRet = css::chart::ErrorBarStyle::NONE; + m_aDefaultValue >>= nRet; + uno::Reference< beans::XPropertySet > xErrorBarProperties; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarProperties ) && xErrorBarProperties.is()) + { + xErrorBarProperties->getPropertyValue( "ErrorBarStyle" ) >>= nRet; + } + return nRet; +} +void WrappedErrorBarStyleProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nNewValue ) const +{ + if( !xSeriesPropertySet.is() ) + return; + + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( xErrorBarProperties.is() ) + { + xErrorBarProperties->setPropertyValue( "ErrorBarStyle" , uno::Any( nNewValue )); + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE +class WrappedErrorBarRangePositiveProperty : public WrappedStatisticProperty< OUString > +{ +public: + virtual OUString getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const override; + + explicit WrappedErrorBarRangePositiveProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarRangePositiveProperty::WrappedErrorBarRangePositiveProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< OUString >( "ErrorBarRangePositive" + , uno::Any( OUString() ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +OUString WrappedErrorBarRangePositiveProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + OUString aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::data::XDataSource > xErrorBarDataSource; + if( xSeriesPropertySet.is() && + ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarDataSource ) && + xErrorBarDataSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarDataSource, true /* positive */ )); + if( xSeq.is()) + aRet = xSeq->getSourceRangeRepresentation(); + else + m_aOuterValue >>= aRet; + } + lcl_ConvertRangeToXML( aRet, m_spChart2ModelContact ); + return aRet; +} + +void WrappedErrorBarRangePositiveProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + uno::Reference< chart2::data::XDataProvider > xDataProvider( + lcl_getDataProviderFromContact( m_spChart2ModelContact )); + uno::Reference< chart2::data::XDataSource > xDataSource( xErrorBarProperties, uno::UNO_QUERY ); + if( xDataSource.is() && xDataProvider.is()) + { + OUString aTmp( aNewValue ); + OUString aXMLRange( aNewValue ); + lcl_ConvertRangeFromXML( aTmp, m_spChart2ModelContact ); + StatisticsHelper::setErrorDataSequence( + xDataSource, xDataProvider, aTmp, true /* positive */, true /* y-error */, &aXMLRange ); + m_aOuterValue <<= aTmp; + } +} + +namespace { + +//PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE +class WrappedErrorBarRangeNegativeProperty : public WrappedStatisticProperty< OUString > +{ +public: + virtual OUString getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const override; + + explicit WrappedErrorBarRangeNegativeProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedErrorBarRangeNegativeProperty::WrappedErrorBarRangeNegativeProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< OUString >( "ErrorBarRangeNegative" + , uno::Any( OUString() ), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +OUString WrappedErrorBarRangeNegativeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + OUString aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::data::XDataSource > xErrorBarDataSource; + if( xSeriesPropertySet.is() && + ( xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xErrorBarDataSource ) && + xErrorBarDataSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarDataSource, false /* positive */ )); + if( xSeq.is()) + aRet = xSeq->getSourceRangeRepresentation(); + else + m_aOuterValue >>= aRet; + } + lcl_ConvertRangeToXML( aRet, m_spChart2ModelContact ); + return aRet; +} + +void WrappedErrorBarRangeNegativeProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const OUString& aNewValue ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProperties( getOrCreateErrorBarProperties(xSeriesPropertySet) ); + if( !xErrorBarProperties.is() ) + return; + + uno::Reference< chart2::data::XDataProvider > xDataProvider( + lcl_getDataProviderFromContact( m_spChart2ModelContact )); + uno::Reference< chart2::data::XDataSource > xDataSource( xErrorBarProperties, uno::UNO_QUERY ); + if( xDataSource.is() && xDataProvider.is()) + { + OUString aTmp( aNewValue ); + OUString aXMLRange( aNewValue ); + lcl_ConvertRangeFromXML( aTmp, m_spChart2ModelContact ); + StatisticsHelper::setErrorDataSequence( + xDataSource, xDataProvider, aTmp, false /* positive */, true /* y-error */, &aXMLRange ); + m_aOuterValue <<= aTmp; + } +} + +namespace { + +//PROP_CHART_STATISTIC_REGRESSION_CURVES +class WrappedRegressionCurvesProperty : public WrappedStatisticProperty< css::chart::ChartRegressionCurveType > +{ +public: + virtual css::chart::ChartRegressionCurveType getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartRegressionCurveType & aNewValue ) const override; + + explicit WrappedRegressionCurvesProperty( std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); +}; + +} + +WrappedRegressionCurvesProperty::WrappedRegressionCurvesProperty( + std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< css::chart::ChartRegressionCurveType >( "RegressionCurves" + , lcl_getRegressionDefault(), std::move(spChart2ModelContact), ePropertyType ) +{ +} + +css::chart::ChartRegressionCurveType WrappedRegressionCurvesProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + css::chart::ChartRegressionCurveType aRet; + m_aDefaultValue >>= aRet; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + if( xRegCnt.is() ) + { + aRet = lcl_getRegressionCurveType( + RegressionCurveHelper::getFirstRegressTypeNotMeanValueLine( xRegCnt ) ); + } + return aRet; +} +void WrappedRegressionCurvesProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const css::chart::ChartRegressionCurveType& aNewValue ) const +{ + uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeriesPropertySet, uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurve > xRegressionCurve( xSeriesPropertySet, uno::UNO_QUERY ); + + if( xRegressionCurveContainer.is() && xRegressionCurve.is() ) + { + SvxChartRegress eNewRegressionType = lcl_getRegressionType( aNewValue ); + + RegressionCurveHelper::changeRegressionCurveType( + eNewRegressionType, + xRegressionCurveContainer, + xRegressionCurve); + } +} + +namespace { + +//PROP_CHART_STATISTIC_REGRESSION_PROPERTIES +//PROP_CHART_STATISTIC_ERROR_PROPERTIES +//PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES +class WrappedStatisticPropertySetProperty : public WrappedStatisticProperty< Reference< beans::XPropertySet > > +{ +public: + virtual Reference< beans::XPropertySet > getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + // properties are read-only, so this method should never be called + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const Reference< beans::XPropertySet > & xNewValue ) const override; + + enum PropertySetType + { + PROPERTY_SET_TYPE_REGRESSION, + PROPERTY_SET_TYPE_ERROR_BAR, + PROPERTY_SET_TYPE_MEAN_VALUE + }; + + explicit WrappedStatisticPropertySetProperty( + PropertySetType ePropertySetType, std::shared_ptr< Chart2ModelContact > spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ); + +private: + PropertySetType m_eType; +}; + +} + +WrappedStatisticPropertySetProperty::WrappedStatisticPropertySetProperty( + PropertySetType ePropertySetType + , std::shared_ptr< Chart2ModelContact > spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedStatisticProperty< Reference< beans::XPropertySet > >( + (ePropertySetType == PROPERTY_SET_TYPE_REGRESSION) + ? OUString("DataRegressionProperties") + : (ePropertySetType == PROPERTY_SET_TYPE_ERROR_BAR) + ? OUString("DataErrorProperties") + : OUString("DataMeanValueProperties") + , uno::Any(), std::move(spChart2ModelContact), ePropertyType ) + , m_eType( ePropertySetType ) +{ +} + +Reference< beans::XPropertySet > WrappedStatisticPropertySetProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + Reference< beans::XPropertySet > xResult; + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropertySet, uno::UNO_QUERY ); + + switch( m_eType ) + { + case PROPERTY_SET_TYPE_REGRESSION: + if( xRegCnt.is() ) + xResult = RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt ); + break; + case PROPERTY_SET_TYPE_ERROR_BAR: + if( xSeriesPropertySet.is()) + xSeriesPropertySet->getPropertyValue( CHART_UNONAME_ERRORBAR_Y ) >>= xResult; + break; + case PROPERTY_SET_TYPE_MEAN_VALUE: + if( xRegCnt.is() ) + xResult = RegressionCurveHelper::getMeanValueLine( xRegCnt ); + break; + } + + return xResult; +} + +void WrappedStatisticPropertySetProperty::setValueToSeries( + const Reference< beans::XPropertySet >& /* xSeriesPropertySet */ + , const Reference< beans::XPropertySet >& /* xNewValue */ ) const +{ +} + +namespace +{ +enum +{ + //statistic properties + PROP_CHART_STATISTIC_CONST_ERROR_LOW = FAST_PROPERTY_ID_START_CHART_STATISTIC_PROP, + PROP_CHART_STATISTIC_CONST_ERROR_HIGH, + PROP_CHART_STATISTIC_MEAN_VALUE, + PROP_CHART_STATISTIC_ERROR_CATEGORY, + PROP_CHART_STATISTIC_ERROR_BAR_STYLE, + PROP_CHART_STATISTIC_PERCENT_ERROR, + PROP_CHART_STATISTIC_ERROR_MARGIN, + PROP_CHART_STATISTIC_ERROR_INDICATOR, + PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE, + PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE, + PROP_CHART_STATISTIC_REGRESSION_CURVES, + PROP_CHART_STATISTIC_REGRESSION_PROPERTIES, + PROP_CHART_STATISTIC_ERROR_PROPERTIES, + PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES +}; + +/** @parameter bDataSeriesProperty if true, this property is for a single data + series, if false, it is for the whole diagram, i.e. for all + series + */ +void lcl_addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + rList.emplace_back( new WrappedConstantErrorLowProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedConstantErrorHighProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedMeanValueProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorCategoryProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarStyleProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedPercentageErrorProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorMarginProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorIndicatorProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarRangePositiveProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedErrorBarRangeNegativeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedRegressionCurvesProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_REGRESSION, spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_ERROR_BAR, spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedStatisticPropertySetProperty( + WrappedStatisticPropertySetProperty::PROPERTY_SET_TYPE_MEAN_VALUE, spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedStatisticProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ConstantErrorLow", + PROP_CHART_STATISTIC_CONST_ERROR_LOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ConstantErrorHigh", + PROP_CHART_STATISTIC_CONST_ERROR_HIGH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "MeanValue", + PROP_CHART_STATISTIC_MEAN_VALUE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorCategory", + PROP_CHART_STATISTIC_ERROR_CATEGORY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarStyle", + PROP_CHART_STATISTIC_ERROR_BAR_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "PercentageError", + PROP_CHART_STATISTIC_PERCENT_ERROR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorMargin", + PROP_CHART_STATISTIC_ERROR_MARGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorIndicator", + PROP_CHART_STATISTIC_ERROR_INDICATOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarRangePositive", + PROP_CHART_STATISTIC_ERROR_RANGE_POSITIVE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ErrorBarRangeNegative", + PROP_CHART_STATISTIC_ERROR_RANGE_NEGATIVE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "RegressionCurves", + PROP_CHART_STATISTIC_REGRESSION_CURVES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DataRegressionProperties", + PROP_CHART_STATISTIC_REGRESSION_PROPERTIES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "DataErrorProperties", + PROP_CHART_STATISTIC_ERROR_PROPERTIES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "DataMeanValueProperties", + PROP_CHART_STATISTIC_MEAN_VALUE_PROPERTIES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::READONLY + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedStatisticProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedStatisticProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx new file mode 100644 index 000000000..7831fccf4 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedStatisticProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx new file mode 100644 index 000000000..23c0b0fe5 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.cxx @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedStockProperties.hxx" +#include "Chart2ModelContact.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace { + +class WrappedStockProperty : public WrappedProperty +{ +public: + explicit WrappedStockProperty( const OUString& rOuterName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr& spChart2ModelContact ); + + void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const = 0; + +protected: + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + mutable css::uno::Any m_aOuterValue; + css::uno::Any m_aDefaultValue; +}; + +} + +WrappedStockProperty::WrappedStockProperty( const OUString& rOuterName + , const css::uno::Any& rDefaulValue + , const std::shared_ptr& spChart2ModelContact ) + : WrappedProperty(rOuterName,OUString()) + , m_spChart2ModelContact(spChart2ModelContact) + , m_aDefaultValue(rDefaulValue) +{ +} + +void WrappedStockProperty::setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + bool bNewValue = false; + if( ! (rOuterValue >>= bNewValue) ) + throw lang::IllegalArgumentException( "stock properties require type sal_Bool", nullptr, 0 ); + + m_aOuterValue = rOuterValue; + + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + sal_Int32 nDimension = ::chart::DiagramHelper::getDimension( xDiagram ); + if( !(xChartDoc.is() && xDiagram.is() && nDimension==2) ) + return; + + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate = + getNewTemplate( bNewValue, aTemplateAndService.sServiceName, xChartTypeManager ); + + if(!xTemplate.is()) + return; + + try + { + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( m_spChart2ModelContact->getDocumentModel() ); + xTemplate->changeDiagram( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +css::uno::Any WrappedStockProperty::getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + return m_aDefaultValue; +} + +namespace { + +class WrappedVolumeProperty : public WrappedStockProperty +{ +public: + explicit WrappedVolumeProperty(const std::shared_ptr& spChart2ModelContact); + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const override; +}; + +} + +WrappedVolumeProperty::WrappedVolumeProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedStockProperty( "Volume", uno::Any(false) , spChart2ModelContact ) +{ +} + +css::uno::Any WrappedVolumeProperty::getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeLowHighClose" + || aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + m_aOuterValue <<= true; + else if( !aTemplateAndService.sServiceName.isEmpty() || !m_aOuterValue.hasValue() ) + m_aOuterValue <<= false; + } + else if(!m_aOuterValue.hasValue()) + m_aOuterValue <<= false; + } + return m_aOuterValue; +} + +rtl::Reference< ::chart::ChartTypeTemplate > WrappedVolumeProperty::getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ::chart::ChartTypeManager >& xFactory ) const +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + + if(!xFactory.is()) + return xTemplate; + + if( bNewValue ) //add volume + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ); + } + else //remove volume + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockOpenLowHighClose" ); + } + return xTemplate; +} + +namespace { + +class WrappedUpDownProperty : public WrappedStockProperty +{ +public: + explicit WrappedUpDownProperty(const std::shared_ptr& spChart2ModelContact); + + css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + rtl::Reference< ::chart::ChartTypeTemplate > getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ChartTypeManager >& xFactory ) const override; +}; + +} + +WrappedUpDownProperty::WrappedUpDownProperty(const std::shared_ptr& spChart2ModelContact) + : WrappedStockProperty( "UpDown", uno::Any(false) , spChart2ModelContact ) +{ +} + +css::uno::Any WrappedUpDownProperty::getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& /*xInnerPropertySet*/ ) const +{ + rtl::Reference< ChartModel > xChartDoc( m_spChart2ModelContact->getDocumentModel() ); + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + if( xDiagram.is() && xChartDoc.is() ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + if( !aSeriesVector.empty() ) + { + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartDoc->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + + if( aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockOpenLowHighClose" + || aTemplateAndService.sServiceName == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + m_aOuterValue <<= true; + else if( !aTemplateAndService.sServiceName.isEmpty() || !m_aOuterValue.hasValue() ) + m_aOuterValue <<= false; + } + else if(!m_aOuterValue.hasValue()) + m_aOuterValue <<= false; + } + return m_aOuterValue; +} +rtl::Reference< ::chart::ChartTypeTemplate > WrappedUpDownProperty::getNewTemplate( bool bNewValue, const OUString& rCurrentTemplate, const rtl::Reference< ChartTypeManager >& xFactory ) const +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + if( bNewValue ) //add open series + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockOpenLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ); + } + else //remove open series + { + if( rCurrentTemplate == "com.sun.star.chart2.template.StockOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockLowHighClose" ); + else if( rCurrentTemplate == "com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ) + xTemplate = xFactory->createTemplate( "com.sun.star.chart2.template.StockVolumeLowHighClose" ); + } + return xTemplate; +} + +namespace +{ +enum +{ + //spline properties + PROP_CHART_STOCK_VOLUME = FAST_PROPERTY_ID_START_CHART_STOCK_PROP + , PROP_CHART_STOCK_UPDOWN +}; + +}//anonymous namespace + +void WrappedStockProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Volume", + PROP_CHART_STOCK_VOLUME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "UpDown", + PROP_CHART_STOCK_UPDOWN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); +} + +void WrappedStockProperties::addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + rList.emplace_back( new WrappedVolumeProperty( spChart2ModelContact ) ); + rList.emplace_back( new WrappedUpDownProperty( spChart2ModelContact ) ); +} + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx new file mode 100644 index 000000000..e460ba587 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedStockProperties.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedStockProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx new file mode 100644 index 000000000..7e2934872 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.cxx @@ -0,0 +1,531 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedSymbolProperties.hxx" +#include "WrappedSeriesOrDiagramProperty.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace chart::wrapper +{ + +namespace +{ + +class WrappedSymbolTypeProperty : public WrappedSeriesOrDiagramProperty< sal_Int32 > +{ +public: + virtual sal_Int32 getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& aNewValue ) const override; + + virtual Any getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolTypeProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolBitmapURLProperty : public WrappedSeriesOrDiagramProperty +{ +public: + virtual OUString getValueFromSeries(const Reference& xSeriesPropertySet) const override; + virtual void setValueToSeries(const Reference & xSeriesPropertySet, OUString const & xNewGraphicURL) const override; + + explicit WrappedSymbolBitmapURLProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolBitmapProperty : public WrappedSeriesOrDiagramProperty> +{ +public: + virtual uno::Reference getValueFromSeries(const Reference& xSeriesPropertySet) const override; + virtual void setValueToSeries(const Reference & xSeriesPropertySet, uno::Reference const & xNewGraphic) const override; + + explicit WrappedSymbolBitmapProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolSizeProperty : public WrappedSeriesOrDiagramProperty< awt::Size > +{ +public: + virtual awt::Size getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const awt::Size& aNewSize ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolSizeProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +class WrappedSymbolAndLinesProperty : public WrappedSeriesOrDiagramProperty< bool > +{ +public: + virtual bool getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const override; + virtual void setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const bool& bDrawLines ) const override; + virtual beans::PropertyState getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const override; + + explicit WrappedSymbolAndLinesProperty(const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType); +}; + +enum +{ + //symbol properties + PROP_CHART_SYMBOL_TYPE = FAST_PROPERTY_ID_START_CHART_SYMBOL_PROP, + PROP_CHART_SYMBOL_BITMAP_URL, + PROP_CHART_SYMBOL_BITMAP, + PROP_CHART_SYMBOL_SIZE, + PROP_CHART_SYMBOL_AND_LINES +}; + +sal_Int32 lcl_getSymbolType( const css::chart2::Symbol& rSymbol ) +{ + sal_Int32 nSymbol = css::chart::ChartSymbolType::NONE; + switch( rSymbol.Style ) + { + case chart2::SymbolStyle_NONE: + break; + case chart2::SymbolStyle_AUTO: + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + case chart2::SymbolStyle_STANDARD: + nSymbol = rSymbol.StandardSymbol%15; + break; + case chart2::SymbolStyle_POLYGON://new feature + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nSymbol = css::chart::ChartSymbolType::BITMAPURL; + break; + default: + nSymbol = css::chart::ChartSymbolType::AUTO; + break; + } + return nSymbol; +} +void lcl_setSymbolTypeToSymbol( sal_Int32 nSymbolType, chart2::Symbol& rSymbol ) +{ + switch( nSymbolType ) + { + case css::chart::ChartSymbolType::NONE: + rSymbol.Style = chart2::SymbolStyle_NONE; + break; + case css::chart::ChartSymbolType::AUTO: + rSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case css::chart::ChartSymbolType::BITMAPURL: + rSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + default: + rSymbol.Style = chart2::SymbolStyle_STANDARD; + rSymbol.StandardSymbol = nSymbolType; + break; + } +} + +void lcl_addWrappedProperties( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact + , tSeriesOrDiagramPropertyType ePropertyType ) +{ + rList.emplace_back( new WrappedSymbolTypeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolBitmapURLProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolBitmapProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolSizeProperty( spChart2ModelContact, ePropertyType ) ); + rList.emplace_back( new WrappedSymbolAndLinesProperty( spChart2ModelContact, ePropertyType ) ); +} + +}//anonymous namespace + +void WrappedSymbolProperties::addProperties( std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "SymbolType", + PROP_CHART_SYMBOL_TYPE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolBitmapURL", + PROP_CHART_SYMBOL_BITMAP_URL, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolBitmap", + PROP_CHART_SYMBOL_BITMAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "SymbolSize", + PROP_CHART_SYMBOL_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Lines", + PROP_CHART_SYMBOL_AND_LINES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void WrappedSymbolProperties::addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DATA_SERIES ); +} + +void WrappedSymbolProperties::addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ) +{ + lcl_addWrappedProperties( rList, spChart2ModelContact, DIAGRAM ); +} + +WrappedSymbolTypeProperty::WrappedSymbolTypeProperty( + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< sal_Int32 >( "SymbolType" + , uno::Any( css::chart::ChartSymbolType::NONE ) + , spChart2ModelContact + , ePropertyType ) +{ +} + +sal_Int32 WrappedSymbolTypeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + sal_Int32 aRet = 0; + m_aDefaultValue >>= aRet; + chart2::Symbol aSymbol; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol ) ) + aRet = lcl_getSymbolType( aSymbol ); + return aRet; +} + +void WrappedSymbolTypeProperty::setValueToSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet, const sal_Int32& nSymbolType ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol; + + lcl_setSymbolTypeToSymbol( nSymbolType, aSymbol ); + xSeriesPropertySet->setPropertyValue( "Symbol", uno::Any( aSymbol ) ); +} + +Any WrappedSymbolTypeProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + //the old chart (< OOo 2.3) needs symbol-type="automatic" at the plot-area if any of the series should be able to have symbols + if( m_ePropertyType == DIAGRAM ) + { + bool bHasAmbiguousValue = false; + sal_Int32 aValue = 0; + if( detectInnerValue( aValue, bHasAmbiguousValue ) ) + { + if(bHasAmbiguousValue) + { + m_aOuterValue <<= css::chart::ChartSymbolType::AUTO; + } + else + { + if( aValue == css::chart::ChartSymbolType::NONE ) + m_aOuterValue <<= css::chart::ChartSymbolType::NONE; + else + m_aOuterValue <<= css::chart::ChartSymbolType::AUTO; + } + } + return m_aOuterValue; + } + else + { + css::uno::Any aRet( m_aDefaultValue ); + aRet <<= getValueFromSeries( xInnerPropertySet ); + return aRet; + } +} + +beans::PropertyState WrappedSymbolTypeProperty::getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + //the special situation for this property here is that the diagram default can be + //different from the normal default and different from all singles series values + //so we need to return PropertyState_DIRECT_VALUE for more cases + + if( m_ePropertyType == DATA_SERIES && //single series or point + m_spChart2ModelContact) + { + rtl::Reference< ::chart::Diagram > xDiagram( m_spChart2ModelContact->getDiagram() ); + Reference< chart2::XDataSeries > xSeries( xInnerPropertyState, uno::UNO_QUERY ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( ChartTypeHelper::isSupportingSymbolProperties( xChartType, 2 ) ) + return beans::PropertyState_DIRECT_VALUE; + } + return WrappedProperty::getPropertyState( xInnerPropertyState ); +} + +WrappedSymbolBitmapURLProperty::WrappedSymbolBitmapURLProperty( + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty("SymbolBitmapURL", + uno::Any(OUString()), spChart2ModelContact, ePropertyType) +{ +} + +OUString WrappedSymbolBitmapURLProperty::getValueFromSeries(const Reference< beans::XPropertySet >& /*xSeriesPropertySet*/) const +{ + return OUString(); +} + +void WrappedSymbolBitmapURLProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + OUString const & xNewGraphicURL) const +{ + if (!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + { + if (!xNewGraphicURL.isEmpty()) + { + Graphic aGraphic = vcl::graphic::loadFromURL(xNewGraphicURL); + aSymbol.Graphic.set(aGraphic.GetXGraphic()); + xSeriesPropertySet->setPropertyValue("Symbol", uno::Any(aSymbol)); + } + } +} + +WrappedSymbolBitmapProperty::WrappedSymbolBitmapProperty( + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty>("SymbolBitmap", + uno::Any(uno::Reference()), spChart2ModelContact, ePropertyType) +{ +} + +uno::Reference WrappedSymbolBitmapProperty::getValueFromSeries(const Reference< beans::XPropertySet >& xSeriesPropertySet) const +{ + uno::Reference xGraphic; + m_aDefaultValue >>= xGraphic; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet.is() && (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + && aSymbol.Graphic.is()) + { + xGraphic = aSymbol.Graphic; + } + return xGraphic; +} + +void WrappedSymbolBitmapProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + uno::Reference const & xNewGraphic) const +{ + if (!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if (xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol) + { + if (xNewGraphic.is()) + { + aSymbol.Graphic.set(xNewGraphic); + xSeriesPropertySet->setPropertyValue("Symbol", uno::Any(aSymbol)); + } + } +} + +namespace +{ + +void lcl_correctSymbolSizeForBitmaps( chart2::Symbol& rSymbol ) +{ + if( rSymbol.Style != chart2::SymbolStyle_GRAPHIC ) + return; + if( rSymbol.Size.Width != -1 ) + return; + if( rSymbol.Size.Height != -1 ) + return; + + //find a good automatic size + try + { + const awt::Size aDefaultSize(250,250); + awt::Size aSize = aDefaultSize; + uno::Reference< beans::XPropertySet > xProp( rSymbol.Graphic, uno::UNO_QUERY ); + if( xProp.is() ) + { + bool bFoundSize = false; + try + { + if( xProp->getPropertyValue( "Size100thMM" ) >>= aSize ) + { + if( aSize.Width == 0 && aSize.Height == 0 ) + aSize = aDefaultSize; + else + bFoundSize = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + if(!bFoundSize) + { + awt::Size aAWTPixelSize(10,10); + if( xProp->getPropertyValue( "SizePixel" ) >>= aAWTPixelSize ) + { + Size aPixelSize(aAWTPixelSize.Width,aAWTPixelSize.Height); + Size aNewSize = o3tl::convert(aPixelSize, o3tl::Length::pt, o3tl::Length::mm100); + + aSize = awt::Size( aNewSize.Width(), aNewSize.Height() ); + + if( aSize.Width == 0 && aSize.Height == 0 ) + aSize = aDefaultSize; + } + } + } + rSymbol.Size = aSize; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +}//end anonymous namespace + +WrappedSymbolSizeProperty::WrappedSymbolSizeProperty( + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< awt::Size >( "SymbolSize" + , uno::Any( awt::Size(250,250) ), spChart2ModelContact, ePropertyType ) +{ +} + +awt::Size WrappedSymbolSizeProperty::getValueFromSeries( const Reference< beans::XPropertySet >& xSeriesPropertySet ) const +{ + awt::Size aRet; + m_aDefaultValue >>= aRet; + chart2::Symbol aSymbol; + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol )) + aRet = aSymbol.Size; + return aRet; +} + +void WrappedSymbolSizeProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + const awt::Size& aNewSize ) const +{ + if(!xSeriesPropertySet.is()) + return; + + chart2::Symbol aSymbol; + if( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol ) + { + aSymbol.Size = aNewSize; + lcl_correctSymbolSizeForBitmaps(aSymbol); + xSeriesPropertySet->setPropertyValue( "Symbol", uno::Any( aSymbol ) ); + } +} + +beans::PropertyState WrappedSymbolSizeProperty::getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + //only export symbol size if necessary + if( m_ePropertyType == DIAGRAM ) + return beans::PropertyState_DEFAULT_VALUE; + + try + { + chart2::Symbol aSymbol; + Reference< beans::XPropertySet > xSeriesPropertySet( xInnerPropertyState, uno::UNO_QUERY ); + if( xSeriesPropertySet.is() && ( xSeriesPropertySet->getPropertyValue("Symbol") >>= aSymbol )) + { + if( aSymbol.Style != chart2::SymbolStyle_NONE ) + return beans::PropertyState_DIRECT_VALUE; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return beans::PropertyState_DEFAULT_VALUE; +} + +WrappedSymbolAndLinesProperty::WrappedSymbolAndLinesProperty( + const std::shared_ptr& spChart2ModelContact, + tSeriesOrDiagramPropertyType ePropertyType ) + : WrappedSeriesOrDiagramProperty< bool >( "Lines" + , uno::Any( true ), spChart2ModelContact, ePropertyType ) +{ +} + +bool WrappedSymbolAndLinesProperty::getValueFromSeries( const Reference< beans::XPropertySet >& /*xSeriesPropertySet*/ ) const +{ + //do not export this property anymore, instead use a linestyle none for no lines + return true; +} + +void WrappedSymbolAndLinesProperty::setValueToSeries( + const Reference< beans::XPropertySet >& xSeriesPropertySet, + const bool& bDrawLines ) const +{ + if(!xSeriesPropertySet.is()) + return; + + drawing::LineStyle eOldLineStyle( drawing::LineStyle_SOLID ); + xSeriesPropertySet->getPropertyValue( "LineStyle" ) >>= eOldLineStyle; + if( bDrawLines ) + { + //#i114298# don't overwrite dashed lines with solid lines here + if( eOldLineStyle == drawing::LineStyle_NONE ) + xSeriesPropertySet->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + } + else + { + if( eOldLineStyle != drawing::LineStyle_NONE ) + xSeriesPropertySet->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); + } +} + +beans::PropertyState WrappedSymbolAndLinesProperty::getPropertyState( const Reference< beans::XPropertyState >& /*xInnerPropertyState*/ ) const +{ + //do not export this property anymore, instead use a linestyle none for no lines + return beans::PropertyState_DEFAULT_VALUE; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx new file mode 100644 index 000000000..f3a0fcd66 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedSymbolProperties.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class WrappedProperty; } +namespace chart::wrapper { class Chart2ModelContact; } +namespace com::sun::star::beans { struct Property; } + +namespace chart::wrapper +{ + +class WrappedSymbolProperties +{ +public: + static void addProperties( std::vector< css::beans::Property > & rOutProperties ); + static void addWrappedPropertiesForSeries( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); + static void addWrappedPropertiesForDiagram( std::vector< std::unique_ptr >& rList + , const std::shared_ptr< Chart2ModelContact >& spChart2ModelContact ); +}; + +} //namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx new file mode 100644 index 000000000..c35a75e31 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "WrappedTextRotationProperty.hxx" + +namespace com::sun::star::beans { class XPropertyState; } + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; + +namespace chart +{ + +WrappedTextRotationProperty::WrappedTextRotationProperty( bool bDirectState ) + : ::chart::WrappedProperty( "TextRotation" , "TextRotation" ) + , m_bDirectState( bDirectState ) +{ +} +WrappedTextRotationProperty::~WrappedTextRotationProperty() +{ +} + +beans::PropertyState WrappedTextRotationProperty::getPropertyState( const uno::Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( m_bDirectState ) + return beans::PropertyState_DIRECT_VALUE; + return WrappedProperty::getPropertyState( xInnerPropertyState ); +} + +Any WrappedTextRotationProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + Any aRet; + double fVal = 0; + if( rInnerValue >>= fVal ) + { + sal_Int32 n100thDegrees = static_cast< sal_Int32 >( fVal * 100.0 ); + aRet <<= n100thDegrees; + } + return aRet; +} +Any WrappedTextRotationProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + Any aRet; + sal_Int32 nVal = 0; + if( rOuterValue >>= nVal ) + { + double fDoubleDegrees = static_cast< double >( nVal ) / 100.0; + aRet <<= fDoubleDegrees; + } + return aRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx new file mode 100644 index 000000000..48287dd59 --- /dev/null +++ b/chart2/source/controller/chartapiwrapper/WrappedTextRotationProperty.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class WrappedTextRotationProperty final : public WrappedProperty +{ +public: + explicit WrappedTextRotationProperty(bool bDirectState = false); + virtual ~WrappedTextRotationProperty() override; + + virtual css::beans::PropertyState getPropertyState( + const css::uno::Reference& xInnerPropertyState) const override; + +private: + virtual css::uno::Any convertInnerToOuterValue(const css::uno::Any& rInnerValue) const override; + virtual css::uno::Any convertOuterToInnerValue(const css::uno::Any& rOuterValue) const override; + + bool m_bDirectState; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/chartcontroller.component b/chart2/source/controller/chartcontroller.component new file mode 100644 index 000000000..01201cbb2 --- /dev/null +++ b/chart2/source/controller/chartcontroller.component @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/chart2/source/controller/dialogs/ChangingResource.cxx b/chart2/source/controller/dialogs/ChangingResource.cxx new file mode 100644 index 000000000..4cbbe569c --- /dev/null +++ b/chart2/source/controller/dialogs/ChangingResource.cxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +namespace chart +{ +ResourceChangeListener::~ResourceChangeListener() {} + +ChangingResource::ChangingResource() + : m_pChangeListener(nullptr) +{ +} +ChangingResource::~ChangingResource() {} +void ChangingResource::setChangeListener(ResourceChangeListener* pListener) +{ + m_pChangeListener = pListener; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx b/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx new file mode 100644 index 000000000..91307afaa --- /dev/null +++ b/chart2/source/controller/dialogs/ChartResourceGroupDlgs.cxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +const sal_uInt16 CUBIC_SPLINE_POS = 0; +const sal_uInt16 B_SPLINE_POS = 1; + +SplinePropertiesDialog::SplinePropertiesDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/schart/ui/smoothlinesdlg.ui", "SmoothLinesDialog") + , m_xLB_Spline_Type(m_xBuilder->weld_combo_box("SplineTypeComboBox")) + , m_xMF_SplineResolution(m_xBuilder->weld_spin_button("ResolutionSpinbutton")) + , m_xFT_SplineOrder(m_xBuilder->weld_label("PolynomialsLabel")) + , m_xMF_SplineOrder(m_xBuilder->weld_spin_button("PolynomialsSpinButton")) +{ + m_xDialog->set_title(SchResId(STR_DLG_SMOOTH_LINE_PROPERTIES)); + + m_xLB_Spline_Type->connect_changed(LINK(this, SplinePropertiesDialog, SplineTypeListBoxHdl)); +} + +void SplinePropertiesDialog::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_CUBIC_SPLINES: + m_xLB_Spline_Type->set_active(CUBIC_SPLINE_POS); + break; + case CurveStyle_B_SPLINES: + m_xLB_Spline_Type->set_active(B_SPLINE_POS); + break; + default: + m_xLB_Spline_Type->set_active(CUBIC_SPLINE_POS); + break; + } + m_xMF_SplineOrder->set_value(rParameter.nSplineOrder); + m_xMF_SplineResolution->set_value(rParameter.nCurveResolution); + + //dis/enabling + m_xFT_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); + m_xMF_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); +} + +void SplinePropertiesDialog::fillParameter(ChartTypeParameter& rParameter, bool bSmoothLines) +{ + if (!bSmoothLines) + rParameter.eCurveStyle = CurveStyle_LINES; + else if (m_xLB_Spline_Type->get_active() == CUBIC_SPLINE_POS) + rParameter.eCurveStyle = CurveStyle_CUBIC_SPLINES; + else if (m_xLB_Spline_Type->get_active() == B_SPLINE_POS) + rParameter.eCurveStyle = CurveStyle_B_SPLINES; + + rParameter.nCurveResolution = m_xMF_SplineResolution->get_value(); + rParameter.nSplineOrder = m_xMF_SplineOrder->get_value(); +} + +IMPL_LINK_NOARG(SplinePropertiesDialog, SplineTypeListBoxHdl, weld::ComboBox&, void) +{ + m_xFT_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); + m_xMF_SplineOrder->set_sensitive(m_xLB_Spline_Type->get_active() == B_SPLINE_POS); +} + +SteppedPropertiesDialog::SteppedPropertiesDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/schart/ui/steppedlinesdlg.ui", "SteppedLinesDialog") + , m_xRB_Start(m_xBuilder->weld_radio_button("step_start_rb")) + , m_xRB_End(m_xBuilder->weld_radio_button("step_end_rb")) + , m_xRB_CenterX(m_xBuilder->weld_radio_button("step_center_x_rb")) + , m_xRB_CenterY(m_xBuilder->weld_radio_button("step_center_y_rb")) +{ + m_xDialog->set_title(SchResId(STR_DLG_STEPPED_LINE_PROPERTIES)); +} + +void SteppedPropertiesDialog::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_STEP_END: + m_xRB_End->set_active(true); + break; + case CurveStyle_STEP_CENTER_X: + m_xRB_CenterX->set_active(true); + break; + case CurveStyle_STEP_CENTER_Y: + m_xRB_CenterY->set_active(true); + break; + default: // includes CurveStyle_STEP_START + m_xRB_Start->set_active(true); + break; + } +} +void SteppedPropertiesDialog::fillParameter(ChartTypeParameter& rParameter, bool bSteppedLines) +{ + if (!bSteppedLines) + rParameter.eCurveStyle = CurveStyle_LINES; + else if (m_xRB_CenterY->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_CENTER_Y; + else if (m_xRB_Start->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_START; + else if (m_xRB_End->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_END; + else if (m_xRB_CenterX->get_active()) + rParameter.eCurveStyle = CurveStyle_STEP_CENTER_X; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartResourceGroups.cxx b/chart2/source/controller/dialogs/ChartResourceGroups.cxx new file mode 100644 index 000000000..19534aa1e --- /dev/null +++ b/chart2/source/controller/dialogs/ChartResourceGroups.cxx @@ -0,0 +1,361 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +Dim3DLookResourceGroup::Dim3DLookResourceGroup(weld::Builder* pBuilder) + : m_xCB_3DLook(pBuilder->weld_check_button("3dlook")) + , m_xLB_Scheme(pBuilder->weld_combo_box("3dscheme")) +{ + m_xCB_3DLook->connect_toggled(LINK(this, Dim3DLookResourceGroup, Dim3DLookCheckHdl)); + m_xLB_Scheme->connect_changed(LINK(this, Dim3DLookResourceGroup, SelectSchemeHdl)); +} + +void Dim3DLookResourceGroup::showControls(bool bShow) +{ + m_xCB_3DLook->set_visible(bShow); + m_xLB_Scheme->set_visible(bShow); +} + +void Dim3DLookResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_3DLook->set_active(rParameter.b3DLook); + m_xLB_Scheme->set_sensitive(rParameter.b3DLook); + + // tdf#124295 - select always a 3D scheme + switch (rParameter.eThreeDLookScheme) + { + case ThreeDLookScheme::ThreeDLookScheme_Simple: + m_xLB_Scheme->set_active(POS_3DSCHEME_SIMPLE); + break; + case ThreeDLookScheme::ThreeDLookScheme_Realistic: + case ThreeDLookScheme::ThreeDLookScheme_Unknown: + m_xLB_Scheme->set_active(POS_3DSCHEME_REALISTIC); + break; + } +} + +void Dim3DLookResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.b3DLook = m_xCB_3DLook->get_active(); + // tdf#124295 - select always a 3D scheme + switch (m_xLB_Scheme->get_active()) + { + case POS_3DSCHEME_SIMPLE: + rParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Simple; + break; + default: + rParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + } +} + +IMPL_LINK_NOARG(Dim3DLookResourceGroup, Dim3DLookCheckHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(Dim3DLookResourceGroup, SelectSchemeHdl, weld::ComboBox&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +SortByXValuesResourceGroup::SortByXValuesResourceGroup(weld::Builder* pBuilder) + : m_xCB_XValueSorting(pBuilder->weld_check_button("sort")) +{ + m_xCB_XValueSorting->connect_toggled( + LINK(this, SortByXValuesResourceGroup, SortByXValuesCheckHdl)); +} + +void SortByXValuesResourceGroup::showControls(bool bShow) +{ + m_xCB_XValueSorting->set_visible(bShow); +} + +void SortByXValuesResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_XValueSorting->set_active(rParameter.bSortByXValues); +} + +void SortByXValuesResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.bSortByXValues = m_xCB_XValueSorting->get_active(); +} + +IMPL_LINK_NOARG(SortByXValuesResourceGroup, SortByXValuesCheckHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +StackingResourceGroup::StackingResourceGroup(weld::Builder* pBuilder) + : m_xCB_Stacked(pBuilder->weld_check_button("stack")) + , m_xRB_Stack_Y(pBuilder->weld_radio_button("ontop")) + , m_xRB_Stack_Y_Percent(pBuilder->weld_radio_button("percent")) + , m_xRB_Stack_Z(pBuilder->weld_radio_button("deep")) +{ + m_xCB_Stacked->connect_toggled(LINK(this, StackingResourceGroup, StackingEnableHdl)); + m_xRB_Stack_Y->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); + m_xRB_Stack_Y_Percent->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); + m_xRB_Stack_Z->connect_toggled(LINK(this, StackingResourceGroup, StackingChangeHdl)); +} + +void StackingResourceGroup::showControls(bool bShow) +{ + m_xCB_Stacked->set_visible(bShow); + m_xRB_Stack_Y->set_visible(bShow); + m_xRB_Stack_Y_Percent->set_visible(bShow); + m_xRB_Stack_Z->set_visible(false); +} + +void StackingResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + m_xCB_Stacked->set_active( + rParameter.eStackMode != GlobalStackMode_NONE + && rParameter.eStackMode + != GlobalStackMode_STACK_Z); //todo remove this condition if z stacking radio button is really used + switch (rParameter.eStackMode) + { + case GlobalStackMode_STACK_Y: + m_xRB_Stack_Y->set_active(true); + break; + case GlobalStackMode_STACK_Y_PERCENT: + m_xRB_Stack_Y_Percent->set_active(true); + break; + case GlobalStackMode_STACK_Z: + //todo uncomment this condition if z stacking radio button is really used + /* + if( rParameter.b3DLook ) + m_xRB_Stack_Z->set_active(true); + else + */ + m_xRB_Stack_Y->set_active(true); + break; + default: + m_xRB_Stack_Y->set_active(true); + break; + } + //dis/enabling + m_xCB_Stacked->set_sensitive(!rParameter.bXAxisWithValues); + m_xRB_Stack_Y->set_sensitive(m_xCB_Stacked->get_active() && !rParameter.bXAxisWithValues); + m_xRB_Stack_Y_Percent->set_sensitive(m_xCB_Stacked->get_active() + && !rParameter.bXAxisWithValues); + m_xRB_Stack_Z->set_sensitive(m_xCB_Stacked->get_active() && rParameter.b3DLook); +} + +void StackingResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + if (!m_xCB_Stacked->get_active()) + rParameter.eStackMode = GlobalStackMode_NONE; + else if (m_xRB_Stack_Y->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Y; + else if (m_xRB_Stack_Y_Percent->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Y_PERCENT; + else if (m_xRB_Stack_Z->get_active()) + rParameter.eStackMode = GlobalStackMode_STACK_Z; +} + +IMPL_LINK(StackingResourceGroup, StackingChangeHdl, weld::Toggleable&, rRadio, void) +{ + //for each radio click there are coming two change events + //first uncheck of previous button -> ignore that call + //the second call gives the check of the new button + if (m_pChangeListener && rRadio.get_active()) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(StackingResourceGroup, StackingEnableHdl, weld::Toggleable&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +SplineResourceGroup::SplineResourceGroup(weld::Builder* pBuilder, weld::Window* pParent) + : m_pParent(pParent) + , m_xFT_LineType(pBuilder->weld_label("linetypeft")) + , m_xLB_LineType(pBuilder->weld_combo_box("linetype")) + , m_xPB_DetailsDialog(pBuilder->weld_button("properties")) +{ + m_xLB_LineType->connect_changed(LINK(this, SplineResourceGroup, LineTypeChangeHdl)); +} + +SplinePropertiesDialog& SplineResourceGroup::getSplinePropertiesDialog() +{ + if (!m_xSplinePropertiesDialog) + { + m_xSplinePropertiesDialog.reset(new SplinePropertiesDialog(m_pParent)); + } + return *m_xSplinePropertiesDialog; +} + +SteppedPropertiesDialog& SplineResourceGroup::getSteppedPropertiesDialog() +{ + if (!m_xSteppedPropertiesDialog) + { + m_xSteppedPropertiesDialog.reset(new SteppedPropertiesDialog(m_pParent)); + } + return *m_xSteppedPropertiesDialog; +} + +void SplineResourceGroup::showControls(bool bShow) +{ + m_xFT_LineType->set_visible(bShow); + m_xLB_LineType->set_visible(bShow); + m_xPB_DetailsDialog->set_visible(bShow); +} + +void SplineResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + switch (rParameter.eCurveStyle) + { + case CurveStyle_LINES: + m_xLB_LineType->set_active(POS_LINETYPE_STRAIGHT); + m_xPB_DetailsDialog->set_sensitive(false); + break; + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + m_xLB_LineType->set_active(POS_LINETYPE_SMOOTH); + m_xPB_DetailsDialog->set_sensitive(true); + m_xPB_DetailsDialog->connect_clicked( + LINK(this, SplineResourceGroup, SplineDetailsDialogHdl)); + m_xPB_DetailsDialog->set_tooltip_text(SchResId(STR_DLG_SMOOTH_LINE_PROPERTIES)); + getSplinePropertiesDialog().fillControls(rParameter); + break; + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + m_xLB_LineType->set_active(POS_LINETYPE_STEPPED); + m_xPB_DetailsDialog->set_sensitive(true); + m_xPB_DetailsDialog->connect_clicked( + LINK(this, SplineResourceGroup, SteppedDetailsDialogHdl)); + m_xPB_DetailsDialog->set_tooltip_text(SchResId(STR_DLG_STEPPED_LINE_PROPERTIES)); + getSteppedPropertiesDialog().fillControls(rParameter); + break; + default: + m_xLB_LineType->set_active(-1); + m_xPB_DetailsDialog->set_sensitive(false); + } +} +void SplineResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + switch (m_xLB_LineType->get_active()) + { + case POS_LINETYPE_SMOOTH: + getSplinePropertiesDialog().fillParameter(rParameter, true); + break; + case POS_LINETYPE_STEPPED: + getSteppedPropertiesDialog().fillParameter(rParameter, true); + break; + default: // includes POS_LINETYPE_STRAIGHT + rParameter.eCurveStyle = CurveStyle_LINES; + break; + } +} + +IMPL_LINK_NOARG(SplineResourceGroup, LineTypeChangeHdl, weld::ComboBox&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +IMPL_LINK_NOARG(SplineResourceGroup, SplineDetailsDialogHdl, weld::Button&, void) +{ + ChartTypeParameter aOldParameter; + getSplinePropertiesDialog().fillParameter(aOldParameter, + m_xLB_LineType->get_active() == POS_LINETYPE_SMOOTH); + + const sal_Int32 iOldLineTypePos = m_xLB_LineType->get_active(); + m_xLB_LineType->set_active(POS_LINETYPE_SMOOTH); + if (getSplinePropertiesDialog().run() == RET_OK) + { + if (m_pChangeListener) + m_pChangeListener->stateChanged(); + } + else + { + //restore old state: + m_xLB_LineType->set_active(iOldLineTypePos); + getSplinePropertiesDialog().fillControls(aOldParameter); + } +} + +IMPL_LINK_NOARG(SplineResourceGroup, SteppedDetailsDialogHdl, weld::Button&, void) +{ + ChartTypeParameter aOldParameter; + getSteppedPropertiesDialog().fillParameter(aOldParameter, m_xLB_LineType->get_active() + == POS_LINETYPE_STEPPED); + + const sal_Int32 iOldLineTypePos = m_xLB_LineType->get_active(); + m_xLB_LineType->set_active(POS_LINETYPE_STEPPED); + if (getSteppedPropertiesDialog().run() == RET_OK) + { + if (m_pChangeListener) + m_pChangeListener->stateChanged(); + } + else + { + //restore old state: + m_xLB_LineType->set_active(iOldLineTypePos); + getSteppedPropertiesDialog().fillControls(aOldParameter); + } +} + +GeometryResourceGroup::GeometryResourceGroup(weld::Builder* pBuilder) + : m_aGeometryResources(pBuilder) +{ + m_aGeometryResources.connect_changed(LINK(this, GeometryResourceGroup, GeometryChangeHdl)); +} + +void GeometryResourceGroup::showControls(bool bShow) { m_aGeometryResources.set_visible(bShow); } + +void GeometryResourceGroup::fillControls(const ChartTypeParameter& rParameter) +{ + sal_uInt16 nGeometry3D = static_cast(rParameter.nGeometry3D); + m_aGeometryResources.select(nGeometry3D); + m_aGeometryResources.set_sensitive(rParameter.b3DLook); +} + +void GeometryResourceGroup::fillParameter(ChartTypeParameter& rParameter) +{ + rParameter.nGeometry3D = 1; + int nSelected = m_aGeometryResources.get_selected_index(); + if (nSelected != -1) + rParameter.nGeometry3D = nSelected; +} + +IMPL_LINK_NOARG(GeometryResourceGroup, GeometryChangeHdl, weld::TreeView&, void) +{ + if (m_pChangeListener) + m_pChangeListener->stateChanged(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ChartTypeDialogController.cxx b/chart2/source/controller/dialogs/ChartTypeDialogController.cxx new file mode 100644 index 000000000..9bcce8c89 --- /dev/null +++ b/chart2/source/controller/dialogs/ChartTypeDialogController.cxx @@ -0,0 +1,1253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeParameter::ChartTypeParameter() + : nSubTypeIndex( 1 ) + , bXAxisWithValues( false ) + , b3DLook( false ) + , bSymbols( true ) + , bLines( true ) + , eStackMode( GlobalStackMode_NONE ) + , eCurveStyle( CurveStyle_LINES ) + , nCurveResolution(20) + , nSplineOrder(3) + , nGeometry3D(DataPointGeometry3D::CUBOID) + , eThreeDLookScheme(ThreeDLookScheme::ThreeDLookScheme_Realistic) + , bSortByXValues(false) + , mbRoundedEdge(false) +{ +} + +ChartTypeParameter::ChartTypeParameter( sal_Int32 SubTypeIndex, bool HasXAxisWithValues + , bool Is3DLook, GlobalStackMode nStackMode + , bool HasSymbols, bool HasLines + , CurveStyle nCurveStyle ) + : nSubTypeIndex( SubTypeIndex ) + , bXAxisWithValues( HasXAxisWithValues ) + , b3DLook( Is3DLook ) + , bSymbols( HasSymbols ) + , bLines( HasLines ) + , eStackMode( nStackMode ) + , eCurveStyle( nCurveStyle ) + , nCurveResolution(20) + , nSplineOrder(3) + , nGeometry3D(DataPointGeometry3D::CUBOID) + , eThreeDLookScheme(ThreeDLookScheme::ThreeDLookScheme_Realistic) + , bSortByXValues(false) + , mbRoundedEdge(false) +{ +} + +bool ChartTypeParameter::mapsToSameService( const ChartTypeParameter& rParameter ) const +{ + return mapsToSimilarService( rParameter, 0 ); +} +bool ChartTypeParameter::mapsToSimilarService( const ChartTypeParameter& rParameter, sal_Int32 nTheHigherTheLess ) const +{ + sal_Int32 nMax=7; + if(nTheHigherTheLess>nMax) + return true; + if( bXAxisWithValues!=rParameter.bXAxisWithValues ) + return nTheHigherTheLess>nMax-1; + if( b3DLook!=rParameter.b3DLook ) + return nTheHigherTheLess>nMax-2; + if( eStackMode!=rParameter.eStackMode ) + return nTheHigherTheLess>nMax-3; + if( nSubTypeIndex!=rParameter.nSubTypeIndex ) + return nTheHigherTheLess>nMax-4; + if( bSymbols!=rParameter.bSymbols ) + return nTheHigherTheLess>nMax-5; + if( bLines!=rParameter.bLines ) + return nTheHigherTheLess>nMax-6; + return true; +} + +ChartTypeDialogController::ChartTypeDialogController() + : bSupportsXAxisWithValues(false) + , bSupports3D(true) +{ +} + +ChartTypeDialogController::~ChartTypeDialogController() +{ +} + +bool ChartTypeDialogController::isSubType( const OUString& rServiceName ) +{ + const tTemplateServiceChartTypeParameterMap& rTemplateMap = getTemplateMap(); + tTemplateServiceChartTypeParameterMap::const_iterator aIt( rTemplateMap.find( rServiceName )); + return aIt != rTemplateMap.end(); +} +ChartTypeParameter ChartTypeDialogController::getChartTypeParameterForService( + const OUString& rServiceName + , const uno::Reference< beans::XPropertySet >& xTemplateProps ) +{ + ChartTypeParameter aRet; + const tTemplateServiceChartTypeParameterMap& rTemplateMap = getTemplateMap(); + tTemplateServiceChartTypeParameterMap::const_iterator aIt( rTemplateMap.find( rServiceName )); + if( aIt != rTemplateMap.end()) + aRet = (*aIt).second; + if( xTemplateProps.is() ) + { + try + { + xTemplateProps->getPropertyValue( CHART_UNONAME_CURVE_STYLE ) >>= aRet.eCurveStyle; + xTemplateProps->getPropertyValue( CHART_UNONAME_CURVE_RESOLUTION ) >>= aRet.nCurveResolution; + xTemplateProps->getPropertyValue( CHART_UNONAME_SPLINE_ORDER ) >>= aRet.nSplineOrder; + } + catch( uno::Exception & ex ) + { + //not all templates need to support CurveStyle, CurveResolution or SplineOrder + ex.Context.is();//to have debug information without compilation warnings + } + + try + { + xTemplateProps->getPropertyValue( "Geometry3D" ) >>= aRet.nGeometry3D; + } + catch( uno::Exception& ex ) + { + //not all templates need to support Geometry3D + ex.Context.is();//to have debug information without compilation warnings + } + } + return aRet; +} +void ChartTypeDialogController::adjustSubTypeAndEnableControls( ChartTypeParameter& /*rParameter*/ ) +{ +} +void ChartTypeDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + case 3: + rParameter.eStackMode=GlobalStackMode_STACK_Y_PERCENT; + break; + case 4: + rParameter.eStackMode=GlobalStackMode_STACK_Z; + break; + default: + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} +void ChartTypeDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + bool bFoundSomeMatch=false; + + rParameter.bXAxisWithValues = bSupportsXAxisWithValues; + if( rParameter.b3DLook && !bSupports3D ) + rParameter.b3DLook = false; + if(!rParameter.b3DLook && rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + const tTemplateServiceChartTypeParameterMap& rMap = getTemplateMap(); + for( sal_Int32 nMatchPrecision=0; nMatchPrecision<7 && !bFoundSomeMatch; nMatchPrecision++ ) + { + for (auto const& elem : rMap) + { + if( rParameter.mapsToSimilarService( elem.second, nMatchPrecision ) ) + { + //remind some values + ThreeDLookScheme aScheme = rParameter.eThreeDLookScheme; + sal_Int32 nCurveResolution = rParameter.nCurveResolution; + sal_Int32 nSplineOrder = rParameter.nSplineOrder; + CurveStyle eCurveStyle = rParameter.eCurveStyle; + sal_Int32 nGeometry3D = rParameter.nGeometry3D; + bool bSortByXValues = rParameter.bSortByXValues; + bool bRoundedEdge = rParameter.mbRoundedEdge; + + rParameter = elem.second; + + //some values should not be changed with charttype + rParameter.eThreeDLookScheme = aScheme; + rParameter.nCurveResolution = nCurveResolution; + rParameter.nSplineOrder =nSplineOrder; + rParameter.eCurveStyle = eCurveStyle; + rParameter.nGeometry3D = nGeometry3D; + rParameter.bSortByXValues = bSortByXValues; + rParameter.mbRoundedEdge = bRoundedEdge; + + bFoundSomeMatch = true; + break; + } + } + } + if(!bFoundSomeMatch) + { + if(!rMap.empty()) + rParameter = (*rMap.begin()).second; + else + rParameter = ChartTypeParameter(); + } +} +OUString ChartTypeDialogController::getServiceNameForParameter( const ChartTypeParameter& rParameter ) const +{ + ChartTypeParameter aParameter(rParameter); + if( aParameter.bXAxisWithValues ) + aParameter.eStackMode = GlobalStackMode_NONE; + if(!aParameter.b3DLook && aParameter.eStackMode==GlobalStackMode_STACK_Z) + aParameter.eStackMode = GlobalStackMode_NONE; + const tTemplateServiceChartTypeParameterMap& rMap = getTemplateMap(); + for (auto const& elem : rMap) + { + if( aParameter.mapsToSameService(elem.second) ) + return elem.first; + } + + OSL_FAIL( "ChartType not implemented yet - use fallback to similar type" ); + for( sal_Int32 nMatchPrecision=1; nMatchPrecision<8; nMatchPrecision++ ) + { + for (auto const& elem : rMap) + { + if( aParameter.mapsToSimilarService(elem.second, nMatchPrecision) ) + return elem.first; + } + } + return OUString(); +} +rtl::Reference< ChartTypeTemplate > ChartTypeDialogController::getCurrentTemplate( + const ChartTypeParameter& rParameter + , const rtl::Reference< ChartTypeManager >& xTemplateManager ) const +{ + rtl::Reference< ChartTypeTemplate > xTemplate; + + OUString aServiceName( getServiceNameForParameter( rParameter ) ); + if(!aServiceName.isEmpty()) + { + xTemplate = xTemplateManager->createTemplate( aServiceName ); + if(xTemplate.is()) + { + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast(xTemplate.get()), uno::UNO_QUERY ); + if(xTemplateProps.is()) + { + try + { + xTemplateProps->setPropertyValue( CHART_UNONAME_CURVE_STYLE , uno::Any(rParameter.eCurveStyle) ); + xTemplateProps->setPropertyValue( CHART_UNONAME_CURVE_RESOLUTION , uno::Any(rParameter.nCurveResolution) ); + xTemplateProps->setPropertyValue( CHART_UNONAME_SPLINE_ORDER , uno::Any(rParameter.nSplineOrder) ); + } + catch( uno::Exception & ex ) + { + //not all templates need to support CurveStyle, CurveResolution or SplineOrder + ex.Context.is();//to have debug information without compilation warnings + } + try + { + xTemplateProps->setPropertyValue( "Geometry3D" , uno::Any(rParameter.nGeometry3D) ); + } + catch( uno::Exception & ex ) + { + //not all templates need to support Geometry3D + ex.Context.is();//to have debug information without compilation warnings + } + + try + { + setTemplateProperties( xTemplateProps ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + return xTemplate; +} + +void ChartTypeDialogController::commitToModel( const ChartTypeParameter& rParameter + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< ::chart::ChartTypeManager > xTemplateManager = xChartModel->getTypeManager(); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( getCurrentTemplate( rParameter, xTemplateManager ) ); + if(!xTemplate.is()) + return; + + // locked controllers + ControllerLockGuardUNO aCtrlLockGuard( xChartModel ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + DiagramHelper::tTemplateWithServiceName aTemplateWithService( + DiagramHelper::getTemplateForDiagram( xDiagram, xTemplateManager )); + if( aTemplateWithService.xChartTypeTemplate.is()) + aTemplateWithService.xChartTypeTemplate->resetStyles2( xDiagram ); + xTemplate->changeDiagram( xDiagram ); + if( AllSettings::GetMathLayoutRTL() ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + if( rParameter.b3DLook ) + ThreeDHelper::setScheme( xDiagram, rParameter.eThreeDLookScheme ); + + if (xDiagram.is()) + { + xDiagram->setPropertyValue(CHART_UNONAME_SORT_BY_XVALUES, uno::Any(rParameter.bSortByXValues)); + } +} +void ChartTypeDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); +} +bool ChartTypeDialogController::shouldShow_3DLookControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_StackingControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_SplineControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_GeometryControl() const +{ + return false; +} +bool ChartTypeDialogController::shouldShow_SortByXValuesResourceGroup() const +{ + return false; +} + +void ChartTypeDialogController::showExtraControls(weld::Builder* /*pBuilder*/) +{ +} +void ChartTypeDialogController::hideExtraControls() const +{ +} +void ChartTypeDialogController::fillExtraControls( const rtl::Reference<::chart::ChartModel>& /*xChartModel*/ + , const uno::Reference< beans::XPropertySet >& /*xTemplateProps*/ ) const +{ +} +void ChartTypeDialogController::setTemplateProperties( const uno::Reference< beans::XPropertySet >& /*xTemplateProps*/ ) const +{ +} + +ColumnOrBarChartDialogController_Base::ColumnOrBarChartDialogController_Base() +{ +} +ColumnOrBarChartDialogController_Base::~ColumnOrBarChartDialogController_Base() +{ +} +bool ColumnOrBarChartDialogController_Base::shouldShow_3DLookControl() const +{ + return true; +} +bool ColumnOrBarChartDialogController_Base::shouldShow_GeometryControl() const +{ + return true; +} +void ColumnOrBarChartDialogController_Base::adjustSubTypeAndEnableControls( ChartTypeParameter& rParameter ) +{ + if(rParameter.nSubTypeIndex>3 && !rParameter.b3DLook) + { + rParameter.nSubTypeIndex=1; + } +} +ColumnChartDialogController::ColumnChartDialogController() +{ +} +ColumnChartDialogController::~ColumnChartDialogController() +{ +} +OUString ColumnChartDialogController::getName() +{ + return SchResId(STR_TYPE_COLUMN); +} + +OUString ColumnChartDialogController::getImage() +{ + return BMP_TYPE_COLUMN; +} + +const tTemplateServiceChartTypeParameterMap& ColumnChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Column" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedColumn" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedColumn" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDColumnFlat" , ChartTypeParameter(1,false,true,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedThreeDColumnFlat" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedThreeDColumnFlat" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDColumnDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z)}}; + return s_aTemplateMap; +} +void ColumnChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + switch(rParameter.nGeometry3D) + { + case DataPointGeometry3D::CYLINDER: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_SAEULE_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_SAEULE_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_SAEULE_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_SAEULE_3D_4)); + break; + case DataPointGeometry3D::CONE: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_KEGEL_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_KEGEL_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_KEGEL_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_KEGEL_3D_4)); + break; + case DataPointGeometry3D::PYRAMID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_PYRAMID_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_PYRAMID_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_PYRAMID_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_PYRAMID_3D_4)); + break; + default: //DataPointGeometry3D::CUBOID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMNS_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMNS_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_COLUMNS_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_COLUMNS_3D)); + break; + } + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMNS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMNS_2D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_COLUMNS_2D_3)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DEEP ) ); +} + +BarChartDialogController::BarChartDialogController() +{ +} + +BarChartDialogController::~BarChartDialogController() +{ +} + +OUString BarChartDialogController::getName() +{ + return SchResId(STR_TYPE_BAR); +} + +OUString BarChartDialogController::getImage() +{ + return BMP_TYPE_BAR; +} + +const tTemplateServiceChartTypeParameterMap& BarChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Bar" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedBar" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedBar" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDBarFlat" , ChartTypeParameter(1,false,true,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.StackedThreeDBarFlat" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedThreeDBarFlat" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.ThreeDBarDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z)}}; + return s_aTemplateMap; +} +void BarChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + switch(rParameter.nGeometry3D) + { + case DataPointGeometry3D::CYLINDER: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_ROEHRE_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_ROEHRE_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_ROEHRE_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_ROEHRE_3D_4)); + break; + case DataPointGeometry3D::CONE: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_KEGELQ_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_KEGELQ_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_KEGELQ_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_KEGELQ_3D_4)); + break; + case DataPointGeometry3D::PYRAMID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_PYRAMIDQ_3D_4)); + break; + default: //DataPointGeometry3D::CUBOID: + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BARS_3D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_BARS_3D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_BARS_3D_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_BARS_3D)); + break; + } + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BARS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_BARS_2D_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_BARS_2D_3)); + } + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DEEP ) ); +} + +PieChartDialogController::PieChartDialogController() +{ +} + +PieChartDialogController::~PieChartDialogController() +{ +} + +OUString PieChartDialogController::getName() +{ + return SchResId(STR_TYPE_PIE); +} + +OUString PieChartDialogController::getImage() +{ + return BMP_TYPE_PIE; +} + +const tTemplateServiceChartTypeParameterMap& PieChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Pie" , ChartTypeParameter(1,false,false)}, + {"com.sun.star.chart2.template.PieAllExploded" , ChartTypeParameter(2,false,false)}, + {"com.sun.star.chart2.template.Donut" , ChartTypeParameter(3,false,false)}, + {"com.sun.star.chart2.template.DonutAllExploded" , ChartTypeParameter(4,false,false)}, + {"com.sun.star.chart2.template.ThreeDPie" , ChartTypeParameter(1,false,true)}, + {"com.sun.star.chart2.template.ThreeDPieAllExploded" , ChartTypeParameter(2,false,true)}, + {"com.sun.star.chart2.template.ThreeDDonut" , ChartTypeParameter(3,false,true)}, + {"com.sun.star.chart2.template.ThreeDDonutAllExploded" , ChartTypeParameter(4,false,true)}}; + return s_aTemplateMap; +} +void PieChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_CIRCLES_3D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_CIRCLES_3D_EXPLODED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_DONUT_3D)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_DONUT_3D_EXPLODED)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_CIRCLES_2D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_CIRCLES_2D_EXPLODED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_DONUT_2D)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_DONUT_2D_EXPLODED)); + } + rSubTypeList.SetItemText( 1, SchResId( STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_PIE_EXPLODED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_DONUT ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_DONUT_EXPLODED ) ); +} + +bool PieChartDialogController::shouldShow_3DLookControl() const +{ + return true; +} + +void PieChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; +} + +LineChartDialogController::LineChartDialogController() +{ +} + +LineChartDialogController::~LineChartDialogController() +{ +} + +OUString LineChartDialogController::getName() +{ + return SchResId(STR_TYPE_LINE); +} + +OUString LineChartDialogController::getImage() +{ + return BMP_TYPE_LINE; +} + +const tTemplateServiceChartTypeParameterMap& LineChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Symbol" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.StackedSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y,true,false)}, + {"com.sun.star.chart2.template.PercentStackedSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y_PERCENT,true,false)}, + {"com.sun.star.chart2.template.LineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.StackedLineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y,true,true)}, + {"com.sun.star.chart2.template.PercentStackedLineSymbol" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y_PERCENT,true,true)}, + {"com.sun.star.chart2.template.Line" , ChartTypeParameter(3,false,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.StackedLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + {"com.sun.star.chart2.template.StackedThreeDLine" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedThreeDLine" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + {"com.sun.star.chart2.template.ThreeDLineDeep" , ChartTypeParameter(4,false,true,GlobalStackMode_STACK_Z,false,true)}}; + return s_aTemplateMap; +} +void LineChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + switch( rParameter.eCurveStyle ) + { + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY_SMOOTH)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED_SMOOTH)); + } + break; + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY_STEPPED)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED_STEPPED)); + } + break; + default: // includes CurveStyle_LINES + //direct lines + if( rParameter.eStackMode == GlobalStackMode_NONE || rParameter.eStackMode == GlobalStackMode_STACK_Z ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XCATEGORY)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XCATEGORY)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XCATEGORY)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XCATEGORY)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_STACKED)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_STACKED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_STACKED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_STACKED)); + } + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_LINES_3D ) ); +} +bool LineChartDialogController::shouldShow_StackingControl() const +{ + return true; +} +bool LineChartDialogController::shouldShow_SplineControl() const +{ + return true; +} +void LineChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = true; + rParameter.b3DLook = true; + if( rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } + + if(!rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_STACK_Z ) + rParameter.eStackMode = GlobalStackMode_NONE; +} +void LineChartDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + if( rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + + ChartTypeDialogController::adjustParameterToMainType( rParameter ); +} + +XYChartDialogController::XYChartDialogController() +{ + bSupportsXAxisWithValues = true; +} + +XYChartDialogController::~XYChartDialogController() +{ +} + +OUString XYChartDialogController::getName() +{ + return SchResId(STR_TYPE_XY); +} + +OUString XYChartDialogController::getImage() +{ + return BMP_TYPE_XY; +} + +const tTemplateServiceChartTypeParameterMap& XYChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.ScatterSymbol" , ChartTypeParameter(1,true,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.ScatterLineSymbol" , ChartTypeParameter(2,true,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.ScatterLine" , ChartTypeParameter(3,true,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.ThreeDScatter" , ChartTypeParameter(4,true,true,GlobalStackMode_NONE,false,true)}}; + return s_aTemplateMap; +} + +void XYChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + switch (rParameter.eCurveStyle) + { + case CurveStyle_CUBIC_SPLINES: + case CurveStyle_B_SPLINES: + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES_SMOOTH)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES_SMOOTH)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES_SMOOTH)); + break; + } + case CurveStyle_STEP_START: + case CurveStyle_STEP_END: + case CurveStyle_STEP_CENTER_X: + case CurveStyle_STEP_CENTER_Y: + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES_STEPPED)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES_STEPPED)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES_STEPPED)); + break; + } + default: // includes CurveStyle_LINES + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_POINTS_XVALUES)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_LINE_P_XVALUES)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_LINE_O_XVALUES)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_LINE3D_XVALUES)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_LINES_3D ) ); +} +bool XYChartDialogController::shouldShow_SplineControl() const +{ + return true; +} +bool XYChartDialogController::shouldShow_SortByXValuesResourceGroup() const +{ + return true; +} +void XYChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.eStackMode=GlobalStackMode_NONE; + rParameter.b3DLook = false; + rParameter.bXAxisWithValues = true; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = true; + rParameter.b3DLook = true; + rParameter.eStackMode=GlobalStackMode_STACK_Z; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } +} + +AreaChartDialogController::AreaChartDialogController() +{ +} + +AreaChartDialogController::~AreaChartDialogController() +{ +} + +OUString AreaChartDialogController::getName() +{ + return SchResId(STR_TYPE_AREA); +} + +OUString AreaChartDialogController::getImage() +{ + return BMP_TYPE_AREA; +} + +bool AreaChartDialogController::shouldShow_3DLookControl() const +{ + return true; +} + +const tTemplateServiceChartTypeParameterMap& AreaChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Area" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE)}, + {"com.sun.star.chart2.template.ThreeDArea" , ChartTypeParameter(1,false,true,GlobalStackMode_STACK_Z)}, + {"com.sun.star.chart2.template.StackedArea" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.StackedThreeDArea" , ChartTypeParameter(2,false,true,GlobalStackMode_STACK_Y)}, + {"com.sun.star.chart2.template.PercentStackedArea" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT)}, + {"com.sun.star.chart2.template.PercentStackedThreeDArea" , ChartTypeParameter(3,false,true,GlobalStackMode_STACK_Y_PERCENT)}}; + return s_aTemplateMap; +} + +void AreaChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.b3DLook ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_AREAS_3D)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_AREAS_3D_1)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_AREAS_3D_2)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_AREAS_2D_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_AREAS_2D)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_AREAS_2D_3)); + } + + rSubTypeList.SetItemText( 1, SchResId( rParameter.b3DLook ? STR_DEEP : STR_NORMAL ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_STACKED ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_PERCENT ) ); +} +void AreaChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.eCurveStyle = CurveStyle_LINES; + + if( rParameter.nSubTypeIndex>3 ) + rParameter.nSubTypeIndex = 1; + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + case 3: + rParameter.eStackMode=GlobalStackMode_STACK_Y_PERCENT; + break; + default: + if( rParameter.b3DLook ) + rParameter.eStackMode=GlobalStackMode_STACK_Z; + else + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} +void AreaChartDialogController::adjustParameterToMainType( ChartTypeParameter& rParameter ) +{ + if( rParameter.b3DLook && rParameter.eStackMode == GlobalStackMode_NONE ) + rParameter.eStackMode = GlobalStackMode_STACK_Z; + + ChartTypeDialogController::adjustParameterToMainType( rParameter ); +} + +NetChartDialogController::NetChartDialogController() +{ + bSupports3D = false; +} + +NetChartDialogController::~NetChartDialogController() +{ +} + +OUString NetChartDialogController::getName() +{ + return SchResId(STR_TYPE_NET); +} + +OUString NetChartDialogController::getImage() +{ + return BMP_TYPE_NET; +} + +bool NetChartDialogController::shouldShow_StackingControl() const +{ + return true; +} + +const tTemplateServiceChartTypeParameterMap& NetChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + //@todo need templates with symbols only + {"com.sun.star.chart2.template.NetSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_NONE,true,false)}, + {"com.sun.star.chart2.template.StackedNetSymbol" , ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y,true,false)}, + {"com.sun.star.chart2.template.PercentStackedNetSymbol" ,ChartTypeParameter(1,false,false,GlobalStackMode_STACK_Y_PERCENT,true,false)}, + + {"com.sun.star.chart2.template.Net" , ChartTypeParameter(2,false,false,GlobalStackMode_NONE,true,true)}, + {"com.sun.star.chart2.template.StackedNet" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y,true,true)}, + {"com.sun.star.chart2.template.PercentStackedNet" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y_PERCENT,true,true)}, + + {"com.sun.star.chart2.template.NetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_NONE,false,true)}, + {"com.sun.star.chart2.template.StackedNetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y,false,true)}, + {"com.sun.star.chart2.template.PercentStackedNetLine" , ChartTypeParameter(3,false,false,GlobalStackMode_STACK_Y_PERCENT,false,true)}, + + {"com.sun.star.chart2.template.FilledNet" , ChartTypeParameter(4,false,false,GlobalStackMode_NONE,false,false)}, + {"com.sun.star.chart2.template.StackedFilledNet" , ChartTypeParameter(4,false,false,GlobalStackMode_STACK_Y,false,false)}, + {"com.sun.star.chart2.template.PercentStackedFilledNet" ,ChartTypeParameter(4,false,false,GlobalStackMode_STACK_Y_PERCENT,false,false)}}; + return s_aTemplateMap; +} +void NetChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& rParameter ) +{ + rSubTypeList.Clear(); + + if( rParameter.eStackMode == GlobalStackMode_NONE ) + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_NET_SYMB)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_NET_LINESYMB)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_NET)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_NET_FILL)); + } + else + { + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_NET_SYMB_STACK)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_NET_LINESYMB_STACK)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_NET_STACK)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_NET_FILL_STACK)); + } + + rSubTypeList.SetItemText( 1, SchResId( STR_POINTS_ONLY ) ); + rSubTypeList.SetItemText( 2, SchResId( STR_POINTS_AND_LINES ) ); + rSubTypeList.SetItemText( 3, SchResId( STR_LINES_ONLY ) ); + rSubTypeList.SetItemText( 4, SchResId( STR_FILLED ) ); +} +void NetChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.bSymbols = true; + rParameter.bLines = true; + break; + case 3: + rParameter.bSymbols = false; + rParameter.bLines = true; + break; + case 4: + rParameter.bSymbols = false; + rParameter.bLines = false; + break; + default: + rParameter.bSymbols = true; + rParameter.bLines = false; + break; + } +} +StockChartDialogController::StockChartDialogController() +{ + bSupports3D = false; +} + +StockChartDialogController::~StockChartDialogController() +{ +} + +OUString StockChartDialogController::getName() +{ + return SchResId(STR_TYPE_STOCK); +} + +OUString StockChartDialogController::getImage() +{ + return BMP_TYPE_STOCK; +} + +const tTemplateServiceChartTypeParameterMap& StockChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.StockLowHighClose" , ChartTypeParameter(1)}, + {"com.sun.star.chart2.template.StockOpenLowHighClose" , ChartTypeParameter(2)}, + {"com.sun.star.chart2.template.StockVolumeLowHighClose" , ChartTypeParameter(3)}, + {"com.sun.star.chart2.template.StockVolumeOpenLowHighClose" ,ChartTypeParameter(4)}}; + return s_aTemplateMap; +} + +void StockChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_STOCK_1)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_STOCK_2)); + rSubTypeList.InsertItem(3, Image(StockImage::Yes, BMP_STOCK_3)); + rSubTypeList.InsertItem(4, Image(StockImage::Yes, BMP_STOCK_4)); + + rSubTypeList.SetItemText( 1, SchResId(STR_STOCK_1) ); + rSubTypeList.SetItemText( 2, SchResId(STR_STOCK_2) ); + rSubTypeList.SetItemText( 3, SchResId(STR_STOCK_3) ); + rSubTypeList.SetItemText( 4, SchResId(STR_STOCK_4) ); +} + +void StockChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + rParameter.eStackMode = GlobalStackMode_NONE; +} + +CombiColumnLineChartDialogController::CombiColumnLineChartDialogController() +{ + bSupports3D = false; +} + +OUString CombiColumnLineChartDialogController::getName() +{ + return SchResId(STR_TYPE_COMBI_COLUMN_LINE); +} + +OUString CombiColumnLineChartDialogController::getImage() +{ + return BMP_TYPE_COLUMN_LINE; +} + +const tTemplateServiceChartTypeParameterMap& CombiColumnLineChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.ColumnWithLine" , ChartTypeParameter(1)}, + {"com.sun.star.chart2.template.StackedColumnWithLine" , ChartTypeParameter(2,false,false,GlobalStackMode_STACK_Y)}}; + return s_aTemplateMap; +} + +void CombiColumnLineChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_COLUMN_LINE)); + rSubTypeList.InsertItem(2, Image(StockImage::Yes, BMP_COLUMN_LINE_STACKED)); + + rSubTypeList.SetItemText(1, SchResId(STR_LINE_COLUMN)); + rSubTypeList.SetItemText(2, SchResId(STR_LINE_STACKEDCOLUMN)); +} + +void CombiColumnLineChartDialogController::showExtraControls(weld::Builder* pBuilder) +{ + if (!m_xFT_NumberOfLines) + { + m_xFT_NumberOfLines = pBuilder->weld_label("nolinesft"); + } + if (!m_xMF_NumberOfLines) + { + m_xMF_NumberOfLines = pBuilder->weld_spin_button("nolines"); + + m_xMF_NumberOfLines->set_increments(1, 10); + m_xMF_NumberOfLines->set_range(1, 100); + + m_xMF_NumberOfLines->connect_value_changed( LINK( this, CombiColumnLineChartDialogController, ChangeLineCountHdl ) ); + } + + m_xFT_NumberOfLines->show(); + m_xMF_NumberOfLines->show(); +} + +void CombiColumnLineChartDialogController::hideExtraControls() const +{ + if (m_xFT_NumberOfLines) + m_xFT_NumberOfLines->hide(); + if (m_xMF_NumberOfLines) + m_xMF_NumberOfLines->hide(); +} + +void CombiColumnLineChartDialogController::fillExtraControls( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< beans::XPropertySet >& xTemplateProps ) const +{ + if (!m_xMF_NumberOfLines) + return; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + if(!xDiagram.is()) + return; + + sal_Int32 nNumLines = 0; + + if(xTemplateProps.is()) + { + try + { + xTemplateProps->getPropertyValue( "NumberOfLines" ) >>= nNumLines; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + if( nNumLines < 0 ) + nNumLines = 0; + m_xMF_NumberOfLines->set_value(nNumLines); + + sal_Int32 nMaxLines = ChartModelHelper::getDataSeries( xChartModel ).size() - 1; + if( nMaxLines < 0 ) + nMaxLines = 0; + m_xMF_NumberOfLines->set_max(nMaxLines); +} +void CombiColumnLineChartDialogController::setTemplateProperties( const uno::Reference< beans::XPropertySet >& xTemplateProps ) const +{ + if( xTemplateProps.is() ) + { + sal_Int32 nNumLines = m_xMF_NumberOfLines->get_value(); + xTemplateProps->setPropertyValue( "NumberOfLines" , uno::Any(nNumLines) ); + } +} + +IMPL_LINK_NOARG(CombiColumnLineChartDialogController, ChangeLineCountHdl, weld::SpinButton&, void) +{ + if( m_pChangeListener ) + m_pChangeListener->stateChanged(); +} +void CombiColumnLineChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + if(rParameter.eStackMode==GlobalStackMode_STACK_Z) + rParameter.eStackMode = GlobalStackMode_NONE; + + switch( rParameter.nSubTypeIndex ) + { + case 2: + rParameter.eStackMode=GlobalStackMode_STACK_Y; + break; + default: + rParameter.eStackMode=GlobalStackMode_NONE; + break; + } +} + +BubbleChartDialogController::BubbleChartDialogController() +{ +} + +BubbleChartDialogController::~BubbleChartDialogController() +{ +} + +OUString BubbleChartDialogController::getName() +{ + return SchResId(STR_TYPE_BUBBLE); +} + +OUString BubbleChartDialogController::getImage() +{ + return BMP_TYPE_BUBBLE; +} + +const tTemplateServiceChartTypeParameterMap& BubbleChartDialogController::getTemplateMap() const +{ + static tTemplateServiceChartTypeParameterMap s_aTemplateMap{ + {"com.sun.star.chart2.template.Bubble" , ChartTypeParameter(1,true)}}; + return s_aTemplateMap; +} +void BubbleChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ ) +{ + rSubTypeList.Clear(); + rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_BUBBLE_1)); + + rSubTypeList.SetItemText( 1, SchResId(STR_BUBBLE_1) ); +} +void BubbleChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter ) +{ + rParameter.b3DLook = false; + rParameter.eStackMode = GlobalStackMode_NONE; +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowser.cxx b/chart2/source/controller/dialogs/DataBrowser.cxx new file mode 100644 index 000000000..eb15e8f3d --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowser.cxx @@ -0,0 +1,1383 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "DataBrowser.hxx" +#include "DataBrowserModel.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +using namespace ::svt; + +namespace +{ +/* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only + entire rows + BrowserMode::(H|V)LINES : show horizontal or vertical grid-lines + BrowserMode::AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when + cursor is moved beyond the edge of the dialog + BrowserMode::HIDESELECT : Do not mark the current row with selection color + (usually blue) + ! BrowserMode::HIDECURSOR would prevent flickering in edit fields, but navigating + with shift up/down, and entering non-editable cells would be problematic, + e.g. the first cell, or when being in read-only mode +*/ +const BrowserMode BrowserStdFlags = BrowserMode::COLUMNSELECTION | + BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL | + BrowserMode::HIDESELECT; + +sal_Int32 lcl_getColumnInData( sal_uInt16 nCol ) +{ + return static_cast< sal_Int32 >( nCol ) - 1; +} + +} // anonymous namespace + +namespace chart +{ + +namespace impl +{ + +class SeriesHeaderEdit +{ +public: + explicit SeriesHeaderEdit(std::unique_ptr xControl); + + void setStartColumn( sal_Int32 nStartColumn ); + sal_Int32 getStartColumn() const { return m_nStartColumn;} + void SetShowWarningBox( bool bShowWarning ); + + OUString GetText() const { return m_xControl->get_text(); } + void SetText(const OUString& rText) { m_xControl->set_text(rText); } + + bool HasFocus() const { return m_xControl->has_focus(); } + + void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); } + void set_margin_start(int nLeft) { m_xControl->set_margin_start(nLeft); } + + void SetModifyHdl(const Link& rLink) { m_aModifyHdl = rLink; } + void SetGetFocusHdl(const Link& rLink) { m_aFocusInHdl = rLink; } + +private: + DECL_LINK(NameEdited, weld::Entry&, void); + DECL_LINK(NameFocusIn, weld::Widget&, void); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + + std::unique_ptr m_xControl; + Link m_aModifyHdl; + Link m_aFocusInHdl; + sal_Int32 m_nStartColumn; + bool m_bShowWarningBox; +}; + +SeriesHeaderEdit::SeriesHeaderEdit(std::unique_ptr xControl) + : m_xControl(std::move(xControl)) + , m_nStartColumn(0) + , m_bShowWarningBox(false) +{ + m_xControl->set_help_id(HID_SCH_DATA_SERIES_LABEL); + m_xControl->connect_changed(LINK(this, SeriesHeaderEdit, NameEdited)); + m_xControl->connect_focus_in(LINK(this, SeriesHeaderEdit, NameFocusIn)); + m_xControl->connect_mouse_press(LINK(this, SeriesHeaderEdit, MousePressHdl)); +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, NameEdited, weld::Entry&, void) +{ + m_aModifyHdl.Call(*this); +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, NameFocusIn, weld::Widget&, void) +{ + m_aFocusInHdl.Call(*this); +} + +void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn ) +{ + m_nStartColumn = nStartColumn; +} + +void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning ) +{ + m_bShowWarningBox = bShowWarning; +} + +IMPL_LINK_NOARG(SeriesHeaderEdit, MousePressHdl, const MouseEvent&, bool) +{ + if (m_bShowWarningBox) + { + std::unique_ptr xWarn(Application::CreateMessageDialog(m_xControl.get(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(STR_INVALID_NUMBER))); + xWarn->run(); + } + + return false; +} + +class SeriesHeader +{ +public: + explicit SeriesHeader(weld::Container* pParent, weld::Container* pColorParent); + ~SeriesHeader(); + + void SetColor( const Color & rCol ); + void SetPos(); + void SetWidth( sal_Int32 nWidth ); + void SetChartType( const rtl::Reference< ::chart::ChartType > & xChartType, + bool bSwapXAndYAxis ); + void SetSeriesName( const OUString & rName ); + void SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol ); + + void SetPixelWidth( sal_Int32 nWidth ); + + sal_Int32 GetStartColumn() const { return m_nStartCol;} + sal_Int32 GetEndColumn() const { return m_nEndCol;} + + static const sal_Int32 nSymbolHeight = 10; + static const sal_Int32 nSymbolDistance = 2; + + static sal_Int32 GetRelativeAppFontXPosForNameField() { return nSymbolHeight + nSymbolDistance; } + + void Show(); + void Hide(); + + /** call this before destroying the class. This notifies the listeners to + changes of the edit field for the series name. + */ + void applyChanges(); + + void SetGetFocusHdl(const Link& rLink); + + void SetEditChangedHdl( const Link & rLink ); + + bool HasFocus() const; + +private: + Timer m_aUpdateDataTimer; + + std::unique_ptr m_xBuilder1; + std::unique_ptr m_xBuilder2; + + weld::Container* m_pParent; + weld::Container* m_pColorParent; + + std::unique_ptr m_xContainer1; + std::unique_ptr m_xContainer2; + std::unique_ptr m_spSymbol; + std::unique_ptr m_spSeriesName; + std::unique_ptr m_spColorBar; + VclPtr< OutputDevice> m_xDevice; + Link m_aChangeLink; + Color m_aColor; + + void notifyChanges(); + DECL_LINK( ImplUpdateDataHdl, Timer*, void ); + DECL_LINK( SeriesNameEdited, SeriesHeaderEdit&, void ); + + static OUString GetChartTypeImage( + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bSwapXAndYAxis + ); + + sal_Int32 m_nStartCol, m_nEndCol; + sal_Int32 m_nWidth; + bool m_bSeriesNameChangePending; +}; + +SeriesHeader::SeriesHeader(weld::Container* pParent, weld::Container* pColorParent) + : m_aUpdateDataTimer( "SeriesHeader UpdateDataTimer" ) + , m_xBuilder1(Application::CreateBuilder(pParent, "modules/schart/ui/columnfragment.ui")) + , m_xBuilder2(Application::CreateBuilder(pColorParent, "modules/schart/ui/imagefragment.ui")) + , m_pParent(pParent) + , m_pColorParent(pColorParent) + , m_xContainer1(m_xBuilder1->weld_container("container")) + , m_xContainer2(m_xBuilder2->weld_container("container")) + , m_spSymbol(m_xBuilder1->weld_image("image")) + , m_spSeriesName(new SeriesHeaderEdit(m_xBuilder1->weld_entry("entry"))) + , m_spColorBar(m_xBuilder2->weld_image("image")) + , m_xDevice(Application::GetDefaultDevice()) + , m_nStartCol( 0 ) + , m_nEndCol( 0 ) + , m_nWidth( 42 ) + , m_bSeriesNameChangePending( false ) +{ + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SeriesHeader, ImplUpdateDataHdl)); + m_aUpdateDataTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT); + + m_spSeriesName->SetModifyHdl(LINK(this, SeriesHeader, SeriesNameEdited)); + Show(); +} + +SeriesHeader::~SeriesHeader() +{ + m_aUpdateDataTimer.Stop(); + m_pParent->move(m_xContainer1.get(), nullptr); + m_pColorParent->move(m_xContainer2.get(), nullptr); +} + +void SeriesHeader::notifyChanges() +{ + m_aChangeLink.Call(*m_spSeriesName); + m_bSeriesNameChangePending = false; +} + +void SeriesHeader::applyChanges() +{ + if( m_bSeriesNameChangePending ) + { + notifyChanges(); + } +} + +void SeriesHeader::SetColor( const Color & rCol ) +{ + m_aColor = rCol; +} + +void SeriesHeader::SetPos() +{ + // chart type symbol + Size aSize( nSymbolHeight, nSymbolHeight ); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + m_spSymbol->set_size_request(aSize.Width(), aSize.Height()); + + // series name edit field + m_spSeriesName->set_margin_start(2); + + aSize.setWidth(nSymbolHeight); + aSize.setHeight(12); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + aSize.setWidth(m_nWidth - aSize.Width() - 2); + m_spSeriesName->set_size_request(aSize.Width(), aSize.Height()); + + // color bar + aSize.setHeight(3); + aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + aSize.setWidth(m_nWidth); + m_spColorBar->set_size_request(aSize.Width(), aSize.Height()); + + ScopedVclPtr xVirDev(m_spColorBar->create_virtual_device()); + xVirDev->SetOutputSizePixel(aSize); + xVirDev->SetFillColor(m_aColor); + xVirDev->SetLineColor(m_aColor); + xVirDev->DrawRect(tools::Rectangle(Point(0, 0), aSize)); + m_spColorBar->set_image(xVirDev.get()); +} + +void SeriesHeader::SetWidth( sal_Int32 nWidth ) +{ + m_nWidth = nWidth; + SetPos(); +} + +void SeriesHeader::SetPixelWidth( sal_Int32 nWidth ) +{ + SetWidth(nWidth); +} + +void SeriesHeader::SetChartType( + const rtl::Reference< ChartType > & xChartType, + bool bSwapXAndYAxis +) +{ + m_spSymbol->set_from_icon_name( GetChartTypeImage( xChartType, bSwapXAndYAxis ) ); +} + +void SeriesHeader::SetSeriesName( const OUString & rName ) +{ + m_spSeriesName->SetText(rName); +} + +void SeriesHeader::SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol ) +{ + m_nStartCol = nStartCol; + m_nEndCol = std::max(nEndCol, nStartCol); + m_spSeriesName->setStartColumn( nStartCol ); +} + +void SeriesHeader::Show() +{ + m_xContainer1->show(); + m_xContainer2->show(); +} + +void SeriesHeader::Hide() +{ + m_xContainer1->hide(); + m_xContainer2->hide(); +} + +void SeriesHeader::SetEditChangedHdl( const Link & rLink ) +{ + m_aChangeLink = rLink; +} + +IMPL_LINK_NOARG(SeriesHeader, ImplUpdateDataHdl, Timer*, void) +{ + notifyChanges(); +} + +IMPL_LINK_NOARG(SeriesHeader, SeriesNameEdited, SeriesHeaderEdit&, void) +{ + m_bSeriesNameChangePending = true; + m_aUpdateDataTimer.Start(); +} + +void SeriesHeader::SetGetFocusHdl( const Link& rLink ) +{ + m_spSeriesName->SetGetFocusHdl( rLink ); +} + +bool SeriesHeader::HasFocus() const +{ + return m_spSeriesName->HasFocus(); +} + +OUString SeriesHeader::GetChartTypeImage( + const rtl::Reference< ChartType > & xChartType, + bool bSwapXAndYAxis +) +{ + OUString aResult; + if( !xChartType.is()) + return aResult; + OUString aChartTypeName( xChartType->getChartType()); + + if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_AREA ) + { + aResult = BMP_TYPE_AREA; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) + { + if( bSwapXAndYAxis ) + aResult = BMP_TYPE_BAR; + else + aResult = BMP_TYPE_COLUMN; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_LINE ) + { + aResult = BMP_TYPE_LINE; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ) + { + aResult = BMP_TYPE_XY; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + { + aResult = BMP_TYPE_PIE; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_NET + || aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET ) + { + aResult = BMP_TYPE_NET; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + // @todo: correct image for candle-stick type + aResult = BMP_TYPE_STOCK; + } + else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE ) + { + aResult = BMP_TYPE_BUBBLE; + } + + return aResult; +} + +} // namespace impl + +namespace +{ + +/** returns false, if no header as the focus. + + If a header has the focus, true is returned and the index of the header + with focus is set at pIndex if pOutIndex is not 0. +*/ +bool lcl_SeriesHeaderHasFocus( + const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader, + sal_Int32 * pOutIndex = nullptr ) +{ + sal_Int32 nIndex = 0; + for (auto const& elem : rSeriesHeader) + { + if(elem->HasFocus()) + { + if( pOutIndex ) + *pOutIndex = nIndex; + return true; + } + ++nIndex; + } + return false; +} + +sal_Int32 lcl_getColumnInDataOrHeader( + sal_uInt16 nCol, const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader ) +{ + sal_Int32 nColIdx = 0; + bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader, &nColIdx )); + + if( bHeaderHasFocus ) + nColIdx = lcl_getColumnInData( static_cast< sal_uInt16 >( rSeriesHeader[nColIdx]->GetStartColumn())); + else + nColIdx = lcl_getColumnInData( nCol ); + + return nColIdx; +} + +} // anonymous namespace + +DataBrowser::DataBrowser(const css::uno::Reference &rParent, + weld::Container* pColumns, weld::Container* pColors) : + ::svt::EditBrowseBox(VCLUnoHelper::GetWindow(rParent), + EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::HANDLE_COLUMN_TEXT, + WB_BORDER | WB_TABSTOP, BrowserStdFlags ), + m_nSeekRow( 0 ), + m_bIsReadOnly( false ), + m_bDataValid( true ), + m_aNumberEditField(VclPtr::Create(&EditBrowseBox::GetDataWindow(), false)), + m_aTextEditField(VclPtr::Create(&EditBrowseBox::GetDataWindow())), + m_pColumnsWin(pColumns), + m_pColorsWin(pColors), + m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField.get() )), + m_rTextEditController( new ::svt::EditCellController( m_aTextEditField.get() )) +{ + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.SetDefaultValue( std::numeric_limits::quiet_NaN() ); + rFormatter.TreatAsNumber( true ); + RenewTable(); +} + +DataBrowser::~DataBrowser() +{ + disposeOnce(); +} + +void DataBrowser::dispose() +{ + m_aSeriesHeaders.clear(); + m_aNumberEditField.disposeAndClear(); + m_aTextEditField.disposeAndClear(); + ::svt::EditBrowseBox::dispose(); +} + +bool DataBrowser::MayInsertRow() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )); +} + +bool DataBrowser::MayInsertColumn() const +{ + return ! IsReadOnly(); +} + +bool DataBrowser::MayDeleteRow() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() >= 0 ) + && ( GetRowCount() > 1 ); +} + +bool DataBrowser::MayDeleteColumn() const +{ + // if a series header has the focus + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + return true; + + return ! IsReadOnly() + && ( GetCurColumnId() > 1 ) + && ( ColCount() > 2 ); +} + +bool DataBrowser::MayMoveUpRows() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() > 0 ) + && ( GetCurRow() <= GetRowCount() - 1 ); +} + +bool DataBrowser::MayMoveDownRows() const +{ + return ! IsReadOnly() + && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders )) + && ( GetCurRow() >= 0 ) + && ( GetCurRow() < GetRowCount() - 1 ); +} + +bool DataBrowser::MayMoveLeftColumns() const +{ + // if a series header (except the last one) has the focus + { + sal_Int32 nColIndex(0); + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex )) + return (o3tl::make_unsigned( nColIndex ) <= (m_aSeriesHeaders.size() - 1)) && (static_cast< sal_uInt32 >( nColIndex ) != 0); + } + + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + return ! IsReadOnly() + && ( nColIdx > 1 ) + && ( nColIdx <= ColCount() - 2 ) + && m_apDataBrowserModel + && !m_apDataBrowserModel->isCategoriesColumn( nColIdx ); +} + +bool DataBrowser::MayMoveRightColumns() const +{ + // if a series header (except the last one) has the focus + { + sal_Int32 nColIndex(0); + if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex )) + return (o3tl::make_unsigned( nColIndex ) < (m_aSeriesHeaders.size() - 1)); + } + + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + return ! IsReadOnly() + && ( nColIdx > 0 ) + && ( nColIdx < ColCount()-2 ) + && m_apDataBrowserModel + && !m_apDataBrowserModel->isCategoriesColumn( nColIdx ); +} + +void DataBrowser::clearHeaders() +{ + for( const auto& spHeader : m_aSeriesHeaders ) + spHeader->applyChanges(); + m_aSeriesHeaders.clear(); +} + +void DataBrowser::RenewTable() +{ + if (!m_apDataBrowserModel) + return; + + sal_Int32 nOldRow = GetCurRow(); + sal_uInt16 nOldColId = GetCurColumnId(); + + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + if( IsModified() ) + SaveModified(); + + DeactivateCell(); + + RemoveColumns(); + RowRemoved( 1, GetRowCount() ); + + // for row numbers + InsertHandleColumn( static_cast< sal_uInt16 >( + GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() )); + + OUString aDefaultSeriesName(SchResId(STR_COLUMN_LABEL)); + replaceParamterInString( aDefaultSeriesName, "%COLUMNNUMBER", OUString::number( 24 ) ); + sal_Int32 nColumnWidth = GetDataWindow().GetTextWidth( aDefaultSeriesName ) + + GetDataWindow().LogicToPixel(Point(8 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0), MapMode(MapUnit::MapAppFont)).X(); + sal_Int32 nColumnCount = m_apDataBrowserModel->getColumnCount(); + // nRowCount is a member of a base class + sal_Int32 nRowCountLocal = m_apDataBrowserModel->getMaxRowCount(); + for( sal_Int32 nColIdx=1; nColIdx<=nColumnCount; ++nColIdx ) + { + InsertDataColumn( static_cast< sal_uInt16 >( nColIdx ), GetColString( nColIdx ), nColumnWidth ); + } + + RowInserted( 1, nRowCountLocal ); + GoToRow( std::min( nOldRow, GetRowCount() - 1 )); + GoToColumnId( std::min( nOldColId, static_cast< sal_uInt16 >( ColCount() - 1 ))); + + // fill series headers + clearHeaders(); + const DataBrowserModel::tDataHeaderVector& aHeaders( m_apDataBrowserModel->getDataHeaders()); + Link aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus )); + Link aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged )); + + for (auto const& elemHeader : aHeaders) + { + auto spHeader = std::make_shared( m_pColumnsWin, m_pColorsWin ); + Color nColor; + // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc. + if( elemHeader.m_xDataSeries.is() && + ( elemHeader.m_xDataSeries->getPropertyValue( "Color" ) >>= nColor )) + spHeader->SetColor( nColor ); + spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis ); + spHeader->SetSeriesName( + DataSeriesHelper::getDataSeriesLabel( + elemHeader.m_xDataSeries, + (elemHeader.m_xChartType.is() ? + elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() : + OUString("values-y")))); + // index is 1-based, as 0 is for the column that contains the row-numbers + spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 ); + spHeader->SetGetFocusHdl( aFocusLink ); + spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink ); + m_aSeriesHeaders.push_back( spHeader ); + } + + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); + ActivateCell(); + Invalidate(); +} + +OUString DataBrowser::GetColString( sal_Int32 nColumnId ) const +{ + OSL_ASSERT(m_apDataBrowserModel); + if( nColumnId > 0 ) + return m_apDataBrowserModel->getRoleOfColumn( nColumnId - 1 ); + return OUString(); +} + +OUString DataBrowser::GetCellText( sal_Int32 nRow, sal_uInt16 nColumnId ) const +{ + OUString aResult; + + if( nColumnId == 0 ) + { + aResult = OUString::number(nRow + 1); + } + else if( nRow >= 0 && m_apDataBrowserModel) + { + sal_Int32 nColIndex = static_cast< sal_Int32 >( nColumnId ) - 1; + + if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::NUMBER ) + { + double fData( m_apDataBrowserModel->getCellNumber( nColIndex, nRow )); + + if( ! std::isnan( fData ) && + m_spNumberFormatterWrapper ) + { + bool bColorChanged = false; + Color nLabelColor; + aResult = m_spNumberFormatterWrapper->getFormattedString( + GetNumberFormatKey( nColumnId ), + fData, nLabelColor, bColorChanged ); + } + } + else if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXTORDATE ) + { + uno::Any aAny = m_apDataBrowserModel->getCellAny( nColIndex, nRow ); + OUString aText; + double fDouble=0.0; + if( aAny>>=aText ) + aResult = aText; + else if( aAny>>=fDouble ) + { + if( ! std::isnan( fDouble ) && m_spNumberFormatterWrapper ) + { + // If a numberformat was available here we could directly + // obtain the corresponding edit format in + // getDateTimeInputNumberFormat() instead of doing the + // guess work. + sal_Int32 nNumberFormat = DiagramHelper::getDateTimeInputNumberFormat( + m_xChartDoc, fDouble ); + Color nLabelColor; + bool bColorChanged = false; + aResult = m_spNumberFormatterWrapper->getFormattedString( + nNumberFormat, fDouble, nLabelColor, bColorChanged ); + } + } + } + else + { + OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXT ); + aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow ); + } + } + + return aResult; +} + +double DataBrowser::GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const +{ + if(( nColumnId >= 1 ) && ( nRow >= 0 ) && m_apDataBrowserModel) + { + return m_apDataBrowserModel->getCellNumber( + static_cast< sal_Int32 >( nColumnId ) - 1, nRow ); + } + + return std::numeric_limits::quiet_NaN(); +} + +void DataBrowser::Resize() +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + ::svt::EditBrowseBox::Resize(); + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::SetReadOnly( bool bNewState ) +{ + if( m_bIsReadOnly != bNewState ) + { + m_bIsReadOnly = bNewState; + Invalidate(); + DeactivateCell(); + } +} + +void DataBrowser::CursorMoved() +{ + EditBrowseBox::CursorMoved(); + + if( GetUpdateMode() ) + m_aCursorMovedHdlLink.Call( this ); +} + +void DataBrowser::MouseButtonDown( const BrowserMouseEvent& rEvt ) +{ + if( !m_bDataValid ) + ShowWarningBox(); + else + EditBrowseBox::MouseButtonDown( rEvt ); +} + +void DataBrowser::ShowWarningBox() +{ + std::unique_ptr xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(STR_INVALID_NUMBER))); + xWarn->run(); +} + +bool DataBrowser::ShowQueryBox() +{ + std::unique_ptr xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SchResId(STR_DATA_EDITOR_INCORRECT_INPUT))); + return xQueryBox->run() == RET_YES; +} + +bool DataBrowser::IsDataValid() const +{ + bool bValid = true; + const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId()); + + if( m_apDataBrowserModel->getCellType( nCol ) == DataBrowserModel::NUMBER ) + { + sal_uInt32 nDummy = 0; + double fDummy = 0.0; + OUString aText(m_aNumberEditField->get_widget().get_text()); + + if( !aText.isEmpty() && + m_spNumberFormatterWrapper && + m_spNumberFormatterWrapper->getSvNumberFormatter() && + ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat( + aText, nDummy, fDummy )) + { + bValid = false; + } + } + + return bValid; +} + +void DataBrowser::CellModified() +{ + m_bDataValid = IsDataValid(); + m_aCursorMovedHdlLink.Call( this ); +} + +void DataBrowser::SetDataFromModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) +{ + m_xChartDoc = xChartDoc; + + m_apDataBrowserModel.reset( new DataBrowserModel( m_xChartDoc )); + m_spNumberFormatterWrapper = + std::make_shared(m_xChartDoc); + + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() ); + + RenewTable(); + + const sal_Int32 nColCnt = m_apDataBrowserModel->getColumnCount(); + const sal_Int32 nRowCnt = m_apDataBrowserModel->getMaxRowCount(); + if( nRowCnt && nColCnt ) + { + GoToRow( 0 ); + GoToColumnId( 1 ); + } +} + +void DataBrowser::InsertColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertDataSeries( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::InsertTextColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertComplexCategoryLevel( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::RemoveColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( nColIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_bDataValid = true; + m_apDataBrowserModel->removeDataSeriesOrComplexCategoryLevel( nColIdx ); + RenewTable(); + } +} + +void DataBrowser::InsertRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( nRowIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx ); + RenewTable(); + } +} + +void DataBrowser::RemoveRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( nRowIdx >= 0 && m_apDataBrowserModel) + { + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_bDataValid = true; + m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx ); + RenewTable(); + } +} + +void DataBrowser::MoveLeftColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( !(nColIdx > 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataSeries( nColIdx - 1 ); + + // keep cursor in swapped column + if(( 0 < GetCurColumnId() ) && ( GetCurColumnId() <= ColCount() - 1 )) + { + Dispatch( BROWSER_CURSORLEFT ); + } + RenewTable(); +} + +void DataBrowser::MoveRightColumn() +{ + sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders ); + + if( !(nColIdx >= 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataSeries( nColIdx ); + + // keep cursor in swapped column + if( GetCurColumnId() < ColCount() - 1 ) + { + Dispatch( BROWSER_CURSORRIGHT ); + } + RenewTable(); +} + +void DataBrowser::MoveUpRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( !(nRowIdx > 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx - 1 ); + + // keep cursor in swapped row + if(( 0 < GetCurRow() ) && ( GetCurRow() <= GetRowCount() - 1 )) + { + Dispatch( BROWSER_CURSORUP ); + } + RenewTable(); +} + +void DataBrowser::MoveDownRow() +{ + sal_Int32 nRowIdx = GetCurRow(); + + if( !(nRowIdx >= 0 && m_apDataBrowserModel)) + return; + + // save changes made to edit-field + if( IsModified() ) + SaveModified(); + + m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx ); + + // keep cursor in swapped row + if( GetCurRow() < GetRowCount() - 1 ) + { + Dispatch( BROWSER_CURSORDOWN ); + } + RenewTable(); +} + +void DataBrowser::SetCursorMovedHdl( const Link& rLink ) +{ + m_aCursorMovedHdlLink = rLink; +} + +// implementations for ::svt::EditBrowseBox (pure virtual methods) +void DataBrowser::PaintCell( + OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const +{ + Point aPos( rRect.TopLeft()); + aPos.AdjustX(1 ); + + OUString aText = GetCellText( m_nSeekRow, nColumnId ); + Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight()); + + // clipping + if( aPos.X() < rRect.Right() || aPos.X() + TxtSize.Width() > rRect.Right() || + aPos.Y() < rRect.Top() || aPos.Y() + TxtSize.Height() > rRect.Bottom()) + rDev.SetClipRegion(vcl::Region(rRect)); + + // allow for a disabled control ... + bool bEnabled = IsEnabled(); + Color aOriginalColor = rDev.GetTextColor(); + if( ! bEnabled ) + rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() ); + + // draw the text + rDev.DrawText( aPos, aText ); + + // reset the color (if necessary) + if( ! bEnabled ) + rDev.SetTextColor( aOriginalColor ); + + if( rDev.IsClipRegion()) + rDev.SetClipRegion(); +} + +bool DataBrowser::SeekRow( sal_Int32 nRow ) +{ + if( ! EditBrowseBox::SeekRow( nRow )) + return false; + + if( nRow < 0 ) + m_nSeekRow = - 1; + else + m_nSeekRow = nRow; + + return true; +} + +bool DataBrowser::IsTabAllowed( bool bForward ) const +{ + sal_Int32 nRow = GetCurRow(); + sal_Int32 nCol = GetCurColumnId(); + + // column 0 is header-column + sal_Int32 nBadCol = bForward + ? GetColumnCount() - 1 + : 1; + sal_Int32 nBadRow = bForward + ? GetRowCount() - 1 + : 0; + + if( !m_bDataValid ) + { + const_cast< DataBrowser* >( this )->ShowWarningBox(); + return false; + } + + return ( nRow != nBadRow || + nCol != nBadCol ); +} + +::svt::CellController* DataBrowser::GetController( sal_Int32 /*nRow*/, sal_uInt16 nCol ) +{ + if( m_bIsReadOnly ) + return nullptr; + + if( CellContainsNumbers( nCol )) + { + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.UseInputStringForFormatting(); + rFormatter.SetFormatKey( GetNumberFormatKey( nCol )); + return m_rNumberEditController.get(); + } + + return m_rTextEditController.get(); +} + +void DataBrowser::InitController( + ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) +{ + if( rController == m_rTextEditController ) + { + OUString aText( GetCellText( nRow, nCol ) ); + weld::Entry& rEntry = m_aTextEditField->get_widget(); + rEntry.set_text(aText); + rEntry.select_region(0, -1); + } + else if( rController == m_rNumberEditController ) + { + // treat invalid and empty text as Nan + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + rFormatter.EnableNotANumber( true ); + if( std::isnan( GetCellNumber( nRow, nCol ))) + rFormatter.SetTextValue( OUString()); + else + rFormatter.SetValue( GetCellNumber( nRow, nCol ) ); + weld::Entry& rEntry = m_aNumberEditField->get_widget(); + rEntry.select_region(0, -1); + } + else + { + OSL_FAIL( "Invalid Controller" ); + } +} + +bool DataBrowser::CellContainsNumbers( sal_uInt16 nCol ) const +{ + if (!m_apDataBrowserModel) + return false; + return m_apDataBrowserModel->getCellType( lcl_getColumnInData( nCol )) == DataBrowserModel::NUMBER; +} + +sal_uInt32 DataBrowser::GetNumberFormatKey( sal_uInt16 nCol ) const +{ + if (!m_apDataBrowserModel) + return 0; + return m_apDataBrowserModel->getNumberFormatKey( lcl_getColumnInData( nCol ) ); +} + +bool DataBrowser::isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue ) +{ + sal_uInt32 nNumberFormat=0; + SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr; + if( !aInputString.isEmpty() && pSvNumberFormatter && pSvNumberFormatter->IsNumberFormat( aInputString, nNumberFormat, fOutDateTimeValue ) ) + { + SvNumFormatType nType = pSvNumberFormatter->GetType( nNumberFormat); + return (nType & SvNumFormatType::DATE) || (nType & SvNumFormatType::TIME); + } + return false; +} + +bool DataBrowser::SaveModified() +{ + if( ! IsModified() ) + return true; + + bool bChangeValid = true; + + const sal_Int32 nRow = GetCurRow(); + const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId()); + + OSL_ENSURE( nRow >= 0 || nCol >= 0, "This cell should not be modified!" ); + + SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr; + switch( m_apDataBrowserModel->getCellType( nCol )) + { + case DataBrowserModel::NUMBER: + { + sal_uInt32 nDummy = 0; + double fDummy = 0.0; + OUString aText(m_aNumberEditField->get_widget().get_text()); + // an empty string is valid, if no numberformatter exists, all + // values are treated as valid + if( !aText.isEmpty() && pSvNumberFormatter && + ! pSvNumberFormatter->IsNumberFormat( aText, nDummy, fDummy ) ) + { + bChangeValid = false; + } + else + { + Formatter& rFormatter = m_aNumberEditField->get_formatter(); + double fData = rFormatter.GetValue(); + bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData ); + } + } + break; + case DataBrowserModel::TEXTORDATE: + { + weld::Entry& rEntry = m_aTextEditField->get_widget(); + OUString aText(rEntry.get_text()); + double fValue = 0.0; + bChangeValid = false; + if( isDateTimeString( aText, fValue ) ) + bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( fValue ) ); + if(!bChangeValid) + bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( aText ) ); + } + break; + case DataBrowserModel::TEXT: + { + weld::Entry& rEntry = m_aTextEditField->get_widget(); + OUString aText(rEntry.get_text()); + bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText ); + } + break; + } + + // the first valid change changes this to true + if( bChangeValid ) + { + RowModified( GetCurRow(), GetCurColumnId()); + ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId()); + if( pCtrl ) + pCtrl->SaveValue(); + } + + return bChangeValid; +} + +bool DataBrowser::EndEditing() +{ + SaveModified(); + + // apply changes made to series headers + for( const auto& spHeader : m_aSeriesHeaders ) + spHeader->applyChanges(); + + if( m_bDataValid ) + return true; + else + return ShowQueryBox(); +} + +void DataBrowser::ColumnResized( sal_uInt16 nColId ) +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + EditBrowseBox::ColumnResized( nColId ); + ImplAdjustHeaderControls(); + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::EndScroll() +{ + bool bLastUpdateMode = GetUpdateMode(); + SetUpdateMode( false ); + + EditBrowseBox::EndScroll(); + RenewSeriesHeaders(); + + SetUpdateMode( bLastUpdateMode ); +} + +void DataBrowser::RenewSeriesHeaders() +{ + clearHeaders(); + DataBrowserModel::tDataHeaderVector aHeaders( m_apDataBrowserModel->getDataHeaders()); + Link aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus )); + Link aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged )); + + for (auto const& elemHeader : aHeaders) + { + auto spHeader = std::make_shared( m_pColumnsWin, m_pColorsWin ); + Color nColor; + if( elemHeader.m_xDataSeries.is() && + ( elemHeader.m_xDataSeries->getPropertyValue( "Color" ) >>= nColor )) + spHeader->SetColor( nColor ); + spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis ); + spHeader->SetSeriesName( + DataSeriesHelper::getDataSeriesLabel( + elemHeader.m_xDataSeries, + (elemHeader.m_xChartType.is() ? + elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() : + OUString( "values-y")))); + spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 ); + spHeader->SetGetFocusHdl( aFocusLink ); + spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink ); + m_aSeriesHeaders.push_back( spHeader ); + } + + ImplAdjustHeaderControls(); +} + +void DataBrowser::ImplAdjustHeaderControls() +{ + sal_uInt16 nColCount = GetColumnCount(); + sal_uInt32 nCurrentPos = GetPosPixel().getX(); + sal_uInt32 nMaxPos = nCurrentPos + GetOutputSizePixel().getWidth(); + sal_uInt32 nStartPos = nCurrentPos; + + // width of header column + nCurrentPos += GetColumnWidth( 0 ); + + weld::Container* pWin = m_pColumnsWin; + weld::Container* pColorWin = m_pColorsWin; + pWin->set_margin_start(nCurrentPos); + pColorWin->set_margin_start(nCurrentPos); + + tSeriesHeaderContainer::iterator aIt( m_aSeriesHeaders.begin()); + sal_uInt16 i = GetFirstVisibleColNumber(); + while( (aIt != m_aSeriesHeaders.end()) && ((*aIt)->GetStartColumn() < i) ) + { + (*aIt)->Hide(); + ++aIt; + } + for( ; i < nColCount && aIt != m_aSeriesHeaders.end(); ++i ) + { + if( (*aIt)->GetStartColumn() == i ) + nStartPos = nCurrentPos; + + nCurrentPos += (GetColumnWidth( i )); + + if( (*aIt)->GetEndColumn() == i ) + { + if( nStartPos < nMaxPos ) + { + (*aIt)->SetPixelWidth( nCurrentPos - nStartPos ); + (*aIt)->Show(); + + if (pWin) + { + pWin->set_margin_start(nStartPos); + pColorWin->set_margin_start(nStartPos); + pWin = pColorWin = nullptr; + } + + } + else + (*aIt)->Hide(); + ++aIt; + } + } +} + +IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, rEdit, void ) +{ + rEdit.SetShowWarningBox( !m_bDataValid ); + + if( !m_bDataValid ) + GoToCell( 0, 0 ); + else + { + MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( rEdit.getStartColumn()) ); + ActivateCell(); + m_aCursorMovedHdlLink.Call( this ); + } +} + +IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit&, rEdit, void ) +{ + rtl::Reference< DataSeries > xSeries = + m_apDataBrowserModel->getDataSeriesByColumn( rEdit.getStartColumn() - 1 ); + if( !xSeries.is()) + return; + + rtl::Reference< ChartType > xChartType( + m_apDataBrowserModel->getHeaderForSeries( xSeries ).m_xChartType ); + if( xChartType.is()) + { + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq = + DataSeriesHelper::getDataSequenceByRole( xSeries, xChartType->getRoleOfSequenceForSeriesLabel()); + if( xLabeledSeq.is()) + { + Reference< container::XIndexReplace > xIndexReplace( xLabeledSeq->getLabel(), uno::UNO_QUERY ); + if( xIndexReplace.is()) + xIndexReplace->replaceByIndex( + 0, uno::Any( rEdit.GetText())); + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowser.hxx b/chart2/source/controller/dialogs/DataBrowser.hxx new file mode 100644 index 000000000..c1d6a72e6 --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowser.hxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include +#include + +namespace com::sun::star { + namespace awt { + class XWindow; + } + namespace chart2 { + class XChartDocument; + } +} + +namespace com::sun::star::uno { class XComponentContext; } + +class OutputDevice; + +namespace chart +{ + +class DataBrowserModel; +class NumberFormatterWrapper; +class ChartModel; + +namespace impl +{ +class SeriesHeader; +class SeriesHeaderEdit; +} + +class DataBrowser : public ::svt::EditBrowseBox +{ +protected: + // EditBrowseBox overridables + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const override; + virtual bool SeekRow( sal_Int32 nRow ) override; + virtual bool IsTabAllowed( bool bForward ) const override; + virtual ::svt::CellController* GetController( sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual void InitController( ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol ) override; + virtual bool SaveModified() override; + virtual void CursorMoved() override; + // called whenever the control of the current cell has been modified + virtual void CellModified() override; + virtual void ColumnResized( sal_uInt16 nColId ) override; + virtual void EndScroll() override; + virtual void MouseButtonDown( const BrowserMouseEvent& rEvt ) override; + +public: + DataBrowser(const css::uno::Reference &rParent, + weld::Container* pColumns, weld::Container* pColors); + + virtual ~DataBrowser() override; + virtual void dispose() override; + + /** GetCellText returns the text at the given position + @param nRow + the number of the row + @param nColId + the ID of the column + @return + the text out of the cell + */ + virtual OUString GetCellText(sal_Int32 nRow, sal_uInt16 nColId) const override; + + /** returns the number in the given cell. If a cell is empty or contains a + string, the result will be Nan + */ + double GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const; + + bool isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue ); + + // Window + virtual void Resize() override; + + void SetReadOnly( bool bNewState ); + bool IsReadOnly() const { return m_bIsReadOnly;} + + void SetDataFromModel( const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + // predicates to determine what actions are possible at the current cursor + // position. This depends on the implementation of the according mutators + // below. (They are used for enabling toolbar icons) + bool MayInsertRow() const; + bool MayInsertColumn() const; + bool MayDeleteRow() const; + bool MayDeleteColumn() const; + + bool MayMoveUpRows() const; + bool MayMoveDownRows() const; + bool MayMoveRightColumns() const; + bool MayMoveLeftColumns() const; + + // mutators mutating data + void InsertRow(); + void InsertColumn(); + void InsertTextColumn(); + void RemoveRow(); + void RemoveColumn(); + + using BrowseBox::RemoveColumn; + using BrowseBox::MouseButtonDown; + + void MoveUpRow(); + void MoveDownRow(); + void MoveLeftColumn(); + void MoveRightColumn(); + + void SetCursorMovedHdl( const Link& rLink ); + + /// confirms all pending changes to be ready to be closed + bool EndEditing(); + + bool CellContainsNumbers( sal_uInt16 nCol ) const; + + sal_uInt32 GetNumberFormatKey( sal_uInt16 nCol ) const; + + bool IsEnableItem() const { return m_bDataValid;} + bool IsDataValid() const; + void ShowWarningBox(); + bool ShowQueryBox(); + + void RenewSeriesHeaders(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartDoc; + std::unique_ptr< DataBrowserModel > m_apDataBrowserModel; + + typedef std::vector< std::shared_ptr< impl::SeriesHeader > > tSeriesHeaderContainer; + tSeriesHeaderContainer m_aSeriesHeaders; + + std::shared_ptr< NumberFormatterWrapper > m_spNumberFormatterWrapper; + + /// the row that is currently painted + sal_Int32 m_nSeekRow; + bool m_bIsReadOnly; + bool m_bDataValid; + + VclPtr m_aNumberEditField; + VclPtr m_aTextEditField; + weld::Container* m_pColumnsWin; + weld::Container* m_pColorsWin; + + /// note: m_aNumberEditField must precede this member! + ::svt::CellControllerRef m_rNumberEditController; + /// note: m_aTextEditField must precede this member! + ::svt::CellControllerRef m_rTextEditController; + + Link m_aCursorMovedHdlLink; + + void clearHeaders(); + void RenewTable(); + void ImplAdjustHeaderControls(); + + OUString GetColString( sal_Int32 nColumnId ) const; + + DECL_LINK( SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, void ); + DECL_LINK( SeriesHeaderChanged, impl::SeriesHeaderEdit&, void ); + + DataBrowser( const DataBrowser & ) = delete; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowserModel.cxx b/chart2/source/controller/dialogs/DataBrowserModel.cxx new file mode 100644 index 000000000..11c6f19d7 --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowserModel.cxx @@ -0,0 +1,936 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DataBrowserModel.hxx" +#include "DialogModel.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart { + +namespace { + +OUString lcl_getRole( + const Reference< chart2::data::XDataSequence > & xSeq ) +{ + OUString aResult; + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( "Role" ) >>= aResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return aResult; +} + +OUString lcl_getUIRoleName( + const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) +{ + OUString aResult = DataSeriesHelper::getRole(xLSeq); + if( !aResult.isEmpty()) + aResult = DialogModel::ConvertRoleFromInternalToUI(aResult); + return aResult; +} + +void lcl_copyDataSequenceProperties( + const Reference< chart2::data::XDataSequence > & xOldSequence, + const Reference< chart2::data::XDataSequence > & xNewSequence ) +{ + Reference< beans::XPropertySet > xOldSeqProp( xOldSequence, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xNewSeqProp( xNewSequence, uno::UNO_QUERY ); + comphelper::copyProperties( xOldSeqProp, xNewSeqProp ); +} + +bool lcl_SequenceOfSeriesIsShared( + const rtl::Reference< ::chart::DataSeries > & xSeries, + const Reference< chart2::data::XDataSequence > & xValues ) +{ + bool bResult = false; + if( !xValues.is()) + return bResult; + try + { + OUString aValuesRole( lcl_getRole( xValues )); + OUString aValuesRep( xValues->getSourceRangeRepresentation()); + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeq( xSeries->getDataSequences2()); + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : aLSeq ) + if (labeledDataSeq.is() && DataSeriesHelper::getRole(labeledDataSeq) == aValuesRole) + { + // getValues().is(), because lcl_getRole checked that already + bResult = (aValuesRep == labeledDataSeq->getValues()->getSourceRangeRepresentation()); + // assumption: a role appears only once in a series + break; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bResult; +} + +typedef std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > lcl_tSharedSeqVec; + +lcl_tSharedSeqVec lcl_getSharedSequences( const std::vector< rtl::Reference< DataSeries > > & rSeries ) +{ + // @todo: if only some series share a sequence, those have to be duplicated + // and made unshared for all series + lcl_tSharedSeqVec aResult; + // if we have only one series, we don't want any shared sequences + if( rSeries.size() <= 1 ) + return aResult; + + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : rSeries[0]->getDataSequences2() ) + { + Reference< chart2::data::XDataSequence > xValues( labeledDataSeq->getValues()); + bool bShared = true; + for( std::size_t nSeriesIdx=1; nSeriesIdx & xLSeq ) +{ + sal_Int32 nResult = -1; + if( xLSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLSeq->getValues()); + if( xSeq.is()) + { + OUString aRep( xSeq->getSourceRangeRepresentation()); + nResult = aRep.toInt32(); + } + } + return nResult; +} + +struct lcl_RepresentationsOfLSeqMatch +{ + explicit lcl_RepresentationsOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : + m_aValuesRep( xLSeq.is() ? + (xLSeq->getValues().is() ? xLSeq->getValues()->getSourceRangeRepresentation() : OUString()) + : OUString() ) + {} + bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) + { + if (!xLSeq.is() || !xLSeq->getValues().is()) + return false; + + return xLSeq->getValues()->getSourceRangeRepresentation() == m_aValuesRep; + } +private: + OUString m_aValuesRep; +}; + +struct lcl_RolesOfLSeqMatch +{ + explicit lcl_RolesOfLSeqMatch( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) : + m_aRole(DataSeriesHelper::getRole(xLSeq)) {} + + bool operator() ( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) + { + return DataSeriesHelper::getRole(xLSeq) == m_aRole; + } +private: + OUString m_aRole; +}; + +bool lcl_ShowCategoriesAsDataLabel( const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + return !DiagramHelper::isCategoryDiagram(xDiagram); +} + +} // anonymous namespace + +struct DataBrowserModel::tDataColumn +{ + rtl::Reference m_xDataSeries; + OUString m_aUIRoleName; + uno::Reference m_xLabeledDataSequence; + eCellType m_eCellType; + sal_Int32 m_nNumberFormatKey; + + // default CTOR + tDataColumn() : m_eCellType( TEXT ), m_nNumberFormatKey( 0 ) {} + // "full" CTOR + tDataColumn( + const rtl::Reference & xDataSeries, + const OUString& aUIRoleName, + const uno::Reference& xLabeledDataSequence, + eCellType aCellType, + sal_Int32 nNumberFormatKey ) : + m_xDataSeries( xDataSeries ), + m_aUIRoleName( aUIRoleName ), + m_xLabeledDataSequence( xLabeledDataSequence ), + m_eCellType( aCellType ), + m_nNumberFormatKey( nNumberFormatKey ) + {} +}; + +struct DataBrowserModel::implColumnLess +{ + bool operator() ( const DataBrowserModel::tDataColumn & rLeft, const DataBrowserModel::tDataColumn & rRight ) + { + if( rLeft.m_xLabeledDataSequence.is() && rRight.m_xLabeledDataSequence.is()) + { + return DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rLeft.m_xLabeledDataSequence)) < + DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rRight.m_xLabeledDataSequence)); + } + return true; + } +}; + +DataBrowserModel::DataBrowserModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) : + m_xChartDocument( xChartDoc ), + m_apDialogModel( new DialogModel( xChartDoc )) +{ + updateFromModel(); +} + +DataBrowserModel::~DataBrowserModel() +{} + +namespace +{ +struct lcl_DataSeriesOfHeaderMatches +{ + explicit lcl_DataSeriesOfHeaderMatches( + const rtl::Reference< ::chart::DataSeries > & xSeriesToCompareWith ) : + m_xSeries( xSeriesToCompareWith ) + {} + bool operator() ( const ::chart::DataBrowserModel::tDataHeader & rHeader ) + { + return (m_xSeries == rHeader.m_xDataSeries); + } +private: + rtl::Reference< ::chart::DataSeries > m_xSeries; +}; +} + +void DataBrowserModel::insertDataSeries( sal_Int32 nAfterColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + + if (!xDataProvider.is()) + return; + + if( isCategoriesColumn(nAfterColumnIndex) ) + // Move to the last category column. + nAfterColumnIndex = getCategoryColumnCount()-1; + + sal_Int32 nStartCol = 0; + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartDocument); + rtl::Reference xChartType; + rtl::Reference xSeries; + if (o3tl::make_unsigned(nAfterColumnIndex) < m_aColumns.size()) + // Get the data series at specific column position (if available). + xSeries = m_aColumns[nAfterColumnIndex].m_xDataSeries; + + sal_Int32 nSeriesNumberFormat = 0; + if( xSeries.is()) + { + // Use the chart type of the currently selected data series. + xChartType = DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ); + + // Find the corresponding header and determine the last column of this + // data series. + tDataHeaderVector::const_iterator aIt( + std::find_if( m_aHeaders.begin(), m_aHeaders.end(), + lcl_DataSeriesOfHeaderMatches( xSeries ))); + if( aIt != m_aHeaders.end()) + nStartCol = aIt->m_nEndColumn; + + // Get the number format too. + if( xSeries.is() ) + xSeries->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nSeriesNumberFormat; + } + else + { + // No data series at specified column position. Use the first chart type. + xChartType = DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + nStartCol = nAfterColumnIndex; + } + + if (!xChartType.is()) + return; + + // Get shared sequences of current series. Normally multiple data series + // only share "values-x" sequences. (TODO: simplify this logic). + lcl_tSharedSeqVec aSharedSequences = lcl_getSharedSequences( xChartType->getDataSeries2()); + + rtl::Reference<::chart::DataSeries> xNewSeries = + m_apDialogModel->insertSeriesAfter(xSeries, xChartType, true); + + if (!xNewSeries.is()) + // Failed to insert new data series to the model. Bail out. + return; + + const std::vector > & aLSequences = xNewSeries->getDataSequences2(); + sal_Int32 nSeqIdx = 0; + sal_Int32 nSeqSize = aLSequences.size(); + for (sal_Int32 nIndex = nStartCol; nSeqIdx < nSeqSize; ++nSeqIdx) + { + lcl_tSharedSeqVec::const_iterator aSharedIt( + std::find_if( aSharedSequences.begin(), aSharedSequences.end(), + lcl_RolesOfLSeqMatch( aLSequences[nSeqIdx] ))); + + if( aSharedIt != aSharedSequences.end()) + { + // Shared sequence. Most likely "values-x" sequence. Copy it from existing sequence. + aLSequences[nSeqIdx]->setValues( (*aSharedIt)->getValues()); + aLSequences[nSeqIdx]->setLabel( (*aSharedIt)->getLabel()); + } + else + { + // Insert a new column in the internal data for the new sequence. + xDataProvider->insertSequence( nIndex - 1 ); + + // values + Reference< chart2::data::XDataSequence > xNewSeq( + xDataProvider->createDataSequenceByRangeRepresentation( + OUString::number( nIndex ))); + lcl_copyDataSequenceProperties( + aLSequences[nSeqIdx]->getValues(), xNewSeq ); + aLSequences[nSeqIdx]->setValues( xNewSeq ); + + // labels + Reference< chart2::data::XDataSequence > xNewLabelSeq( + xDataProvider->createDataSequenceByRangeRepresentation( + "label " + + OUString::number( nIndex ))); + lcl_copyDataSequenceProperties( + aLSequences[nSeqIdx]->getLabel(), xNewLabelSeq ); + aLSequences[nSeqIdx]->setLabel( xNewLabelSeq ); + ++nIndex; + } + } + + if( nSeriesNumberFormat != 0 ) + { + //give the new series the same number format as the former series especially for bubble charts thus the bubble size values can be edited with same format immediately + xNewSeries->setPropertyValue(CHART_UNONAME_NUMFMT , uno::Any(nSeriesNumberFormat)); + } + + updateFromModel(); +} + +void DataBrowserModel::insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex ) +{ + //create a new text column for complex categories + + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is()) + return; + + if( !isCategoriesColumn(nAfterColumnIndex) ) + nAfterColumnIndex = getCategoryColumnCount()-1; + + if(nAfterColumnIndex<0) + { + OSL_FAIL( "wrong index for category level insertion" ); + return; + } + + m_apDialogModel->startControllerLockTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + xDataProvider->insertComplexCategoryLevel( nAfterColumnIndex+1 ); + updateFromModel(); +} + +void DataBrowserModel::removeComplexCategoryLevel( sal_Int32 nAtColumnIndex ) +{ + //delete a category column if there is more than one level (in case of a single column we do not get here) + OSL_ENSURE(nAtColumnIndex>0, "wrong index for categories deletion" ); + + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is()) + return; + + m_apDialogModel->startControllerLockTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + xDataProvider->deleteComplexCategoryLevel( nAtColumnIndex ); + + updateFromModel(); +} + +void DataBrowserModel::removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + if (nAtColumnIndex < 0 || o3tl::make_unsigned(nAtColumnIndex) >= m_aColumns.size()) + // Out of bound. + return; + + if (isCategoriesColumn(nAtColumnIndex)) + { + removeComplexCategoryLevel(nAtColumnIndex); + return; + } + + const rtl::Reference& xSeries = m_aColumns[nAtColumnIndex].m_xDataSeries; + + m_apDialogModel->deleteSeries(xSeries, getHeaderForSeries(xSeries).m_xChartType); + + //delete sequences from internal data provider that are not used anymore + //but do not delete sequences that are still in use by the remaining series + + Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + if (!xDataProvider.is() || !xSeries.is()) + { + // Something went wrong. Bail out. + updateFromModel(); + return; + } + + rtl::Reference xSeriesCnt(getHeaderForSeries(xSeries).m_xChartType); + if (!xSeriesCnt.is()) + { + // Unexpected happened. Bail out. + updateFromModel(); + return; + } + + // Collect all the remaining data sequences in the same chart type. The + // deleted data series is already gone by this point. + std::vector > aAllDataSeqs = + DataSeriesHelper::getAllDataSequences(xSeriesCnt->getDataSeries()); + + // Check if the sequences to be deleted are still referenced by any of + // the other data series. If not, mark them for deletion. + std::vector aSequenceIndexesToDelete; + const std::vector > & aSequencesOfDeleted = xSeries->getDataSequences2(); + for (auto const & labeledDataSeq : aSequencesOfDeleted) + { + // if not used by the remaining series this sequence can be deleted + if( std::none_of( aAllDataSeqs.begin(), aAllDataSeqs.end(), + lcl_RepresentationsOfLSeqMatch( labeledDataSeq )) ) + aSequenceIndexesToDelete.push_back( lcl_getValuesRepresentationIndex( labeledDataSeq ) ); + } + + // delete unnecessary sequences of the internal data + // iterate using greatest index first, so that deletion does not + // shift other sequences that will be deleted later + std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); + for( std::vector< sal_Int32 >::reverse_iterator aIt( + aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) + { + if( *aIt != -1 ) + xDataProvider->deleteSequence( *aIt ); + } + + updateFromModel(); +} + +void DataBrowserModel::swapDataSeries( sal_Int32 nFirstColumnIndex ) +{ + OSL_ASSERT(m_apDialogModel); + if( o3tl::make_unsigned( nFirstColumnIndex ) < m_aColumns.size() - 1 ) + { + rtl::Reference< DataSeries > xSeries( m_aColumns[nFirstColumnIndex].m_xDataSeries ); + if( xSeries.is()) + { + m_apDialogModel->moveSeries( xSeries, DialogModel::MoveDirection::Down ); + updateFromModel(); + } + } +} + +void DataBrowserModel::swapDataPointForAllSeries( sal_Int32 nFirstIndex ) +{ + OSL_ASSERT(m_apDialogModel); + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->swapDataPointWithNextOneForAllSequences( nFirstIndex ); + // unlockControllers +} + +void DataBrowserModel::insertDataPointForAllSeries( sal_Int32 nAfterIndex ) +{ + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->insertDataPointForAllSequences( nAfterIndex ); + // unlockControllers +} + +void DataBrowserModel::removeDataPointForAllSeries( sal_Int32 nAtIndex ) +{ + Reference< chart2::XInternalDataProvider > xDataProvider( + m_apDialogModel->getDataProvider(), uno::UNO_QUERY ); + // lockControllers + ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel()); + if( xDataProvider.is()) + xDataProvider->deleteDataPointForAllSequences( nAtIndex ); + // unlockControllers +} + +DataBrowserModel::tDataHeader DataBrowserModel::getHeaderForSeries( + const Reference< chart2::XDataSeries > & xSeries ) const +{ + rtl::Reference pSeries = dynamic_cast(xSeries.get()); + assert(!xSeries || pSeries); + for (auto const& elemHeader : m_aHeaders) + { + if( elemHeader.m_xDataSeries == pSeries ) + return elemHeader; + } + return tDataHeader(); +} + +rtl::Reference< DataSeries > + DataBrowserModel::getDataSeriesByColumn( sal_Int32 nColumn ) const +{ + tDataColumnVector::size_type nIndex( nColumn ); + if( nIndex < m_aColumns.size()) + return m_aColumns[nIndex].m_xDataSeries; + return nullptr; +} + +DataBrowserModel::eCellType DataBrowserModel::getCellType( sal_Int32 nAtColumn ) const +{ + eCellType eResult = TEXT; + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size()) + eResult = m_aColumns[nIndex].m_eCellType; + return eResult; +} + +double DataBrowserModel::getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XNumericalDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xData.is()) + { + Sequence< double > aValues( xData->getNumericalData()); + if( nAtRow < aValues.getLength()) + return aValues[nAtRow]; + } + } + return std::numeric_limits::quiet_NaN(); +} + +uno::Any DataBrowserModel::getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + uno::Any aResult; + + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues() ); + if( xData.is() ) + { + Sequence< uno::Any > aValues( xData->getData()); + if( nAtRow < aValues.getLength()) + aResult = aValues[nAtRow]; + } + } + return aResult; +} + +OUString DataBrowserModel::getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow ) +{ + OUString aResult; + + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XTextualDataSequence > xData( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xData.is()) + { + Sequence< OUString > aValues( xData->getTextualData()); + if( nAtRow < aValues.getLength()) + aResult = aValues[nAtRow]; + } + } + return aResult; +} + +sal_uInt32 DataBrowserModel::getNumberFormatKey( sal_Int32 nAtColumn ) +{ + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size()) + return m_aColumns[ nIndex ].m_nNumberFormatKey; + return 0; +} + +bool DataBrowserModel::setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const uno::Any & rValue ) +{ + bool bResult = false; + tDataColumnVector::size_type nIndex( nAtColumn ); + if( nIndex < m_aColumns.size() && + m_aColumns[ nIndex ].m_xLabeledDataSequence.is()) + { + bResult = true; + try + { + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + // label + if( nAtRow == -1 ) + { + Reference< container::XIndexReplace > xIndexReplace( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getLabel(), uno::UNO_QUERY_THROW ); + xIndexReplace->replaceByIndex( 0, rValue ); + } + else + { + Reference< container::XIndexReplace > xIndexReplace( + m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY_THROW ); + xIndexReplace->replaceByIndex( nAtRow, rValue ); + } + + m_apDialogModel->startControllerLockTimer(); + //notify change directly to the model (this is necessary here as sequences for complex categories not known directly to the chart model so they do not notify their changes) (for complex categories see issue #i82971#) + if( m_xChartDocument.is() ) + m_xChartDocument->setModified(true); + } + catch( const uno::Exception & ) + { + bResult = false; + } + } + return bResult; +} + +bool DataBrowserModel::setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue ) +{ + return (getCellType( nAtColumn ) == NUMBER) && + setCellAny( nAtColumn, nAtRow, uno::Any( fValue )); +} + +bool DataBrowserModel::setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const OUString & rText ) +{ + return (getCellType( nAtColumn ) == TEXT) && + setCellAny( nAtColumn, nAtRow, uno::Any( rText )); +} + +sal_Int32 DataBrowserModel::getColumnCount() const +{ + return static_cast< sal_Int32 >( m_aColumns.size()); +} + +sal_Int32 DataBrowserModel::getMaxRowCount() const +{ + sal_Int32 nResult = 0; + for (auto const& column : m_aColumns) + { + if( column.m_xLabeledDataSequence.is()) + { + Reference< chart2::data::XDataSequence > xSeq( + column.m_xLabeledDataSequence->getValues()); + if( !xSeq.is()) + continue; + sal_Int32 nLength( xSeq->getData().getLength()); + if( nLength > nResult ) + nResult = nLength; + } + } + + return nResult; +} + +OUString DataBrowserModel::getRoleOfColumn( sal_Int32 nColumnIndex ) const +{ + if( nColumnIndex != -1 && + o3tl::make_unsigned( nColumnIndex ) < m_aColumns.size()) + return m_aColumns[ nColumnIndex ].m_aUIRoleName; + return OUString(); +} + +bool DataBrowserModel::isCategoriesColumn( sal_Int32 nColumnIndex ) const +{ + if (nColumnIndex < 0) + return false; + + if (o3tl::make_unsigned(nColumnIndex) >= m_aColumns.size()) + return false; + + // A column is a category when it doesn't have an associated data series. + return !m_aColumns[nColumnIndex].m_xDataSeries.is(); +} + +sal_Int32 DataBrowserModel::getCategoryColumnCount() +{ + sal_Int32 nLastTextColumnIndex = -1; + for (auto const& column : m_aColumns) + { + if( !column.m_xDataSeries.is() ) + nLastTextColumnIndex++; + else + break; + } + return nLastTextColumnIndex+1; +} + +void DataBrowserModel::updateFromModel() +{ + if( !m_xChartDocument.is()) + return; + m_aColumns.clear(); + m_aHeaders.clear(); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDocument )); + if( !xDiagram.is()) + return; + + // set template at DialogModel + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartDocument->getTypeManager(); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + if( aTemplateAndService.xChartTypeTemplate.is()) + m_apDialogModel->setTemplate( aTemplateAndService.xChartTypeTemplate ); + + sal_Int32 nHeaderStart = 0; + sal_Int32 nHeaderEnd = 0; + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( ChartModelHelper::getFirstCoordinateSystem(m_xChartDocument), *m_xChartDocument ); + + const std::vector< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList = aExplicitCategoriesProvider.getSplitCategoriesList(); + sal_Int32 nLevelCount = rSplitCategoriesList.size(); + for( sal_Int32 nL = 0; nL xCategories( rSplitCategoriesList[nL] ); + if( !xCategories.is() ) + continue; + + tDataColumn aCategories; + aCategories.m_xLabeledDataSequence = xCategories; + if( lcl_ShowCategoriesAsDataLabel( xDiagram )) + aCategories.m_aUIRoleName = DialogModel::GetRoleDataLabel(); + else + aCategories.m_aUIRoleName = lcl_getUIRoleName( xCategories ); + aCategories.m_eCellType = TEXTORDATE; + m_aColumns.push_back( aCategories ); + ++nHeaderStart; + } + } + + if( !xDiagram.is()) + return; + const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq( xDiagram->getBaseCoordinateSystems()); + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + const std::vector< rtl::Reference< ChartType > > aChartTypes( coords->getChartTypes2()); + sal_Int32 nXAxisNumberFormat = DataSeriesHelper::getNumberFormatKeyFromAxis( nullptr, coords, 0, 0 ); + + for( auto const & CT: aChartTypes ) + { + rtl::Reference< ChartType > xSeriesCnt( CT ); + OUString aRoleForDataLabelNumberFormat = ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( CT ); + + const std::vector< rtl::Reference< DataSeries > > & aSeries( xSeriesCnt->getDataSeries2()); + lcl_tSharedSeqVec aSharedSequences( lcl_getSharedSequences( aSeries )); + for (auto const& sharedSequence : aSharedSequences) + { + tDataColumn aSharedSequence; + aSharedSequence.m_xLabeledDataSequence = sharedSequence; + aSharedSequence.m_aUIRoleName = lcl_getUIRoleName(sharedSequence); + aSharedSequence.m_eCellType = NUMBER; + // as the sequences are shared it should be ok to take the first series + // @todo: dimension index 0 for x-values used here. This is just a guess. + // Also, the axis index is 0, as there is usually only one x-axis + aSharedSequence.m_nNumberFormatKey = nXAxisNumberFormat; + m_aColumns.push_back( aSharedSequence ); + ++nHeaderStart; + } + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + tDataColumnVector::size_type nStartColIndex = m_aColumns.size(); + rtl::Reference< DataSeries > xSeries( dataSeries ); + if( xSeries.is()) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeqs( xSeries->getDataSequences2()); + if( aLSeqs.empty() ) + continue; + nHeaderEnd = nHeaderStart; + + // @todo: dimension index 1 for y-values used here. This is just a guess + sal_Int32 nYAxisNumberFormatKey = + DataSeriesHelper::getNumberFormatKeyFromAxis( + dataSeries, coords, 1 ); + + sal_Int32 nSeqIdx=0; + for( ; nSeqIdx(aLSeqs.size()); ++nSeqIdx ) + { + sal_Int32 nSequenceNumberFormatKey = nYAxisNumberFormatKey; + OUString aRole = DataSeriesHelper::getRole(aLSeqs[nSeqIdx]); + + if( aRole == aRoleForDataLabelNumberFormat ) + { + nSequenceNumberFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + xSeries); + } + else if( aRole == "values-x" ) + nSequenceNumberFormatKey = nXAxisNumberFormat; + + if( std::none_of( aSharedSequences.begin(), aSharedSequences.end(), + lcl_RepresentationsOfLSeqMatch( aLSeqs[nSeqIdx] )) ) + { + // no shared sequence + m_aColumns.emplace_back( + dataSeries, + lcl_getUIRoleName( aLSeqs[nSeqIdx] ), + aLSeqs[nSeqIdx], + NUMBER, + nSequenceNumberFormatKey ); + ++nHeaderEnd; + } + // else skip + } + bool bSwapXAndYAxis = false; + try + { + coords->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndYAxis; + } + catch( const beans::UnknownPropertyException & ) {} + + // add ranges for error bars if present for a series + if( StatisticsHelper::usesErrorBarRanges( dataSeries )) + addErrorBarRanges( dataSeries, nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, true ); + + if( StatisticsHelper::usesErrorBarRanges( dataSeries, /* bYError = */ false )) + addErrorBarRanges( dataSeries, nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, false ); + + m_aHeaders.emplace_back( + dataSeries, + CT, + bSwapXAndYAxis, + nHeaderStart, + nHeaderEnd - 1 ); + + nHeaderStart = nHeaderEnd; + + std::sort( m_aColumns.begin() + nStartColIndex, m_aColumns.end(), implColumnLess() ); + } + } + } + } +} + +void DataBrowserModel::addErrorBarRanges( + const Reference< chart2::XDataSeries > & xDataSeries, + sal_Int32 nNumberFormatKey, + sal_Int32 & rInOutSequenceIndex, + sal_Int32 & rInOutHeaderEnd, bool bYError ) +{ + try + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences; + + Reference< chart2::data::XDataSource > xErrorSource( + StatisticsHelper::getErrorBars( xDataSeries, bYError ), uno::UNO_QUERY ); + + uno::Reference< chart2::data::XLabeledDataSequence > xErrorLSequence = + StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + xErrorSource, + /* bPositiveValue = */ true, + bYError ); + if( xErrorLSequence.is()) + aSequences.push_back( xErrorLSequence ); + + xErrorLSequence = + StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + xErrorSource, + /* bPositiveValue = */ false, + bYError ); + if( xErrorLSequence.is()) + aSequences.push_back( xErrorLSequence ); + + for (uno::Reference const & rDataSequence : aSequences) + { + rtl::Reference pDataSeries = dynamic_cast(xDataSeries.get()); + assert(pDataSeries || !xDataSeries); + m_aColumns.emplace_back(pDataSeries, lcl_getUIRoleName(rDataSequence), + rDataSequence, NUMBER, nNumberFormatKey); + ++rInOutSequenceIndex; + ++rInOutHeaderEnd; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DataBrowserModel.hxx b/chart2/source/controller/dialogs/DataBrowserModel.hxx new file mode 100644 index 000000000..3eb1756fa --- /dev/null +++ b/chart2/source/controller/dialogs/DataBrowserModel.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include + +#include +#include + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace com::sun::star::chart2 { + class XDataSeries; + class XChartType; +} + +namespace chart +{ + +class DialogModel; +class ChartModel; +class ChartType; +class DataSeries; + +class DataBrowserModel final +{ +public: + explicit DataBrowserModel( + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + ~DataBrowserModel(); + + /** Inserts a new data series after the data series to which the data column + with index nAfterColumnIndex belongs. + */ + void insertDataSeries( sal_Int32 nAfterColumnIndex ); + + /** Inserts a new text column for complex categories. + */ + void insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex ); + + /** Removes a data series to which the data column with index nAtColumnIndex + belongs. + */ + void removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex ); + + /** Swaps the series to which the data column with index nFirstIndex belongs + with the next series (which starts at an index >= nFirstIndex + 1) + */ + void swapDataSeries( sal_Int32 nFirstIndex ); + void swapDataPointForAllSeries( sal_Int32 nFirstIndex ); + + void insertDataPointForAllSeries( sal_Int32 nAfterIndex ); + void removeDataPointForAllSeries( sal_Int32 nAtIndex ); + + enum eCellType + { + NUMBER, + TEXT, + TEXTORDATE + }; + + eCellType getCellType( sal_Int32 nAtColumn ) const; + /// If getCellType( nAtColumn, nAtRow ) returns TEXT, the result will be Nan + double getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + OUString getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + css::uno::Any getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow ); + sal_uInt32 getNumberFormatKey( sal_Int32 nAtColumn ); + + /// returns if the number could successfully be set at the given position + bool setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue ); + /// returns if the text could successfully be set at the given position + bool setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const OUString & rText ); + bool setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const css::uno::Any & aValue ); + + sal_Int32 getColumnCount() const; + sal_Int32 getMaxRowCount() const; + + // returns the UI string of the corresponding role + OUString getRoleOfColumn( sal_Int32 nColumnIndex ) const; + bool isCategoriesColumn( sal_Int32 nColumnIndex ) const; + + struct tDataHeader + { + rtl::Reference< ::chart::DataSeries > m_xDataSeries; + rtl::Reference< ::chart::ChartType > m_xChartType; + bool m_bSwapXAndYAxis; + sal_Int32 m_nStartColumn; + sal_Int32 m_nEndColumn; + + // default CTOR + tDataHeader() : + m_bSwapXAndYAxis( false ), + m_nStartColumn( -1 ), + m_nEndColumn( -1 ) + {} + // "full" CTOR + tDataHeader( + rtl::Reference< ::chart::DataSeries > const & xDataSeries, + rtl::Reference< ::chart::ChartType > const &xChartType, + bool bSwapXAndYAxis, + sal_Int32 nStartColumn, + sal_Int32 nEndColumn ) : + m_xDataSeries( xDataSeries ), + m_xChartType( xChartType ), + m_bSwapXAndYAxis( bSwapXAndYAxis ), + m_nStartColumn( nStartColumn ), + m_nEndColumn( nEndColumn ) + {} + }; + + typedef std::vector< tDataHeader > tDataHeaderVector; + + const tDataHeaderVector& getDataHeaders() const { return m_aHeaders;} + + tDataHeader getHeaderForSeries( + const css::uno::Reference< css::chart2::XDataSeries > &xSeries ) const; + + rtl::Reference< ::chart::DataSeries > + getDataSeriesByColumn( sal_Int32 nColumn ) const; + +private: + void updateFromModel(); + + void removeComplexCategoryLevel( sal_Int32 nAtColumnIndex ); + + void addErrorBarRanges( + const css::uno::Reference & xDataSeries, + sal_Int32 nNumberFormatKey, + sal_Int32 & rInOutSequenceIndex, + sal_Int32 & rInOutHeaderEnd, bool bYError ); + + sal_Int32 getCategoryColumnCount(); + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + std::unique_ptr< DialogModel > m_apDialogModel; + + struct tDataColumn; + struct implColumnLess; + + typedef std::vector< tDataColumn > tDataColumnVector; + + tDataColumnVector m_aColumns; + tDataHeaderVector m_aHeaders; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DialogModel.cxx b/chart2/source/controller/dialogs/DialogModel.cxx new file mode 100644 index 000000000..2d12bc6cd --- /dev/null +++ b/chart2/source/controller/dialogs/DialogModel.cxx @@ -0,0 +1,841 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DialogModel.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +constexpr OUStringLiteral lcl_aLabelRole( u"label" ); + + +OUString lcl_ConvertRole( const OUString & rRoleString ) +{ + OUString aResult( rRoleString ); + + typedef std::map< OUString, OUString > tTranslationMap; + static const tTranslationMap aTranslationMap = + { + { "categories", ::chart::SchResId( STR_DATA_ROLE_CATEGORIES ) }, + { "error-bars-x", ::chart::SchResId( STR_DATA_ROLE_X_ERROR ) }, + { "error-bars-x-positive", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_POSITIVE ) }, + { "error-bars-x-negative", ::chart::SchResId( STR_DATA_ROLE_X_ERROR_NEGATIVE ) }, + { "error-bars-y", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR ) }, + { "error-bars-y-positive", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_POSITIVE ) }, + { "error-bars-y-negative", ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_NEGATIVE ) }, + { "label", ::chart::SchResId( STR_DATA_ROLE_LABEL ) }, + { "values-first", ::chart::SchResId( STR_DATA_ROLE_FIRST ) }, + { "values-last", ::chart::SchResId( STR_DATA_ROLE_LAST ) }, + { "values-max", ::chart::SchResId( STR_DATA_ROLE_MAX ) }, + { "values-min", ::chart::SchResId( STR_DATA_ROLE_MIN ) }, + { "values-x", ::chart::SchResId( STR_DATA_ROLE_X ) }, + { "values-y", ::chart::SchResId( STR_DATA_ROLE_Y ) }, + { "values-size", ::chart::SchResId( STR_DATA_ROLE_SIZE ) }, + { "FillColor", ::chart::SchResId( STR_PROPERTY_ROLE_FILLCOLOR ) }, + { "BorderColor", ::chart::SchResId( STR_PROPERTY_ROLE_BORDERCOLOR ) }, + }; + + tTranslationMap::const_iterator aIt( aTranslationMap.find( rRoleString )); + if( aIt != aTranslationMap.end()) + { + aResult = (*aIt).second; + } + return aResult; +} + +typedef std::map< OUString, sal_Int32 > lcl_tRoleIndexMap; + +lcl_tRoleIndexMap lcl_createRoleIndexMap() +{ + lcl_tRoleIndexMap aMap; + sal_Int32 nIndex = 0; + + aMap[ "label" ] = ++nIndex; + aMap[ "categories" ] = ++nIndex; + aMap[ "values-x" ] = ++nIndex; + aMap[ "values-y" ] = ++nIndex; + aMap[ "error-bars-x" ] = ++nIndex; + aMap[ "error-bars-x-positive" ] = ++nIndex; + aMap[ "error-bars-x-negative" ] = ++nIndex; + aMap[ "error-bars-y" ] = ++nIndex; + aMap[ "error-bars-y-positive" ] = ++nIndex; + aMap[ "error-bars-y-negative" ] = ++nIndex; + aMap[ "values-first" ] = ++nIndex; + aMap[ "values-min" ] = ++nIndex; + aMap[ "values-max" ] = ++nIndex; + aMap[ "values-last" ] = ++nIndex; + aMap[ "values-size" ] = ++nIndex; + + return aMap; +} + + +struct lcl_RolesWithRangeAppend +{ + typedef Reference< data::XLabeledDataSequence > value_type; + typedef ::chart::DialogModel::tRolesWithRanges tContainerType; + + explicit lcl_RolesWithRangeAppend( tContainerType * rCnt, + const OUString & aLabelRole ) + : m_rDestCnt( rCnt ), + m_aRoleForLabelSeq( aLabelRole ) + {} + + lcl_RolesWithRangeAppend & operator= ( const value_type & xVal ) + { + try + { + if( xVal.is()) + { + // data sequence + Reference< data::XDataSequence > xSeq( xVal->getValues()); + if( xSeq.is()) + { + OUString aRole; + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + if( xProp->getPropertyValue( "Role" ) >>= aRole ) + { + m_rDestCnt->emplace(aRole, xSeq->getSourceRangeRepresentation()); + // label + if( aRole == m_aRoleForLabelSeq ) + { + Reference< data::XDataSequence > xLabelSeq( xVal->getLabel()); + if( xLabelSeq.is()) + { + m_rDestCnt->emplace( + lcl_aLabelRole, xLabelSeq->getSourceRangeRepresentation()); + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return *this; + } + + // Implement output operator requirements as required by std::copy (and + // implement prefix increment in terms of postfix increment to avoid unused + // member function warnings for the latter in the common case where + // std::copy would not actually need it): + lcl_RolesWithRangeAppend & operator* () { return *this; } + lcl_RolesWithRangeAppend & operator++ () { return operator++(0); } + lcl_RolesWithRangeAppend & operator++ (int) { return *this; } + +private: + tContainerType * m_rDestCnt; + OUString m_aRoleForLabelSeq; +}; + +} + +namespace std +{ + template<> struct iterator_traits + { + typedef std::output_iterator_tag iterator_category; + typedef Reference< data::XLabeledDataSequence > value_type; + typedef value_type& reference; + }; +} + +namespace { + +void lcl_SetSequenceRole( + const Reference< data::XDataSequence > & xSeq, + const OUString & rRole ) +{ + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is()) + xProp->setPropertyValue( "Role" , uno::Any( rRole )); +} + +Sequence< OUString > lcl_CopyExcludingValuesFirst( + Sequence< OUString > const & i_aInput ) +{ + Sequence< OUString > aOutput( i_aInput.getLength()); + auto pOutput = aOutput.getArray(); + int nSourceIndex, nDestIndex; + for( nSourceIndex = nDestIndex = 0; nSourceIndex < i_aInput.getLength(); nSourceIndex++ ) + { + if( i_aInput[nSourceIndex] == "values-first" ) + { + aOutput.realloc( aOutput.getLength() - 1 ); + pOutput = aOutput.getArray(); + } + else + { + pOutput[nDestIndex] = i_aInput[nSourceIndex]; + nDestIndex++; + } + } + return aOutput; +} + +rtl::Reference< ::chart::DataSeries > lcl_CreateNewSeries( + const rtl::Reference< ::chart::ChartType > & xChartType, + sal_Int32 nNewSeriesIndex, + sal_Int32 nTotalNumberOfSeriesInCTGroup, + const rtl::Reference< ::chart::Diagram > & xDiagram, + const rtl::Reference< ::chart::ChartTypeTemplate > & xTemplate, + bool bCreateDataCachedSequences ) +{ + // create plain series + rtl::Reference< ::chart::DataSeries > xResult = new ::chart::DataSeries(); + if( xTemplate.is()) + { + // @deprecated: correct default color should be found by view + // without setting it as hard attribute + Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is()) + xResult->setPropertyValue( "Color" , uno::Any( xColorScheme->getColorByIndex( nNewSeriesIndex ))); + std::size_t nGroupIndex=0; + if( xChartType.is()) + { + std::vector< rtl::Reference< ::chart::ChartType > > aCTs( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram )); + for( ; nGroupIndex < aCTs.size(); ++nGroupIndex) + if( aCTs[nGroupIndex] == xChartType ) + break; + if( nGroupIndex == aCTs.size()) + nGroupIndex = 0; + } + xTemplate->applyStyle2( xResult, nGroupIndex, nNewSeriesIndex, nTotalNumberOfSeriesInCTGroup ); + } + + if( bCreateDataCachedSequences ) + { + // set chart type specific roles + if( xChartType.is() ) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSequences; + const OUString aRoleOfSeqForSeriesLabel = xChartType->getRoleOfSequenceForSeriesLabel(); + const OUString aLabel(::chart::SchResId(STR_DATA_UNNAMED_SERIES)); + Sequence< OUString > aPossibleRoles( xChartType->getSupportedMandatoryRoles()); + Sequence< OUString > aPossibleOptRoles( xChartType->getSupportedOptionalRoles()); + + //special handling for candlestick type + if( xTemplate.is()) + { + rtl::Reference< ::chart::DataInterpreter > xInterpreter( xTemplate->getDataInterpreter2()); + if( xInterpreter.is()) + { + sal_Int32 nStockVariant; + if( xInterpreter->getChartTypeSpecificData("stock variant") >>= nStockVariant ) + { + if( nStockVariant == 0 || nStockVariant == 2) { + //delete "values-first" role + aPossibleRoles = lcl_CopyExcludingValuesFirst(aPossibleRoles); + aPossibleOptRoles = lcl_CopyExcludingValuesFirst(aPossibleOptRoles); + } + } + } + } + + const Sequence< OUString > aRoles( aPossibleRoles ); + const Sequence< OUString > aOptRoles( aPossibleOptRoles ); + + for(OUString const & role : aRoles) + { + if( role == lcl_aLabelRole ) + continue; + Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence() ); + lcl_SetSequenceRole( xSeq, role ); + // assert that aRoleOfSeqForSeriesLabel is part of the mandatory roles + if( role == aRoleOfSeqForSeriesLabel ) + { + Reference< data::XDataSequence > xLabel( ::chart::DataSourceHelper::createCachedDataSequence( aLabel )); + lcl_SetSequenceRole( xLabel, lcl_aLabelRole ); + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq, xLabel )); + } + else + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq )); + } + + for(OUString const & role : aOptRoles) + { + if( role == lcl_aLabelRole ) + continue; + Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence()); + lcl_SetSequenceRole( xSeq, role ); + aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq )); + } + + xResult->setData( aNewSequences ); + } + } + + return xResult; +} + +struct lcl_addSeriesNumber +{ + sal_Int32 operator() ( sal_Int32 nCurrentNumber, const Reference< XDataSeriesContainer > & xCnt ) const + { + if( xCnt.is()) + return nCurrentNumber + (xCnt->getDataSeries().getLength()); + return nCurrentNumber; + } +}; + +} // anonymous namespace + +namespace chart +{ + +DialogModelTimeBasedInfo::DialogModelTimeBasedInfo(): + bTimeBased(false), + nStart(0), + nEnd(0) +{ +} + +DialogModel::DialogModel( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + m_xChartDocument( xChartDocument ), + m_aTimerTriggeredControllerLock( m_xChartDocument ) +{ +} + +DialogModel::~DialogModel() +{ + if(maTimeBasedInfo.bTimeBased) + { + getModel().setTimeBasedRange(maTimeBasedInfo.nStart, maTimeBasedInfo.nEnd); + } +} + +void DialogModel::setTemplate( + const rtl::Reference< ChartTypeTemplate > & xTemplate ) +{ + m_xTemplate = xTemplate; +} + +std::shared_ptr< RangeSelectionHelper > const & + DialogModel::getRangeSelectionHelper() const +{ + if( ! m_spRangeSelectionHelper) + m_spRangeSelectionHelper = + std::make_shared( m_xChartDocument ); + + return m_spRangeSelectionHelper; +} + +const rtl::Reference<::chart::ChartModel> & DialogModel::getChartModel() const +{ + return m_xChartDocument; +} + +Reference< data::XDataProvider > DialogModel::getDataProvider() const +{ + Reference< data::XDataProvider > xResult; + if( m_xChartDocument.is()) + xResult.set( m_xChartDocument->getDataProvider()); + return xResult; +} + +std::vector< rtl::Reference< ChartType > > + DialogModel::getAllDataSeriesContainers() const +{ + std::vector< rtl::Reference< ChartType > > aResult; + + try + { + if( !m_xChartDocument ) + return {}; + rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram(); + if( xDiagram.is()) + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + + for (const auto & rxChartType : coords->getChartTypes2()) + aResult.push_back(rxChartType); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +std::vector< DialogModel::tSeriesWithChartTypeByName > + DialogModel::getAllDataSeriesWithLabel() const +{ + std::vector< tSeriesWithChartTypeByName > aResult; + std::vector< rtl::Reference< ChartType > > aContainers( + getAllDataSeriesContainers()); + + for (const auto & rxChartType : aContainers ) + { + try + { + const std::vector< rtl::Reference< DataSeries > > & aSeq = rxChartType->getDataSeries2(); + OUString aRole = rxChartType->getRoleOfSequenceForSeriesLabel(); + for( rtl::Reference< DataSeries > const & dataSeries : aSeq ) + { + aResult.push_back( + ::chart::DialogModel::tSeriesWithChartTypeByName( + ::chart::DataSeriesHelper::getDataSeriesLabel( dataSeries, aRole ), + std::make_pair( dataSeries, rxChartType ))); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +namespace { + +void addMissingRoles(DialogModel::tRolesWithRanges& rResult, const uno::Sequence& rRoles) +{ + for(OUString const & role : rRoles) + { + if(rResult.find(role) == rResult.end()) + rResult.emplace(role, OUString()); + } +} + +/** + * Insert a new data series to chart type at position after specified series + * position. + * + * @param xChartType chart type that contains data series. + * @param xSeries insertion position. The new series will be inserted after + * this one. + * @param xNewSeries new data series to insert. + */ +void addNewSeriesToContainer( + const rtl::Reference& xChartType, + const rtl::Reference& xSeries, + const rtl::Reference& xNewSeries ) +{ + auto aSeries = xChartType->getDataSeries2(); + + auto aIt = std::find( aSeries.begin(), aSeries.end(), xSeries); + + if( aIt == aSeries.end()) + // if we have no series we insert at the first position. + aIt = aSeries.begin(); + else + // vector::insert inserts before, so we have to advance + ++aIt; + + aSeries.insert(aIt, xNewSeries); + xChartType->setDataSeries(aSeries); +} + +} + +DialogModel::tRolesWithRanges DialogModel::getRolesWithRanges( + const Reference< XDataSeries > & xSeries, + const OUString & aRoleOfSequenceForLabel, + const rtl::Reference< ::chart::ChartType > & xChartType ) +{ + DialogModel::tRolesWithRanges aResult; + try + { + Reference< data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW ); + const Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + std::copy( aSeq.begin(), aSeq.end(), + lcl_RolesWithRangeAppend( &aResult, aRoleOfSequenceForLabel )); + if( xChartType.is()) + { + // add missing mandatory roles + Sequence< OUString > aRoles( xChartType->getSupportedMandatoryRoles()); + addMissingRoles(aResult, aRoles); + + // add missing optional roles + aRoles = xChartType->getSupportedOptionalRoles(); + addMissingRoles(aResult, aRoles); + + // add missing property roles + aRoles = xChartType->getSupportedPropertyRoles(); + addMissingRoles(aResult, aRoles); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aResult; +} + +void DialogModel::moveSeries( + const Reference< XDataSeries > & xSeries, + MoveDirection eDirection ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + DiagramHelper::moveSeries( xDiagram, xSeries, eDirection==MoveDirection::Down ); +} + +rtl::Reference< ::chart::DataSeries > DialogModel::insertSeriesAfter( + const Reference< XDataSeries > & xUnoSeries, + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bCreateDataCachedSequences /* = false */ ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + rtl::Reference< ::chart::DataSeries > xNewSeries; + rtl::Reference xSeries = dynamic_cast(xUnoSeries.get()); + assert(xSeries || !xUnoSeries); + + try + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + + sal_Int32 nSeriesInChartType = 0; + const sal_Int32 nTotalSeries = countSeries(); + if( xChartType.is()) + { + nSeriesInChartType = xChartType->getDataSeries().getLength(); + } + + // create new series + xNewSeries = + lcl_CreateNewSeries( + xChartType, + nTotalSeries, // new series' index + nSeriesInChartType, + xDiagram, + m_xTemplate, + bCreateDataCachedSequences ); + + // add new series to container + if( xNewSeries.is()) + addNewSeriesToContainer(xChartType, xSeries, xNewSeries); + + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xNewSeries; +} + +void DialogModel::deleteSeries( + const Reference< XDataSeries > & xSeries, + const rtl::Reference< ChartType > & xChartType ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + DataSeriesHelper::deleteSeries( xSeries, xChartType ); +} + +uno::Reference< chart2::data::XLabeledDataSequence > DialogModel::getCategories() const +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + try + { + if( m_xChartDocument.is()) + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + xResult = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xResult; +} + +void DialogModel::setCategories( const Reference< chart2::data::XLabeledDataSequence > & xCategories ) +{ + if( !m_xChartDocument.is()) + return; + + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + if( !xDiagram.is()) + return; + + // categories + bool bSupportsCategories = true; + + rtl::Reference< ChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + if( xFirstChartType.is() ) + { + sal_Int32 nAxisType = ChartTypeHelper::getAxisType( xFirstChartType, 0 ); // x-axis + bSupportsCategories = (nAxisType == AxisType::CATEGORY); + } + DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram, true, bSupportsCategories ); +} + +OUString DialogModel::getCategoriesRange() const +{ + uno::Reference< chart2::data::XLabeledDataSequence > xLSeq( getCategories()); + OUString aRange; + if( xLSeq.is()) + { + Reference< data::XDataSequence > xSeq( xLSeq->getValues()); + if( xSeq.is()) + aRange = xSeq->getSourceRangeRepresentation(); + } + return aRange; +} + +bool DialogModel::isCategoryDiagram() const +{ + bool bRet = false; + if( m_xChartDocument.is()) + bRet = DiagramHelper::isCategoryDiagram( m_xChartDocument->getFirstChartDiagram() ); + return bRet; +} + +void DialogModel::detectArguments( + OUString & rOutRangeString, + bool & rOutUseColumns, + bool & rOutFirstCellAsLabel, + bool & rOutHasCategories ) const +{ + try + { + uno::Sequence< sal_Int32 > aSequenceMapping;//todo YYYX + + // Note: unused data is currently not supported in being passed to detectRangeSegmentation + if( m_xChartDocument.is()) + { + (void)DataSourceHelper::detectRangeSegmentation( + m_xChartDocument, + rOutRangeString, aSequenceMapping, rOutUseColumns, rOutFirstCellAsLabel, rOutHasCategories ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool DialogModel::allArgumentsForRectRangeDetected() const +{ + return DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument ); +} + +void DialogModel::startControllerLockTimer() +{ + m_aTimerTriggeredControllerLock.startTimer(); +} + +void DialogModel::setData( + const Sequence< beans::PropertyValue > & rArguments ) +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aLockedControllers( m_xChartDocument ); + + Reference< data::XDataProvider > xDataProvider( getDataProvider()); + if( ! xDataProvider.is() || + ! m_xTemplate.is() ) + { + OSL_FAIL( "Model objects missing" ); + return; + } + + try + { + Reference< chart2::data::XDataSource > xDataSource( + xDataProvider->createDataSource( rArguments ) ); + + rtl::Reference< ::chart::DataInterpreter > xInterpreter( + m_xTemplate->getDataInterpreter2()); + if( xInterpreter.is()) + { + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram() ); + ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram ); + + std::vector< rtl::Reference< DataSeries > > aSeriesToReUse = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + applyInterpretedData( + xInterpreter->interpretDataSource( + xDataSource, rArguments, + aSeriesToReUse ), + aSeriesToReUse); + + ThreeDHelper::setScheme( xDiagram, e3DScheme ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void DialogModel::setTimeBasedRange( bool bTimeBased, sal_Int32 nStart, sal_Int32 nEnd) const +{ + maTimeBasedInfo.nStart = nStart; + maTimeBasedInfo.nEnd = nEnd; + maTimeBasedInfo.bTimeBased = bTimeBased; +} + +OUString DialogModel::ConvertRoleFromInternalToUI( const OUString & rRoleString ) +{ + return lcl_ConvertRole( rRoleString ); +} + +OUString DialogModel::GetRoleDataLabel() +{ + return ::chart::SchResId(STR_OBJECT_DATALABELS); +} + +sal_Int32 DialogModel::GetRoleIndexForSorting( const OUString & rInternalRoleString ) +{ + static lcl_tRoleIndexMap aRoleIndexMap = lcl_createRoleIndexMap(); + + lcl_tRoleIndexMap::const_iterator aIt( aRoleIndexMap.find( rInternalRoleString )); + if( aIt != aRoleIndexMap.end()) + return aIt->second; + + return 0; +} + +// private methods + +void DialogModel::applyInterpretedData( + const InterpretedData & rNewData, + const std::vector< rtl::Reference< DataSeries > > & rSeriesToReUse ) +{ + if( ! m_xChartDocument.is()) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + rtl::Reference< Diagram > xDiagram( m_xChartDocument->getFirstChartDiagram()); + if( !xDiagram.is()) + return; + + // styles + if( m_xTemplate.is() ) + { + sal_Int32 nGroup = 0; + sal_Int32 nSeriesCounter = 0; + sal_Int32 nNewSeriesIndex = static_cast< sal_Int32 >( rSeriesToReUse.size()); + const sal_Int32 nOuterSize=rNewData.Series.size(); + + for(; nGroup < nOuterSize; ++nGroup) + { + const std::vector< rtl::Reference< DataSeries > > & aSeries( rNewData.Series[ nGroup ] ); + const sal_Int32 nSeriesInGroup = aSeries.size(); + for( sal_Int32 nSeries=0; nSeries xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is()) + aSeries[nSeries]->setPropertyValue( "Color" , + uno::Any( xColorScheme->getColorByIndex( nSeriesCounter ))); + } + m_xTemplate->applyStyle2( aSeries[nSeries], nGroup, nNewSeriesIndex++, nSeriesInGroup ); + } + } + } + } + + // data series + std::vector< rtl::Reference< ChartType > > aSeriesCnt = getAllDataSeriesContainers(); + + OSL_ASSERT( aSeriesCnt.size() == rNewData.Series.size()); + + auto aSrcIt = rNewData.Series.begin(); + auto aDestIt = aSeriesCnt.begin(); + for(; aSrcIt != rNewData.Series.end() && aDestIt != aSeriesCnt.end(); + ++aSrcIt, ++aDestIt ) + { + try + { + OSL_ASSERT( (*aDestIt).is()); + (*aDestIt)->setDataSeries( *aSrcIt ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + DialogModel::setCategories(rNewData.Categories); +} + +sal_Int32 DialogModel::countSeries() const +{ + std::vector< rtl::Reference< ChartType > > aCnt( getAllDataSeriesContainers()); + return std::accumulate( aCnt.begin(), aCnt.end(), 0, lcl_addSeriesNumber()); +} + +ChartModel& DialogModel::getModel() const +{ + return *m_xChartDocument; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/DialogModel.hxx b/chart2/source/controller/dialogs/DialogModel.hxx new file mode 100644 index 000000000..2f8e1c1fb --- /dev/null +++ b/chart2/source/controller/dialogs/DialogModel.hxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { template class Sequence; } + +namespace com::sun::star::chart2 { + class XDataSeriesContainer; + class XDataSeries; + class XChartType; + namespace data { + class XDataProvider; + class XLabeledDataSequence; + } +} + +namespace chart +{ +class ChartType; +class ChartTypeTemplate; +class DataSeries; +struct InterpretedData; +class LabeledDataSequence; +class RangeSelectionHelper; + +struct DialogModelTimeBasedInfo +{ + DialogModelTimeBasedInfo(); + + bool bTimeBased; + sal_Int32 nStart; + sal_Int32 nEnd; +}; + +class DialogModel +{ +public: + explicit DialogModel( const rtl::Reference<::chart::ChartModel> & xChartDocument ); + ~DialogModel(); + + typedef std::pair< + OUString, + std::pair< rtl::Reference< ::chart::DataSeries >, + rtl::Reference< ::chart::ChartType > > > + tSeriesWithChartTypeByName; + + typedef std::map< OUString, OUString > + tRolesWithRanges; + + void setTemplate( + const rtl::Reference< ::chart::ChartTypeTemplate > & xTemplate ); + + std::shared_ptr< RangeSelectionHelper > const & + getRangeSelectionHelper() const; + + const rtl::Reference<::chart::ChartModel> & + getChartModel() const; + + css::uno::Reference< css::chart2::data::XDataProvider > + getDataProvider() const; + + std::vector< rtl::Reference< ::chart::ChartType > > + getAllDataSeriesContainers() const; + + std::vector< tSeriesWithChartTypeByName > + getAllDataSeriesWithLabel() const; + + static tRolesWithRanges getRolesWithRanges( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const OUString & aRoleOfSequenceForLabel, + const rtl::Reference< ::chart::ChartType > & xChartType ); + + enum class MoveDirection + { + Down, Up + }; + + void moveSeries( const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + MoveDirection eDirection ); + + /// @return the newly inserted series + rtl::Reference< + ::chart::DataSeries > insertSeriesAfter( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType, + bool bCreateDataCachedSequences = false ); + + void deleteSeries( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType ); + + css::uno::Reference< css::chart2::data::XLabeledDataSequence > + getCategories() const; + + void setCategories( const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xCategories ); + + OUString getCategoriesRange() const; + + bool isCategoryDiagram() const; + + void detectArguments( + OUString & rOutRangeString, + bool & rOutUseColumns, bool & rOutFirstCellAsLabel, bool & rOutHasCategories ) const; + + bool allArgumentsForRectRangeDetected() const; + + void setData( const css::uno::Sequence< css::beans::PropertyValue > & rArguments ); + + void setTimeBasedRange( bool bTimeBased, sal_Int32 nStart, sal_Int32 nEnd) const; + + const DialogModelTimeBasedInfo& getTimeBasedInfo() const { return maTimeBasedInfo; } + + void startControllerLockTimer(); + + static OUString ConvertRoleFromInternalToUI( const OUString & rRoleString ); + static OUString GetRoleDataLabel(); + + // pass a role string (not translated) and get an index that serves for + // relative ordering, to get e.g. x-values and y-values in the right order + static sal_Int32 GetRoleIndexForSorting( const OUString & rInternalRoleString ); + + ChartModel& getModel() const; + +private: + rtl::Reference<::chart::ChartModel> + m_xChartDocument; + + rtl::Reference< ::chart::ChartTypeTemplate > m_xTemplate; + + mutable std::shared_ptr< RangeSelectionHelper > + m_spRangeSelectionHelper; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + +private: + void applyInterpretedData( + const InterpretedData & rNewData, + const std::vector< rtl::Reference< ::chart::DataSeries > > & rSeriesToReUse ); + + sal_Int32 countSeries() const; + + mutable DialogModelTimeBasedInfo maTimeBasedInfo; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/ObjectNameProvider.cxx b/chart2/source/controller/dialogs/ObjectNameProvider.cxx new file mode 100644 index 000000000..07b7f3503 --- /dev/null +++ b/chart2/source/controller/dialogs/ObjectNameProvider.cxx @@ -0,0 +1,860 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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; + +namespace +{ + +OUString lcl_getDataSeriesName( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel ); + if( xDiagram.is() && xSeries.is() ) + { + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( xChartType.is() ) + { + aRet = ::chart::DataSeriesHelper::getDataSeriesLabel( + xSeries, xChartType->getRoleOfSequenceForSeriesLabel() ) ; + } + } + + return aRet; +} + +OUString lcl_getFullSeriesName( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet(SchResId(STR_TIP_DATASERIES)); + OUString aWildcard( "%SERIESNAME" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataSeriesName( rObjectCID, xChartModel ) ); + return aRet; +} + +void lcl_addText( OUString& rOut, std::u16string_view rSeparator, std::u16string_view rNext ) +{ + if( !(rOut.isEmpty() || rNext.empty()) ) + rOut+=rSeparator; + if( !rNext.empty() ) + rOut+=rNext; +} + +OUString lcl_getDataPointValueText( const rtl::Reference< DataSeries >& xSeries, sal_Int32 nPointIndex, + const rtl::Reference< BaseCoordinateSystem >& xCooSys, + const Reference< frame::XModel >& xChartModel ) +{ + + OUString aRet; + + if(!xSeries.is()) + return aRet; + + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSequences = xSeries->getDataSequences2(); + + OUString aX, aY, aY_Min, aY_Max, aY_First, aY_Last, a_Size; + double fValue = 0; + + uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( xChartModel, uno::UNO_QUERY ); + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + Color nLabelColor;//dummy + bool bColorChanged;//dummy + + for(sal_Int32 nN = aDataSequences.size();nN--;) + { + uno::Reference xDataSequence( aDataSequences[nN]->getValues()); + if( !xDataSequence.is() ) + continue; + Sequence< Any > aData( xDataSequence->getData() ); + if( nPointIndex >= aData.getLength() ) + continue; + uno::Reference xProp(xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + uno::Any aARole = xProp->getPropertyValue( "Role" ); + OUString aRole; + aARole >>= aRole; + + if( aRole == "values-x" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aX = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-y") + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-first" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_First = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-min" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Min = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-max" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Max = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-last" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + aY_Last = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + else if( aRole == "values-size" ) + { + aData[nPointIndex]>>= fValue; + sal_Int32 nNumberFormatKey = xDataSequence->getNumberFormatKeyByIndex( nPointIndex ); + a_Size = aNumberFormatterWrapper.getFormattedString( nNumberFormatKey, fValue, nLabelColor, bColorChanged ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + + if( aX.isEmpty() ) + { + ChartModel& rModel = dynamic_cast(*xChartModel); + aRet = ExplicitCategoriesProvider::getCategoryByIndex( xCooSys, rModel, nPointIndex ); + } + else + { + aRet = aX; + } + + OUString aSeparator( " " ); + + lcl_addText( aRet, aSeparator, aY ); + lcl_addText( aRet, aSeparator, aY_First ); + lcl_addText( aRet, aSeparator, aY_Min ); + lcl_addText( aRet, aSeparator, aY_Max ); + lcl_addText( aRet, aSeparator, aY_Last ); + lcl_addText( aRet, aSeparator, a_Size ); + + return aRet; +} + +} //end anonymous namespace + +OUString ObjectNameProvider::getName( ObjectType eObjectType, bool bPlural ) +{ + OUString aRet; + switch( eObjectType ) + { + case OBJECTTYPE_PAGE: + aRet=SchResId(STR_OBJECT_PAGE); + break; + case OBJECTTYPE_TITLE: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_TITLES); + else + aRet=SchResId(STR_OBJECT_TITLE); + } + break; + case OBJECTTYPE_LEGEND: + aRet=SchResId(STR_OBJECT_LEGEND); + break; + case OBJECTTYPE_LEGEND_ENTRY: + aRet=SchResId(STR_OBJECT_LEGEND_SYMBOL);//@todo change string if we do differentiate symbol and legend entry in future + break; + case OBJECTTYPE_DIAGRAM: + aRet=SchResId(STR_OBJECT_DIAGRAM); + break; + case OBJECTTYPE_DIAGRAM_WALL: + aRet=SchResId(STR_OBJECT_DIAGRAM_WALL); + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + aRet=SchResId(STR_OBJECT_DIAGRAM_FLOOR); + break; + case OBJECTTYPE_AXIS: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_AXES); + else + aRet=SchResId(STR_OBJECT_AXIS); + } + break; + case OBJECTTYPE_AXIS_UNITLABEL: + aRet=SchResId(STR_OBJECT_LABEL);//@todo maybe a more concrete name + break; + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: //maybe todo: different names for subgrids + { + if(bPlural) + aRet=SchResId(STR_OBJECT_GRIDS); + else + aRet=SchResId(STR_OBJECT_GRID); + } + break; + case OBJECTTYPE_DATA_SERIES: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_DATASERIES_PLURAL); + else + aRet=SchResId(STR_OBJECT_DATASERIES); + } + break; + case OBJECTTYPE_DATA_POINT: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_DATAPOINTS); + else + aRet=SchResId(STR_OBJECT_DATAPOINT); + } + break; + case OBJECTTYPE_DATA_LABELS: + aRet=SchResId(STR_OBJECT_DATALABELS); + break; + case OBJECTTYPE_DATA_LABEL: + aRet=SchResId(STR_OBJECT_LABEL); + break; + case OBJECTTYPE_DATA_ERRORS_X: + aRet=SchResId(STR_OBJECT_ERROR_BARS_X); + break; + case OBJECTTYPE_DATA_ERRORS_Y: + aRet=SchResId(STR_OBJECT_ERROR_BARS_Y); + break; + case OBJECTTYPE_DATA_ERRORS_Z: + aRet=SchResId(STR_OBJECT_ERROR_BARS_Z); + break; + case OBJECTTYPE_DATA_AVERAGE_LINE: + aRet=SchResId(STR_OBJECT_AVERAGE_LINE); + break; + case OBJECTTYPE_DATA_CURVE: + { + if(bPlural) + aRet=SchResId(STR_OBJECT_CURVES); + else + aRet=SchResId(STR_OBJECT_CURVE); + } + break; + case OBJECTTYPE_DATA_STOCK_RANGE: + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + aRet=SchResId(STR_OBJECT_STOCK_LOSS); + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + aRet=SchResId(STR_OBJECT_STOCK_GAIN); + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + aRet=SchResId(STR_OBJECT_CURVE_EQUATION); + break; + default: //OBJECTTYPE_UNKNOWN + ; + } + return aRet; +} + +OUString ObjectNameProvider::getAxisName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + Reference< XAxis > xAxis( + ObjectIdentifier::getObjectPropertySet( rObjectCID , xChartModel ), uno::UNO_QUERY ); + + sal_Int32 nCooSysIndex = 0; + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ), nCooSysIndex, nDimensionIndex, nAxisIndex ); + + switch(nDimensionIndex) + { + case 0://x-axis + if( nAxisIndex == 0 ) + aRet=SchResId(STR_OBJECT_AXIS_X); + else + aRet=SchResId(STR_OBJECT_SECONDARY_X_AXIS); + break; + case 1://y-axis + if( nAxisIndex == 0 ) + aRet=SchResId(STR_OBJECT_AXIS_Y); + else + aRet=SchResId(STR_OBJECT_SECONDARY_Y_AXIS); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_AXIS_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_AXIS); + break; + } + + return aRet; +} + +OUString ObjectNameProvider::getTitleNameByType( TitleHelper::eTitleType eType ) +{ + OUString aRet; + + switch(eType) + { + case TitleHelper::MAIN_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_MAIN); + break; + case TitleHelper::SUB_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SUB); + break; + case TitleHelper::X_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_X_AXIS); + break; + case TitleHelper::Y_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_Y_AXIS); + break; + case TitleHelper::Z_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_Z_AXIS); + break; + case TitleHelper::SECONDARY_X_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SECONDARY_X_AXIS); + break; + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + aRet=SchResId(STR_OBJECT_TITLE_SECONDARY_Y_AXIS); + break; + default: + OSL_FAIL("unknown title type"); + break; + } + + if( aRet.isEmpty() ) + aRet=SchResId(STR_OBJECT_TITLE); + + return aRet; +} + +OUString ObjectNameProvider::getTitleName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + Reference< XTitle > xTitle( + ObjectIdentifier::getObjectPropertySet( rObjectCID , xChartModel ), uno::UNO_QUERY ); + if( xTitle.is() ) + { + TitleHelper::eTitleType eType; + if( TitleHelper::getTitleType( eType, xTitle, xChartModel ) ) + aRet = ObjectNameProvider::getTitleNameByType( eType ); + } + if( aRet.isEmpty() ) + aRet=SchResId(STR_OBJECT_TITLE); + + return aRet; +} + +OUString ObjectNameProvider::getGridName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + sal_Int32 nCooSysIndex = -1; + sal_Int32 nDimensionIndex = -1; + sal_Int32 nAxisIndex = -1; + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rObjectCID , xChartModel ); + AxisHelper::getIndicesForAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) + , nCooSysIndex , nDimensionIndex, nAxisIndex ); + + bool bMainGrid = (ObjectIdentifier::getObjectType( rObjectCID ) == OBJECTTYPE_GRID); + + if( bMainGrid ) + { + switch(nDimensionIndex) + { + case 0://x-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_X); + break; + case 1://y-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_Y); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_GRID_MAJOR_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_GRID); + break; + } + } + else + { + switch(nDimensionIndex) + { + case 0://x-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_X); + break; + case 1://y-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_Y); + break; + case 2://z-axis + aRet=SchResId(STR_OBJECT_GRID_MINOR_Z); + break; + default://axis + aRet=SchResId(STR_OBJECT_GRID); + break; + } + } + return aRet; +} + +OUString ObjectNameProvider::getHelpText( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, bool bVerbose ) +{ + OUString aRet; + ObjectType eObjectType( ObjectIdentifier::getObjectType(rObjectCID) ); + if( eObjectType == OBJECTTYPE_AXIS ) + { + aRet=ObjectNameProvider::getAxisName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_GRID + || eObjectType == OBJECTTYPE_SUBGRID ) + { + aRet=ObjectNameProvider::getGridName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_TITLE ) + { + aRet=ObjectNameProvider::getTitleName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_DATA_SERIES ) + { + aRet = lcl_getFullSeriesName( rObjectCID, xChartModel ); + } + else if( eObjectType == OBJECTTYPE_DATA_POINT ) + { + if( bVerbose ) + { + aRet= SchResId(STR_TIP_DATAPOINT_INDEX) + "\n" + + SchResId(STR_TIP_DATASERIES) + "\n" + + SchResId(STR_TIP_DATAPOINT_VALUES); + } + else + aRet=SchResId(STR_TIP_DATAPOINT); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel ); + if( xDiagram.is() && xSeries.is() ) + { + sal_Int32 nPointIndex = o3tl::toInt32(ObjectIdentifier::getParticleID(rObjectCID)); + + //replace data point index + OUString aWildcard( "%POINTNUMBER" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), OUString::number(nPointIndex+1) ); + } + + //replace data series index + aWildcard = "%SERIESNUMBER"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 nSeriesIndex = -1; + for( nSeriesIndex=aSeriesVector.size();nSeriesIndex--;) + { + if( aSeriesVector[nSeriesIndex] == xSeries ) + { + break; + } + } + + OUString aReplacement( OUString::number(nSeriesIndex+1) ); + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), aReplacement ); + } + + //replace point values + aWildcard = "%POINTVALUES"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataPointValueText( + xSeries,nPointIndex, DataSeriesHelper::getCoordinateSystemOfSeries(xSeries, xDiagram), xChartModel ) ); + + //replace series name + aWildcard = "%SERIESNAME"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), lcl_getDataSeriesName( rObjectCID, xChartModel ) ); + } + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE ) + { + if( bVerbose ) + { + aRet = SchResId( STR_OBJECT_CURVE_WITH_PARAMETERS ); + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel )); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve = RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex); + if( xCurve.is()) + { + try + { + Reference< chart2::XRegressionCurveCalculator > xCalculator( xCurve->getCalculator(), uno::UNO_SET_THROW ); + sal_Int32 aDegree = 2; + sal_Int32 aPeriod = 2; + sal_Int32 aMovingType = css::chart2::MovingAverageType::Prior; + bool bForceIntercept = false; + double aInterceptValue = 0.0; + OUString aXName ("x"), aYName ("f(x)"); + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + sal_Unicode cDecSeparator = aNumDecimalSep[0]; + + xCurve->getPropertyValue( "PolynomialDegree") >>= aDegree; + xCurve->getPropertyValue( "MovingAveragePeriod") >>= aPeriod; + xCurve->getPropertyValue( "MovingAverageType") >>= aMovingType; + xCurve->getPropertyValue( "ForceIntercept") >>= bForceIntercept; + if (bForceIntercept) + xCurve->getPropertyValue( "InterceptValue") >>= aInterceptValue; + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + if( xEqProp.is()) + { + if ( !(xEqProp->getPropertyValue( "XName") >>= aXName) ) + aXName = "x"; + if ( !(xEqProp->getPropertyValue( "YName") >>= aYName) ) + aYName = "f(x)"; + } + xCalculator->setRegressionProperties(aDegree, bForceIntercept, aInterceptValue, 2, aMovingType); + xCalculator->setXYNames ( aXName, aYName ); + RegressionCurveHelper::initializeCurveCalculator( xCalculator, xSeries, xChartModel ); + + // change text for Moving Average + OUString aWildcard( "%PERIOD" ); + sal_Int32 nIndex = xCalculator->getRepresentation().indexOf( aWildcard ); + if( nIndex != -1 ) + { // replace period + aRet = xCalculator->getRepresentation(); + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), OUString::number(aPeriod) ); + } + + // replace formula + aWildcard = "%FORMULA"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + OUString aFormula ( xCalculator->getRepresentation() ); + if ( cDecSeparator != '.' ) + { + aFormula = aFormula.replace( '.', cDecSeparator ); + } + aRet = aRet.replaceAt( nIndex, aWildcard.getLength(), aFormula ); + } + + // replace r^2 + aWildcard = "%RSQUARED"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + double fR( xCalculator->getCorrelationCoefficient()); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fR*fR, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + else + { + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID(rObjectCID , xChartModel)); + aRet += getName(eObjectType); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex) ); + if( xCurve.is()) + { + aRet += " (" + RegressionCurveHelper::getRegressionCurveName(xCurve) + " )"; + } + } + } + } + else if( eObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + { + if( bVerbose ) + { + aRet = SchResId(STR_OBJECT_AVERAGE_LINE_WITH_PARAMETERS); + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartModel )); + if( xSeries.is()) + { + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getMeanValueLine( xSeries )); + if( xCurve.is()) + { + try + { + Reference< chart2::XRegressionCurveCalculator > xCalculator( xCurve->getCalculator(), uno::UNO_SET_THROW ); + RegressionCurveHelper::initializeCurveCalculator( xCalculator, xSeries, xChartModel ); + + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + sal_Unicode cDecSeparator = aNumDecimalSep[0]; + + OUString aWildcard( "%AVERAGE_VALUE" ); + sal_Int32 nIndex = aRet.indexOf( aWildcard ); + // as the curve is constant, the value at any x-value is ok + if( nIndex != -1 ) + { + const double fMeanValue( xCalculator->getCurveValue( 0.0 )); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fMeanValue, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + + // replace standard deviation + aWildcard = "%STD_DEVIATION"; + nIndex = aRet.indexOf( aWildcard ); + if( nIndex != -1 ) + { + const double fStdDev( xCalculator->getCorrelationCoefficient()); + aRet = aRet.replaceAt( + nIndex, aWildcard.getLength(), + ::rtl::math::doubleToUString( + fStdDev, rtl_math_StringFormat_G, 4, cDecSeparator, true )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + else + { + // non-verbose + aRet = ObjectNameProvider::getName( eObjectType ); + } + } + else + { + aRet = ObjectNameProvider::getName( eObjectType ); + } + return aRet; +} + +OUString ObjectNameProvider::getSelectedObjectText( const OUString & rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + OUString aRet; + ObjectType eObjectType( ObjectIdentifier::getObjectType(rObjectCID) ); + + if( eObjectType == OBJECTTYPE_DATA_POINT ) + { + aRet = SchResId( STR_STATUS_DATAPOINT_MARKED ); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartDocument ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartDocument ); + if( xDiagram.is() && xSeries.is() ) + { + sal_Int32 nPointIndex = o3tl::toInt32( ObjectIdentifier::getParticleID(rObjectCID) ); + + // replace data point index + replaceParamterInString( aRet, "%POINTNUMBER", OUString::number( nPointIndex + 1 )); + + // replace data series index + { + std::vector< rtl::Reference< DataSeries > > aSeriesVector( + DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); + sal_Int32 nSeriesIndex = -1; + for( nSeriesIndex=aSeriesVector.size();nSeriesIndex--;) + { + if( aSeriesVector[nSeriesIndex] == xSeries ) + break; + } + replaceParamterInString( aRet, "%SERIESNUMBER", OUString::number( nSeriesIndex + 1 ) ); + } + + // replace point value + replaceParamterInString( aRet, "%POINTVALUES", lcl_getDataPointValueText( + xSeries, nPointIndex, DataSeriesHelper::getCoordinateSystemOfSeries(xSeries, xDiagram), xChartDocument ) ); + } + } + else + { + // use the verbose text including the formula for trend lines + const bool bVerbose( eObjectType == OBJECTTYPE_DATA_CURVE || eObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ); + const OUString aHelpText( getHelpText( rObjectCID, xChartDocument, bVerbose )); + if( !aHelpText.isEmpty()) + { + aRet = SchResId( STR_STATUS_OBJECT_MARKED ); + replaceParamterInString( aRet, "%OBJECTNAME", aHelpText ); + } + } + + return aRet; +} + +OUString ObjectNameProvider::getNameForCID( + const OUString& rObjectCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + ObjectType eType( ObjectIdentifier::getObjectType( rObjectCID )); + + switch( eType ) + { + case OBJECTTYPE_AXIS: + return getAxisName( rObjectCID, xChartDocument ); + case OBJECTTYPE_TITLE: + return getTitleName( rObjectCID, xChartDocument ); + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + return getGridName( rObjectCID, xChartDocument ); + case OBJECTTYPE_DATA_SERIES: + return lcl_getFullSeriesName( rObjectCID, xChartDocument ); + case OBJECTTYPE_DATA_POINT: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + OUString aRet = lcl_getFullSeriesName( rObjectCID, xChartDocument ) + " "; + if( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL ) + { + aRet += getName( OBJECTTYPE_DATA_POINT ); + sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + aRet += " " + OUString::number(nPointIndex+1); + if( eType == OBJECTTYPE_DATA_LABEL ) + { + aRet += " " + getName( OBJECTTYPE_DATA_LABEL ); + } + } + else if (eType == OBJECTTYPE_DATA_CURVE || eType == OBJECTTYPE_DATA_CURVE_EQUATION) + { + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( rObjectCID , xChartDocument )); + + aRet += " " + getName(eType); + + if( xSeries.is()) + { + sal_Int32 nCurveIndex = ObjectIdentifier::getIndexFromParticleOrCID( rObjectCID ); + rtl::Reference< RegressionCurveModel > xCurve( RegressionCurveHelper::getRegressionCurveAtIndex(xSeries, nCurveIndex) ); + if( xCurve.is()) + { + aRet += " (" + RegressionCurveHelper::getRegressionCurveName(xCurve) + ")"; + } + } + } + else + { + aRet += getName( eType ); + } + return aRet; + } + default: + break; + } + + return getName( eType ); +} + +OUString ObjectNameProvider::getName_ObjectForSeries( + ObjectType eObjectType, + const OUString& rSeriesCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSeriesCID , xChartDocument ); + if( xSeries.is() ) + { + OUString aRet = SchResId(STR_OBJECT_FOR_SERIES); + replaceParamterInString( aRet, "%OBJECTNAME", getName( eObjectType ) ); + replaceParamterInString( aRet, "%SERIESNAME", lcl_getDataSeriesName( rSeriesCID, xChartDocument ) ); + return aRet; + } + else + return ObjectNameProvider::getName_ObjectForAllSeries( eObjectType ); +} + +OUString ObjectNameProvider::getName_ObjectForAllSeries( ObjectType eObjectType ) +{ + OUString aRet = SchResId(STR_OBJECT_FOR_ALL_SERIES); + replaceParamterInString( aRet, "%OBJECTNAME", getName( eObjectType, true /*bPlural*/ ) ); + return aRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/RangeSelectionHelper.cxx b/chart2/source/controller/dialogs/RangeSelectionHelper.cxx new file mode 100644 index 000000000..ede420f07 --- /dev/null +++ b/chart2/source/controller/dialogs/RangeSelectionHelper.cxx @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +RangeSelectionHelper::RangeSelectionHelper( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + m_xChartDocument( xChartDocument ) +{} + +RangeSelectionHelper::~RangeSelectionHelper() +{} + +bool RangeSelectionHelper::hasRangeSelection() +{ + return getRangeSelection().is(); +} + +Reference< sheet::XRangeSelection > const & RangeSelectionHelper::getRangeSelection() +{ + if( !m_xRangeSelection.is() && + m_xChartDocument.is() ) + { + try + { + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( xDataProvider.is()) + m_xRangeSelection.set( xDataProvider->getRangeSelection()); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + + m_xRangeSelection.clear(); + } + } + + return m_xRangeSelection; +} + +void RangeSelectionHelper::raiseRangeSelectionDocument() +{ + Reference< sheet::XRangeSelection > xRangeSel( getRangeSelection()); + if( !xRangeSel.is()) + return; + + try + { + // bring document to front + Reference< frame::XController > xCtrl( xRangeSel, uno::UNO_QUERY ); + if( xCtrl.is()) + { + Reference< frame::XFrame > xFrame( xCtrl->getFrame()); + if( xFrame.is()) + { + Reference< awt::XTopWindow > xWin( xFrame->getContainerWindow(), + uno::UNO_QUERY_THROW ); + xWin->toFront(); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool RangeSelectionHelper::chooseRange( + const OUString & aCurrentRange, + const OUString & aUIString, + RangeSelectionListenerParent & rListenerParent ) +{ + ControllerLockGuardUNO aGuard( m_xChartDocument ); + + bool bResult = true; + raiseRangeSelectionDocument(); + + try + { + Reference< sheet::XRangeSelection > xRangeSel( getRangeSelection()); + if( xRangeSel.is()) + { + Sequence< beans::PropertyValue > aArgs{ + beans::PropertyValue( + "InitialValue", -1, uno::Any( aCurrentRange ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "Title", -1, + uno::Any( aUIString ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "CloseOnMouseRelease", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "MultiSelectionMode", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) + }; + if( m_xRangeSelectionListener.is() ) + stopRangeListening(); + m_xRangeSelectionListener.set( Reference< sheet::XRangeSelectionListener >( + new RangeSelectionListener( rListenerParent, aCurrentRange, m_xChartDocument ))); + + xRangeSel->addRangeSelectionListener( m_xRangeSelectionListener ); + xRangeSel->startRangeSelection( aArgs ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + bResult = false; + } + + return bResult; +} + +void RangeSelectionHelper::stopRangeListening( bool bRemoveListener /* = true */ ) +{ + if( bRemoveListener && + m_xRangeSelectionListener.is() && + m_xRangeSelection.is() ) + { + m_xRangeSelection->removeRangeSelectionListener( m_xRangeSelectionListener ); + } + + m_xRangeSelectionListener = nullptr; +} + +bool RangeSelectionHelper::verifyCellRange( const OUString & rRangeStr ) +{ + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( ! xDataProvider.is()) + return false; + + return xDataProvider->createDataSequenceByRangeRepresentationPossible( rRangeStr ); +} + +bool RangeSelectionHelper::verifyArguments( const Sequence< beans::PropertyValue > & rArguments ) +{ + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( ! xDataProvider.is()) + return false; + + return xDataProvider->createDataSourcePossible( rArguments ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/RangeSelectionListener.cxx b/chart2/source/controller/dialogs/RangeSelectionListener.cxx new file mode 100644 index 000000000..473ad909f --- /dev/null +++ b/chart2/source/controller/dialogs/RangeSelectionListener.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +RangeSelectionListener::RangeSelectionListener( + RangeSelectionListenerParent & rParent, + const OUString & rInitialRange, + const rtl::Reference<::chart::ChartModel>& xModelToLockController ) : + m_rParent( rParent ), + m_aRange( rInitialRange ), + m_aControllerLockGuard( xModelToLockController ) +{} + +RangeSelectionListener::~RangeSelectionListener() +{} + +// ____ XRangeSelectionListener ____ +void SAL_CALL RangeSelectionListener::done( const sheet::RangeSelectionEvent& aEvent ) +{ + m_aRange = aEvent.RangeDescriptor; + m_rParent.listeningFinished( m_aRange ); +} + +void SAL_CALL RangeSelectionListener::aborted( const sheet::RangeSelectionEvent& /*aEvent*/ ) +{ + m_rParent.listeningFinished( m_aRange ); +} + +// ____ XEventListener ____ +void SAL_CALL RangeSelectionListener::disposing( const lang::EventObject& /*Source*/ ) +{ + m_rParent.disposingRangeSelection(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TextDirectionListBox.cxx b/chart2/source/controller/dialogs/TextDirectionListBox.cxx new file mode 100644 index 000000000..68181fdfc --- /dev/null +++ b/chart2/source/controller/dialogs/TextDirectionListBox.cxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +TextDirectionListBox::TextDirectionListBox(std::unique_ptr pControl) + : svx::FrameDirectionListBox(std::move(pControl)) +{ + append(SvxFrameDirection::Horizontal_LR_TB, SchResId(STR_TEXT_DIRECTION_LTR)); + append(SvxFrameDirection::Horizontal_RL_TB, SchResId(STR_TEXT_DIRECTION_RTL)); + append(SvxFrameDirection::Environment, SchResId(STR_TEXT_DIRECTION_SUPER)); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx b/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx new file mode 100644 index 000000000..89dbc3aca --- /dev/null +++ b/chart2/source/controller/dialogs/TimerTriggeredControllerLock.cxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +TimerTriggeredControllerLock::TimerTriggeredControllerLock( + const rtl::Reference<::chart::ChartModel>& xModel) + : m_xModel(xModel) + , m_aTimer("chart2 TimerTriggeredControllerLock") +{ + m_aTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT); + m_aTimer.SetInvokeHandler(LINK(this, TimerTriggeredControllerLock, TimerTimeout)); +} +TimerTriggeredControllerLock::~TimerTriggeredControllerLock() { m_aTimer.Stop(); } + +void TimerTriggeredControllerLock::startTimer() +{ + if (!m_apControllerLockGuard) + m_apControllerLockGuard.reset(new ControllerLockGuardUNO(m_xModel)); + m_aTimer.Start(); +} +IMPL_LINK_NOARG(TimerTriggeredControllerLock, TimerTimeout, Timer*, void) +{ + m_apControllerLockGuard.reset(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/TitleDialogData.cxx b/chart2/source/controller/dialogs/TitleDialogData.cxx new file mode 100644 index 000000000..2a8b74465 --- /dev/null +++ b/chart2/source/controller/dialogs/TitleDialogData.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +TitleDialogData::TitleDialogData( std::unique_ptr pRefSizeProvider ) + : aPossibilityList{ true, true, true, true, true, true, true } + , aExistenceList{ false, false, false, false, false, false, false } + , aTextList(7) + , apReferenceSizeProvider( std::move(pRefSizeProvider) ) +{ +} + +void TitleDialogData::readFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(xChartModel); + + //get possibilities + uno::Sequence< sal_Bool > aAxisPossibilityList; + AxisHelper::getAxisOrGridPossibilities( aAxisPossibilityList, xDiagram ); + sal_Bool* pPossibilityList = aPossibilityList.getArray(); + pPossibilityList[2]=aAxisPossibilityList[0];//x axis title + pPossibilityList[3]=aAxisPossibilityList[1];//y axis title + pPossibilityList[4]=aAxisPossibilityList[2];//z axis title + pPossibilityList[5]=aAxisPossibilityList[3];//secondary x axis title + pPossibilityList[6]=aAxisPossibilityList[4];//secondary y axis title + + sal_Bool* pExistenceList = aExistenceList.getArray(); + auto pTextList = aTextList.getArray(); + //find out which title exists and get their text + //main title: + for( auto nTitleIndex = +TitleHelper::TITLE_BEGIN; + nTitleIndex < +TitleHelper::NORMAL_TITLE_END; + nTitleIndex++) + { + uno::Reference< XTitle > xTitle = TitleHelper::getTitle( + static_cast< TitleHelper::eTitleType >( nTitleIndex ), xChartModel ); + pExistenceList[nTitleIndex] = xTitle.is(); + pTextList[nTitleIndex]=TitleHelper::getCompleteString( xTitle ); + } +} + +bool TitleDialogData::writeDifferenceToModel( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< uno::XComponentContext >& xContext + , const TitleDialogData* pOldState ) +{ + bool bChanged = false; + for( auto nN = +TitleHelper::TITLE_BEGIN; + nN < +TitleHelper::NORMAL_TITLE_END; + nN++) + { + if( !pOldState || ( pOldState->aExistenceList[nN] != aExistenceList[nN] ) ) + { + if(aExistenceList[nN]) + { + TitleHelper::createTitle( + static_cast< TitleHelper::eTitleType >( nN ), aTextList[nN], xChartModel, xContext, + apReferenceSizeProvider.get() ); + bChanged = true; + } + else + { + TitleHelper::removeTitle( static_cast< TitleHelper::eTitleType >( nN ), xChartModel ); + bChanged = true; + } + } + else if( !pOldState || ( pOldState->aTextList[nN] != aTextList[nN] ) ) + { + //change content + uno::Reference< XTitle > xTitle( + TitleHelper::getTitle( static_cast< TitleHelper::eTitleType >( nN ), xChartModel ) ); + if(xTitle.is()) + { + TitleHelper::setCompleteString( aTextList[nN], xTitle, xContext ); + bChanged = true; + } + } + } + return bChanged; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ChartType.cxx b/chart2/source/controller/dialogs/dlg_ChartType.cxx new file mode 100644 index 000000000..b62ac2215 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ChartType.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "tp_ChartType.hxx" +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeDialog::ChartTypeDialog(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel>& xChartModel) + : GenericDialogController(pParent, "modules/schart/ui/charttypedialog.ui", "ChartTypeDialog") + , m_xChartModel(xChartModel) + , m_xContentArea(m_xDialog->weld_content_area()) +{ + m_xChartTypeTabPage = std::make_unique( + m_xContentArea.get(), this, m_xChartModel, false /*don't show title description*/); + + m_xChartTypeTabPage->initializePage(); +} + +ChartTypeDialog::~ChartTypeDialog() { m_xChartTypeTabPage.reset(); } + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx b/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx new file mode 100644 index 000000000..0e95cd75c --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ChartType_UNO.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::awt { class XWindow; } + +namespace chart +{ +using namespace ::com::sun::star; +ChartTypeUnoDlg::ChartTypeUnoDlg( const uno::Reference< uno::XComponentContext >& _xContext ) + : ChartTypeUnoDlg_BASE( _xContext ) +{ +} +ChartTypeUnoDlg::~ChartTypeUnoDlg() +{ + // we do this here cause the base class' call to destroyDialog won't reach us anymore: we're within a dtor, + // so this virtual-method-call the base class does not work, we're already dead then... + if (m_xDialog) + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xDialog) + destroyDialog(); + } +} +// lang::XServiceInfo +OUString SAL_CALL ChartTypeUnoDlg::getImplementationName() +{ + return CHART_TYPE_DIALOG_SERVICE_IMPLEMENTATION_NAME; +} + +css::uno::Sequence SAL_CALL ChartTypeUnoDlg::getSupportedServiceNames() +{ + return { CHART_TYPE_DIALOG_SERVICE_NAME }; +} +uno::Sequence< sal_Int8 > SAL_CALL ChartTypeUnoDlg::getImplementationId() +{ + return css::uno::Sequence(); +} +void ChartTypeUnoDlg::implInitialize(const uno::Any& _rValue) +{ + beans::PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "ChartModel") + { + uno::Reference xInt; + aProperty.Value >>= xInt; + assert(dynamic_cast<::chart::ChartModel*>(xInt.get())); + m_xChartModel = dynamic_cast<::chart::ChartModel*>(xInt.get()); + } + else + ChartTypeUnoDlg_BASE::implInitialize(_rValue); + } + else + ChartTypeUnoDlg_BASE::implInitialize(_rValue); +} + +std::unique_ptr ChartTypeUnoDlg::createDialog(const css::uno::Reference& rParent) +{ + ChartModel* pChartModel = dynamic_cast(rParent.get()); + assert(pChartModel); + return std::make_unique(Application::GetFrameWeld(rParent), pChartModel); +} + +uno::Reference SAL_CALL ChartTypeUnoDlg::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +::cppu::IPropertyArrayHelper& ChartTypeUnoDlg::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ChartTypeUnoDlg::createArrayHelper( ) const +{ + uno::Sequence< beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartTypeDialog_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::ChartTypeUnoDlg(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_CreationWizard.cxx b/chart2/source/controller/dialogs/dlg_CreationWizard.cxx new file mode 100644 index 000000000..988386eea --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_CreationWizard.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include "tp_ChartType.hxx" +#include "tp_RangeChooser.hxx" +#include "tp_Wizard_TitlesAndObjects.hxx" +#include "tp_DataSource.hxx" +#include +#include +#include "DialogModel.hxx" + +using namespace css; + +using vcl::RoadmapWizardTypes::WizardPath; + +namespace chart +{ +#define PATH_FULL 1 +#define STATE_FIRST 0 +#define STATE_CHARTTYPE STATE_FIRST +#define STATE_SIMPLE_RANGE 1 +#define STATE_DATA_SERIES 2 +#define STATE_OBJECTS 3 +#define STATE_LAST STATE_OBJECTS + +CreationWizard::CreationWizard(weld::Window* pParent, const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference& xContext) + : vcl::RoadmapWizardMachine(pParent) + , m_xChartModel(xChartModel,uno::UNO_QUERY) + , m_xComponentContext(xContext) + , m_pTemplateProvider(nullptr) + , m_aTimerTriggeredControllerLock(xChartModel) + , m_bCanTravel(true) +{ + m_pDialogModel.reset(new DialogModel(m_xChartModel)); + defaultButton(WizardButtonFlags::FINISH); + + setTitleBase(SchResId(STR_DLG_CHART_WIZARD)); + + // tdf#134386 set m_pTemplateProvider before creating any other pages + m_pTemplateProvider = static_cast(GetOrCreatePage(STATE_CHARTTYPE)); + assert(m_pTemplateProvider && "must exist"); + m_pDialogModel->setTemplate(m_pTemplateProvider->getCurrentTemplate()); + + WizardPath aPath = { + STATE_CHARTTYPE, + STATE_SIMPLE_RANGE, + STATE_DATA_SERIES, + STATE_OBJECTS + }; + + declarePath(PATH_FULL, aPath); + + // tdf#135935 ensure help ID is set when no element is clicked in the dialog + m_xAssistant->set_help_id(HID_SCH_WIZARD_ROADMAP); + + if (!m_pDialogModel->getModel().isDataFromSpreadsheet()) + { + enableState(STATE_SIMPLE_RANGE, false); + enableState(STATE_DATA_SERIES, false); + } + + // Call ActivatePage, to create and activate the first page + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +CreationWizard::~CreationWizard() = default; + +std::unique_ptr CreationWizard::createPage(WizardState nState) +{ + std::unique_ptr xRet; + + OString sIdent(OString::number(nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch( nState ) + { + case STATE_CHARTTYPE: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique(pPageContainer, this, m_xChartModel); + break; + } + case STATE_SIMPLE_RANGE: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique(pPageContainer, this, *m_pDialogModel, m_pTemplateProvider); + break; + } + case STATE_DATA_SERIES: + { + m_aTimerTriggeredControllerLock.startTimer(); + xRet = std::make_unique(pPageContainer, this, *m_pDialogModel, m_pTemplateProvider); + break; + } + case STATE_OBJECTS: + { + xRet = std::make_unique(pPageContainer, this, m_xChartModel, m_xComponentContext); + m_aTimerTriggeredControllerLock.startTimer(); + break; + } + default: + break; + } + + if (xRet) + xRet->SetPageTitle(OUString()); //remove title of pages to not get them in the wizard title + + return xRet; +} + +bool CreationWizard::leaveState( WizardState /*_nState*/ ) +{ + return m_bCanTravel; +} + +vcl::WizardTypes::WizardState CreationWizard::determineNextState( WizardState nCurrentState ) const +{ + if( !m_bCanTravel ) + return WZS_INVALID_STATE; + if( nCurrentState == STATE_LAST ) + return WZS_INVALID_STATE; + vcl::WizardTypes::WizardState nNextState = nCurrentState + 1; + while( !isStateEnabled( nNextState ) && nNextState <= STATE_LAST ) + ++nNextState; + return (nNextState==STATE_LAST+1) ? WZS_INVALID_STATE : nNextState; +} + +void CreationWizard::enterState(WizardState nState) +{ + m_aTimerTriggeredControllerLock.startTimer(); + enableButtons( WizardButtonFlags::PREVIOUS, nState > STATE_FIRST ); + enableButtons( WizardButtonFlags::NEXT, nState < STATE_LAST ); + if( isStateEnabled( nState )) + vcl::RoadmapWizardMachine::enterState(nState); +} + +void CreationWizard::setInvalidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_pCurTabPage) + m_bCanTravel = false; +} + +void CreationWizard::setValidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_pCurTabPage) + m_bCanTravel = true; +} + +OUString CreationWizard::getStateDisplayName( WizardState nState ) const +{ + TranslateId pResId; + switch( nState ) + { + case STATE_CHARTTYPE: + pResId = STR_PAGE_CHARTTYPE; + break; + case STATE_SIMPLE_RANGE: + pResId = STR_PAGE_DATA_RANGE; + break; + case STATE_DATA_SERIES: + pResId = STR_OBJECT_DATASERIES_PLURAL; + break; + case STATE_OBJECTS: + pResId = STR_PAGE_CHART_ELEMENTS; + break; + default: + break; + } + if (!pResId) + return OUString(); + return SchResId(pResId); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx b/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx new file mode 100644 index 000000000..973b8fa74 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_CreationWizard_UNO.cxx @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +CreationWizardUnoDlg::CreationWizardUnoDlg(const uno::Reference& xContext) + : OComponentHelper(m_aMutex) + , m_xCC(xContext) + , m_bUnlockControllersOnExecute(false) +{ + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xCC); + uno::Reference< frame::XTerminateListener > xListener( this ); + xDesktop->addTerminateListener( xListener ); +} + +CreationWizardUnoDlg::~CreationWizardUnoDlg() +{ + SolarMutexGuard aSolarGuard; + m_xDialog.reset(); +} + +// lang::XServiceInfo +OUString SAL_CALL CreationWizardUnoDlg::getImplementationName() +{ + return CHART_WIZARD_DIALOG_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL CreationWizardUnoDlg::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CreationWizardUnoDlg::getSupportedServiceNames() +{ + return { CHART_WIZARD_DIALOG_SERVICE_NAME }; +} + +// XInterface +uno::Any SAL_CALL CreationWizardUnoDlg::queryInterface( const uno::Type& aType ) +{ + return OComponentHelper::queryInterface( aType ); +} +void SAL_CALL CreationWizardUnoDlg::acquire() noexcept +{ + OComponentHelper::acquire(); +} +void SAL_CALL CreationWizardUnoDlg::release() noexcept +{ + OComponentHelper::release(); +} +uno::Any SAL_CALL CreationWizardUnoDlg::queryAggregation( uno::Type const & rType ) +{ + if (rType == cppu::UnoType::get()) + { + void * p = static_cast< ui::dialogs::XAsynchronousExecutableDialog * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType::get()) + { + void * p = static_cast< lang::XServiceInfo * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType::get()) + { + void * p = static_cast< lang::XInitialization * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType::get()) + { + void * p = static_cast< frame::XTerminateListener * >( this ); + return uno::Any( &p, rType ); + } + else if (rType == cppu::UnoType::get()) + { + void * p = static_cast< beans::XPropertySet * >( this ); + return uno::Any( &p, rType ); + } + return OComponentHelper::queryAggregation( rType ); +} + +uno::Sequence< uno::Type > CreationWizardUnoDlg::getTypes() +{ + static uno::Sequence aTypeList{ cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get() }; + return aTypeList; +} + +uno::Sequence< sal_Int8 > SAL_CALL CreationWizardUnoDlg::getImplementationId() +{ + return css::uno::Sequence(); +} + +// XTerminateListener +void SAL_CALL CreationWizardUnoDlg::queryTermination( const lang::EventObject& /*Event*/ ) +{ +} + +void SAL_CALL CreationWizardUnoDlg::notifyTermination( const lang::EventObject& /*Event*/ ) +{ + // we are going down, so dispose us! + dispose(); +} + +void SAL_CALL CreationWizardUnoDlg::disposing( const lang::EventObject& /*Source*/ ) +{ + //Listener should deregister himself and release all references to the closing object. +} + +void SAL_CALL CreationWizardUnoDlg::setDialogTitle( const OUString& /*rTitle*/ ) +{ +} +void CreationWizardUnoDlg::createDialogOnDemand() +{ + SolarMutexGuard aSolarGuard; + if (m_xDialog) + return; + + if( !m_xParentWindow.is() && m_xChartModel.is() ) + { + uno::Reference< frame::XController > xController( + m_xChartModel->getCurrentController() ); + if( xController.is() ) + { + uno::Reference< frame::XFrame > xFrame( + xController->getFrame() ); + if(xFrame.is()) + m_xParentWindow = xFrame->getContainerWindow(); + } + } + uno::Reference< XComponent > xKeepAlive( this ); + if( m_xChartModel.is() ) + { + m_xDialog = std::make_shared(Application::GetFrameWeld(m_xParentWindow), m_xChartModel, m_xCC); + } +} + +IMPL_STATIC_LINK_NOARG(CreationWizardUnoDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*) +{ + return SfxViewShell::Current(); +} + +void SAL_CALL CreationWizardUnoDlg::startExecuteModal( const css::uno::Reference& xListener ) +{ + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + + if( !m_xDialog ) + return; + + m_xDialog->getDialog()->SetInstallLOKNotifierHdl( + LINK(this, CreationWizardUnoDlg, InstallLOKNotifierHdl)); + + TimerTriggeredControllerLock aTimerTriggeredControllerLock( m_xChartModel ); + if( m_bUnlockControllersOnExecute && m_xChartModel.is() ) + m_xChartModel->unlockControllers(); + + CreationWizardUnoDlg* xThat = this; + weld::DialogController::runAsync(m_xDialog, [xListener, xThat](sal_Int32 nResult){ + if( xListener.is() ) + { + ::css::uno::Reference< ::css::uno::XInterface > xSource; + // Notify UNO listener to perform correct action depending on the result + css::ui::dialogs::DialogClosedEvent aEvent( xSource, nResult ); + xListener->dialogClosed( aEvent ); + } + xThat->m_xDialog.reset(); + }); +} + +void SAL_CALL CreationWizardUnoDlg::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + for(const uno::Any& rArgument : aArguments) + { + beans::PropertyValue aProperty; + if(rArgument >>= aProperty) + { + if( aProperty.Name == "ParentWindow" ) + { + aProperty.Value >>= m_xParentWindow; + } + else if( aProperty.Name == "ChartModel" ) + { + uno::Reference xInt; + aProperty.Value >>= xInt; + m_xChartModel = dynamic_cast<::chart::ChartModel*>(xInt.get()); + assert(m_xChartModel); + } + } + } +} + +// ____ OComponentHelper ____ +/// Called in dispose method after the listeners were notified. +void SAL_CALL CreationWizardUnoDlg::disposing() +{ + m_xChartModel.clear(); + m_xParentWindow.clear(); + + SolarMutexGuard aSolarGuard; + m_xDialog.reset(); + + try + { + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xCC); + uno::Reference< frame::XTerminateListener > xListener( this ); + xDesktop->removeTerminateListener( xListener ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +//XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL CreationWizardUnoDlg::getPropertySetInfo() +{ + OSL_FAIL("not implemented"); + return nullptr; +} + +void SAL_CALL CreationWizardUnoDlg::setPropertyValue(const OUString& rPropertyName, + const uno::Any& rValue) +{ + if( rPropertyName == "Position" ) + { + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + + //read only property, do nothing else + } + else if( rPropertyName == "Size") + { + //read only property, do nothing + } + else if( rPropertyName == "UnlockControllersOnExecute" ) + { + if( ! (rValue >>= m_bUnlockControllersOnExecute) ) + throw lang::IllegalArgumentException( "Property 'UnlockControllers' requires value of type boolean" , nullptr, 0 ); + } + else + throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard" , nullptr ); +} + +uno::Any SAL_CALL CreationWizardUnoDlg::getPropertyValue( const OUString& rPropertyName ) +{ + uno::Any aRet; + if( rPropertyName == "Position" ) + { + //get left upper outer corner relative to screen + //pixels, screen position + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + if (m_xDialog) + { + Point aPos(m_xDialog->getDialog()->get_position()); + awt::Point aPoint(aPos.X(), aPos.Y()); + aRet <<= aPoint; + } + } + else if( rPropertyName == "Size" ) + { + //get outer size inclusive decoration + //pixels, screen position + SolarMutexGuard aSolarGuard; + createDialogOnDemand(); + if (m_xDialog) + { + Size aRect(m_xDialog->getDialog()->get_size()); + awt::Size aSize(aRect.Width(), aRect.Height()); + aRet <<= aSize; + } + } + else if( rPropertyName == "UnlockControllersOnExecute" ) + { + aRet <<= m_bUnlockControllersOnExecute; + } + else + throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard" , nullptr ); + return aRet; +} + +void SAL_CALL CreationWizardUnoDlg::addPropertyChangeListener( + const OUString& /* aPropertyName */, const uno::Reference< beans::XPropertyChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL CreationWizardUnoDlg::removePropertyChangeListener( + const OUString& /* aPropertyName */, const uno::Reference< beans::XPropertyChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL CreationWizardUnoDlg::addVetoableChangeListener( const OUString& /* PropertyName */, const uno::Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL CreationWizardUnoDlg::removeVetoableChangeListener( const OUString& /* PropertyName */, const uno::Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_WizardDialog_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::CreationWizardUnoDlg(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_DataEditor.cxx b/chart2/source/controller/dialogs/dlg_DataEditor.cxx new file mode 100644 index 000000000..6ea5a4264 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_DataEditor.cxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "DataBrowser.hxx" +#include +#include + +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +DataEditor::DataEditor(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const Reference< uno::XComponentContext > & xContext) + : GenericDialogController(pParent, "modules/schart/ui/chartdatadialog.ui", "ChartDataDialog") + , m_bReadOnly(false) + , m_xChartDoc(xChartDoc) + , m_xContext(xContext) + , m_xTbxData(m_xBuilder->weld_toolbar("toolbar")) + , m_xCloseBtn(m_xBuilder->weld_button("close")) + , m_xTable(m_xBuilder->weld_container("datawindow")) + , m_xColumns(m_xBuilder->weld_container("columns")) + , m_xColors(m_xBuilder->weld_container("colorcolumns")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xBrwData(VclPtr::Create(m_xTableCtrlParent, m_xColumns.get(), m_xColors.get())) +{ + m_xCloseBtn->connect_clicked(LINK(this, DataEditor, CloseHdl)); + + Size aSize(m_xTable->get_approximate_digit_width() * 75, m_xTable->get_text_height() * 15); + m_xTable->set_size_request(aSize.Width(), aSize.Height()); + + m_xBrwData->Show(); + + m_xTbxData->connect_clicked(LINK(this, DataEditor, ToolboxHdl)); + + m_xBrwData->SetCursorMovedHdl( LINK( this, DataEditor, BrowserCursorMovedHdl )); + + m_xBrwData->SetDataFromModel( m_xChartDoc ); + m_xBrwData->GrabFocus(); + + bool bReadOnly = true; + if( m_xChartDoc.is()) + bReadOnly = m_xChartDoc->isReadonly(); + SetReadOnly( bReadOnly ); +} + +DataEditor::~DataEditor() +{ + m_xBrwData.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +// react on click (or keypress) on toolbar icon +IMPL_LINK(DataEditor, ToolboxHdl, const OString&, rId, void) +{ + if (rId == "InsertRow") + m_xBrwData->InsertRow(); + else if (rId == "InsertColumn") + m_xBrwData->InsertColumn(); + else if (rId == "InsertTextColumn") + m_xBrwData->InsertTextColumn(); + else if (rId == "RemoveRow") + m_xBrwData->RemoveRow(); + else if (rId == "RemoveColumn") + m_xBrwData->RemoveColumn(); + else if (rId == "MoveLeftColumn") + m_xBrwData->MoveLeftColumn(); + else if (rId == "MoveRightColumn") + m_xBrwData->MoveRightColumn(); + else if (rId == "MoveUpRow") + m_xBrwData->MoveUpRow(); + else if (rId == "MoveDownRow") + m_xBrwData->MoveDownRow(); +} + +// refresh toolbar icons according to currently selected cell in browse box +IMPL_LINK_NOARG(DataEditor, BrowserCursorMovedHdl, DataBrowser*, void) +{ + if( m_bReadOnly ) + return; + + bool bIsDataValid = m_xBrwData->IsEnableItem(); + + m_xTbxData->set_item_sensitive("InsertRow", bIsDataValid && m_xBrwData->MayInsertRow() ); + m_xTbxData->set_item_sensitive("InsertColumn", bIsDataValid && m_xBrwData->MayInsertColumn() ); + m_xTbxData->set_item_sensitive("InsertTextColumn", bIsDataValid && m_xBrwData->MayInsertColumn() ); + m_xTbxData->set_item_sensitive("RemoveRow", m_xBrwData->MayDeleteRow() ); + m_xTbxData->set_item_sensitive("RemoveColumn", m_xBrwData->MayDeleteColumn() ); + + m_xTbxData->set_item_sensitive("MoveLeftColumn", bIsDataValid && m_xBrwData->MayMoveLeftColumns() ); + m_xTbxData->set_item_sensitive("MoveRightColumn", bIsDataValid && m_xBrwData->MayMoveRightColumns() ); + m_xTbxData->set_item_sensitive("MoveDownRow", bIsDataValid && m_xBrwData->MayMoveDownRows() ); + m_xTbxData->set_item_sensitive("MoveUpRow", bIsDataValid && m_xBrwData->MayMoveUpRows() ); +} + +// disable all modifying controls +void DataEditor::SetReadOnly( bool bReadOnly ) +{ + m_bReadOnly = bReadOnly; + if( m_bReadOnly ) + { + m_xTbxData->set_item_sensitive("InsertRow", false); + m_xTbxData->set_item_sensitive("InsertColumn", false); + m_xTbxData->set_item_sensitive("InsertTextColumn", false); + m_xTbxData->set_item_sensitive("RemoveRow", false); + m_xTbxData->set_item_sensitive("RemoveColumn", false); + m_xTbxData->set_item_sensitive("MoveLeftColumn", false); + m_xTbxData->set_item_sensitive("MoveRightColumn", false); + m_xTbxData->set_item_sensitive("MoveUpRow", false); + m_xTbxData->set_item_sensitive("MoveDownRow", false); + } + + m_xBrwData->SetReadOnly( m_bReadOnly ); +} + +IMPL_LINK_NOARG(DataEditor, CloseHdl, weld::Button&, void) +{ + bool bApplied = m_xBrwData->EndEditing(); // apply changes to model + if (bApplied) + m_xDialog->response(RET_CLOSE); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_DataSource.cxx b/chart2/source/controller/dialogs/dlg_DataSource.cxx new file mode 100644 index 000000000..dc1296af7 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_DataSource.cxx @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include "DialogModel.hxx" +#include + +#include "tp_RangeChooser.hxx" +#include "tp_DataSource.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::chart; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +namespace { + +class DocumentChartTypeTemplateProvider : public ChartTypeTemplateProvider +{ +public: + explicit DocumentChartTypeTemplateProvider( + const rtl::Reference<::chart::ChartModel> & xDoc ); + + // ____ ChartTypeTemplateProvider ____ + virtual rtl::Reference< ::chart::ChartTypeTemplate > getCurrentTemplate() const override; + +private: + rtl::Reference< ::chart::ChartTypeTemplate > m_xTemplate; +}; + +} + +DocumentChartTypeTemplateProvider::DocumentChartTypeTemplateProvider( + const rtl::Reference<::chart::ChartModel> & xDoc ) +{ + if( !xDoc.is()) + return; + + rtl::Reference< Diagram > xDia( xDoc->getFirstChartDiagram()); + if( xDia.is()) + { + DiagramHelper::tTemplateWithServiceName aResult( + DiagramHelper::getTemplateForDiagram( + xDia, + xDoc->getTypeManager() )); + m_xTemplate = aResult.xChartTypeTemplate; + } +} + +rtl::Reference< ::chart::ChartTypeTemplate > DocumentChartTypeTemplateProvider::getCurrentTemplate() const +{ + return m_xTemplate; +} + +sal_uInt16 DataSourceDialog::m_nLastPageId = 0; + +DataSourceDialog::DataSourceDialog(weld::Window * pParent, + const rtl::Reference<::chart::ChartModel> & xChartDocument) + : GenericDialogController(pParent, "modules/schart/ui/datarangedialog.ui", + "DataRangeDialog") + , m_apDocTemplateProvider(new DocumentChartTypeTemplateProvider(xChartDocument)) + , m_apDialogModel(new DialogModel(xChartDocument)) + , m_bRangeChooserTabIsValid(true) + , m_bDataSourceTabIsValid(true) + , m_bTogglingEnabled(true) + , m_xTabControl(m_xBuilder->weld_notebook("tabcontrol")) + , m_xBtnOK(m_xBuilder->weld_button("ok")) +{ + m_xRangeChooserTabPage = std::make_unique(m_xTabControl->get_page("range"), this, + *m_apDialogModel, + m_apDocTemplateProvider.get(), true /* bHideDescription */ ); + m_xDataSourceTabPage = std::make_unique(m_xTabControl->get_page("series"), this, + *m_apDialogModel, + m_apDocTemplateProvider.get(), true /* bHideDescription */ ); + m_xTabControl->connect_enter_page(LINK(this, DataSourceDialog, ActivatePageHdl)); + m_xTabControl->connect_leave_page(LINK(this, DataSourceDialog, DeactivatePageHdl)); + ActivatePageHdl(m_xTabControl->get_current_page_ident()); + if (m_nLastPageId != 0) + { + m_xTabControl->set_current_page(m_nLastPageId); + ActivatePageHdl(m_xTabControl->get_current_page_ident()); + } +} + +DataSourceDialog::~DataSourceDialog() +{ + m_xRangeChooserTabPage.reset(); + m_xDataSourceTabPage.reset(); + m_nLastPageId = m_xTabControl->get_current_page(); +} + +short DataSourceDialog::run() +{ + short nResult = GenericDialogController::run(); + if( nResult == RET_OK ) + { + if( m_xRangeChooserTabPage ) + m_xRangeChooserTabPage->commitPage(); + if( m_xDataSourceTabPage ) + m_xDataSourceTabPage->commitPage(); + } + return nResult; +} + +IMPL_LINK(DataSourceDialog, ActivatePageHdl, const OString&, rPage, void) +{ + if (rPage == "range") + m_xRangeChooserTabPage->Activate(); + else if (rPage == "series") + m_xDataSourceTabPage->Activate(); +} + +// allow/disallow user to leave page +IMPL_LINK_NOARG(DataSourceDialog, DeactivatePageHdl, const OString&, bool) +{ + return m_bTogglingEnabled; +} + +void DataSourceDialog::setInvalidPage(BuilderPage* pTabPage) +{ + if (pTabPage == m_xRangeChooserTabPage.get()) + m_bRangeChooserTabIsValid = false; + else if (pTabPage == m_xDataSourceTabPage.get()) + m_bDataSourceTabIsValid = false; + + if (!(m_bRangeChooserTabIsValid && m_bDataSourceTabIsValid)) + { + m_xBtnOK->set_sensitive(false); + // note: there seems to be no suitable mechanism to address pages by + // identifier, at least it is unclear what the page identifiers are. + // @todo: change the fixed numbers to identifiers + if( m_bRangeChooserTabIsValid ) + m_xTabControl->set_current_page(1); + else if( m_bDataSourceTabIsValid ) + m_xTabControl->set_current_page(0); + m_bTogglingEnabled = false; + } +} + +void DataSourceDialog::setValidPage(BuilderPage* pTabPage) +{ + if( pTabPage == m_xRangeChooserTabPage.get() ) + m_bRangeChooserTabIsValid = true; + else if( pTabPage == m_xDataSourceTabPage.get() ) + m_bDataSourceTabIsValid = true; + + if (m_bRangeChooserTabIsValid && m_bDataSourceTabIsValid) + { + m_xBtnOK->set_sensitive(true); + m_bTogglingEnabled = true; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx b/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx new file mode 100644 index 000000000..f20571e22 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertAxis_Grid.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +namespace chart +{ + +InsertAxisOrGridDialogData::InsertAxisOrGridDialogData() + : aPossibilityList{ true, true, true, true, true, true } + , aExistenceList{ false, false, false, false, false, false } +{ +} + +// SchAxisDlg + +SchAxisDlg::SchAxisDlg(weld::Window* pWindow, + const InsertAxisOrGridDialogData& rInput, bool bAxisDlg) + : GenericDialogController(pWindow, + bAxisDlg ? + OUString("modules/schart/ui/insertaxisdlg.ui") : + OUString("modules/schart/ui/insertgriddlg.ui"), + bAxisDlg ? + OString("InsertAxisDialog") : + OString("InsertGridDialog")) + , m_xCbPrimaryX(m_xBuilder->weld_check_button("primaryX")) + , m_xCbPrimaryY(m_xBuilder->weld_check_button("primaryY")) + , m_xCbPrimaryZ(m_xBuilder->weld_check_button("primaryZ")) + , m_xCbSecondaryX(m_xBuilder->weld_check_button("secondaryX")) + , m_xCbSecondaryY(m_xBuilder->weld_check_button("secondaryY")) + , m_xCbSecondaryZ(m_xBuilder->weld_check_button("secondaryZ")) +{ + if (bAxisDlg) + { + //todo: remove if secondary z axis are possible somewhere + m_xCbSecondaryZ->hide(); + } + + m_xCbPrimaryX->set_active( rInput.aExistenceList[0] ); + m_xCbPrimaryY->set_active( rInput.aExistenceList[1] ); + m_xCbPrimaryZ->set_active( rInput.aExistenceList[2] ); + m_xCbSecondaryX->set_active( rInput.aExistenceList[3] ); + m_xCbSecondaryY->set_active( rInput.aExistenceList[4] ); + m_xCbSecondaryZ->set_active( rInput.aExistenceList[5] ); + + m_xCbPrimaryX->set_sensitive( rInput.aPossibilityList[0] ); + m_xCbPrimaryY->set_sensitive( rInput.aPossibilityList[1] ); + m_xCbPrimaryZ->set_sensitive( rInput.aPossibilityList[2] ); + m_xCbSecondaryX->set_sensitive( rInput.aPossibilityList[3] ); + m_xCbSecondaryY->set_sensitive( rInput.aPossibilityList[4] ); + m_xCbSecondaryZ->set_sensitive( rInput.aPossibilityList[5] ); +} + +void SchAxisDlg::getResult( InsertAxisOrGridDialogData& rOutput ) +{ + sal_Bool* pExistenceList = rOutput.aExistenceList.getArray(); + pExistenceList[0]=m_xCbPrimaryX->get_active(); + pExistenceList[1]=m_xCbPrimaryY->get_active(); + pExistenceList[2]=m_xCbPrimaryZ->get_active(); + pExistenceList[3]=m_xCbSecondaryX->get_active(); + pExistenceList[4]=m_xCbSecondaryY->get_active(); + pExistenceList[5]=m_xCbSecondaryZ->get_active(); +} + +SchGridDlg::SchGridDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput) + : SchAxisDlg(pParent, rInput, false) //rInAttrs, b3D, bNet, bSecondaryX, bSecondaryY, false ) +{ +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx b/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx new file mode 100644 index 000000000..57817d883 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertDataLabel.cxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "res_DataLabel.hxx" + +namespace chart +{ + +DataLabelsDialog::DataLabelsDialog(weld::Window* pWindow, const SfxItemSet& rInAttrs, SvNumberFormatter* pFormatter) + : GenericDialogController(pWindow, "modules/schart/ui/dlg_DataLabel.ui", "dlg_DataLabels") + , m_apDataLabelResources(new DataLabelResources(m_xBuilder.get(), pWindow, rInAttrs)) +{ + m_apDataLabelResources->SetNumberFormatter( pFormatter ); + m_apDataLabelResources->Reset(rInAttrs); +} + +DataLabelsDialog::~DataLabelsDialog() = default; + +void DataLabelsDialog::FillItemSet(SfxItemSet& rOutAttrs) +{ + m_apDataLabelResources->FillItemSet(&rOutAttrs); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx b/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx new file mode 100644 index 000000000..98afaa47c --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertErrorBars.cxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using ::com::sun::star::uno::Reference; +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart +{ + +InsertErrorBarsDialog::InsertErrorBarsDialog( + weld::Window* pParent, const SfxItemSet& rMyAttrs, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ErrorBarResources::tErrorBarType eType /* = ErrorBarResources::ERROR_BAR_Y */ ) + : GenericDialogController(pParent, "modules/schart/ui/dlg_InsertErrorBars.ui", "dlg_InsertErrorBars") + , m_apErrorBarResources( new ErrorBarResources( + m_xBuilder.get(), this, rMyAttrs, + /* bNoneAvailable = */ true, eType )) +{ + ObjectType objType = eType == ErrorBarResources::ERROR_BAR_Y ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X; + + m_xDialog->set_title(ObjectNameProvider::getName_ObjectForAllSeries(objType)); + + m_apErrorBarResources->SetChartDocumentForRangeChoosing( xChartDocument ); +} + +void InsertErrorBarsDialog::FillItemSet(SfxItemSet& rOutAttrs) +{ + m_apErrorBarResources->FillItemSet(rOutAttrs); +} + +void InsertErrorBarsDialog::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_apErrorBarResources->SetAxisMinorStepWidthForErrorBarDecimals( fMinorStepWidth ); +} + +double InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const Reference< uno::XInterface >& xChartView, + const OUString& rSelectedObjectCID ) +{ + double fStepWidth = 0.001; + + ExplicitValueProvider* pExplicitValueProvider( comphelper::getFromUnoTunnel(xChartView) ); + if( pExplicitValueProvider ) + { + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedObjectCID, xChartModel ); + rtl::Reference< Axis > xAxis = DiagramHelper::getAttachedAxis( xSeries, xDiagram ); + if(!xAxis.is()) + xAxis = AxisHelper::getAxis( 1/*nDimensionIndex*/, true/*bMainAxis*/, xDiagram ); + if(xAxis.is()) + { + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + pExplicitValueProvider->getExplicitValuesForAxis( xAxis,aExplicitScale, aExplicitIncrement ); + + fStepWidth = aExplicitIncrement.Distance; + if( !aExplicitIncrement.SubIncrements.empty() && aExplicitIncrement.SubIncrements[0].IntervalCount>0 ) + fStepWidth=fStepWidth/double(aExplicitIncrement.SubIncrements[0].IntervalCount); + else + fStepWidth/=10; + } + } + + return fStepWidth; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertLegend.cxx b/chart2/source/controller/dialogs/dlg_InsertLegend.cxx new file mode 100644 index 000000000..c55ecc3e8 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertLegend.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +SchLegendDlg::SchLegendDlg(weld::Window* pWindow, const uno::Reference& xCC) + : GenericDialogController(pWindow, "modules/schart/ui/dlg_InsertLegend.ui", "dlg_InsertLegend") + , m_xLegendPositionResources(new LegendPositionResources(*m_xBuilder, xCC)) +{ +} + +void SchLegendDlg::init(const rtl::Reference<::chart::ChartModel>& xChartModel) +{ + m_xLegendPositionResources->writeToResources(xChartModel); +} + +void SchLegendDlg::writeToModel(const rtl::Reference<::chart::ChartModel>& xChartModel) const +{ + m_xLegendPositionResources->writeToModel(xChartModel); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_InsertTitle.cxx b/chart2/source/controller/dialogs/dlg_InsertTitle.cxx new file mode 100644 index 000000000..03f942945 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_InsertTitle.cxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +SchTitleDlg::SchTitleDlg(weld::Window* pWindow, const TitleDialogData& rInput) + : GenericDialogController(pWindow, "modules/schart/ui/inserttitledlg.ui", "InsertTitleDialog") + , m_xTitleResources(new TitleResources(*m_xBuilder, true)) +{ + m_xDialog->set_title(ObjectNameProvider::getName(OBJECTTYPE_TITLE, true)); + m_xTitleResources->writeToResources(rInput); +} + +void SchTitleDlg::getResult(TitleDialogData& rOutput) +{ + m_xTitleResources->readFromResources(rOutput); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_NumberFormat.cxx b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx new file mode 100644 index 000000000..7750588cc --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_NumberFormat.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dlg_NumberFormat.hxx" + +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +NumberFormatDialog::NumberFormatDialog(weld::Window* pParent, const SfxItemSet& rSet) + : SfxSingleTabDialogController(pParent, &rSet, "cui/ui/formatnumberdialog.ui", "FormatNumberDialog") +{ + SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ); + if (fnCreatePage) + { + std::unique_ptr xTabPage = (*fnCreatePage)(get_content_area(), this, &rSet); + xTabPage->PageCreated(rSet); + SetTabPage(std::move(xTabPage)); + } +} + +SfxItemSet NumberFormatDialog::CreateEmptyItemSetForNumberFormatDialog( SfxItemPool& rItemPool ) +{ + return SfxItemSet( rItemPool, svl::Items< + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA, + SID_ATTR_NUMBERFORMAT_NOLANGUAGE, SID_ATTR_NUMBERFORMAT_NOLANGUAGE, + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE> ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_NumberFormat.hxx b/chart2/source/controller/dialogs/dlg_NumberFormat.hxx new file mode 100644 index 000000000..56d5acd20 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_NumberFormat.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace weld +{ +class Window; +} +class SfxItemSet; +class SfxItemPool; + +namespace chart +{ +class NumberFormatDialog : public SfxSingleTabDialogController +{ +public: + NumberFormatDialog(weld::Window* pParent, const SfxItemSet& rSet); + + static SfxItemSet CreateEmptyItemSetForNumberFormatDialog(SfxItemPool& rItemPool); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx new file mode 100644 index 000000000..f0497ecdc --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include "tp_AxisLabel.hxx" +#include "tp_DataLabel.hxx" +#include "tp_LegendPosition.hxx" +#include "tp_PointGeometry.hxx" +#include "tp_Scale.hxx" +#include "tp_AxisPositions.hxx" +#include "tp_ErrorBars.hxx" +#include "tp_Trendline.hxx" +#include "tp_SeriesToAxis.hxx" +#include "tp_TitleRotation.hxx" +#include "tp_PolarOptions.hxx" +#include "tp_DataPointOption.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } + +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::Exception; +using ::com::sun::star::beans::XPropertySet; + +ObjectPropertiesDialogParameter::ObjectPropertiesDialogParameter( const OUString& rObjectCID ) + : m_aObjectCID( rObjectCID ) + , m_eObjectType( ObjectIdentifier::getObjectType( m_aObjectCID ) ) + , m_bAffectsMultipleObjects(false) + , m_bHasGeometryProperties(false) + , m_bHasStatisticProperties(false) + , m_bProvidesSecondaryYAxis(false) + , m_bProvidesOverlapAndGapWidth(false) + , m_bProvidesBarConnectors(false) + , m_bHasAreaProperties(false) + , m_bHasSymbolProperties(false) + , m_bHasNumberProperties(false) + , m_bProvidesStartingAngle(false) + , m_bProvidesMissingValueTreatments(false) + , m_bIsPieChartDataPoint(false) + , m_bHasScaleProperties(false) + , m_bCanAxisLabelsBeStaggered(false) + , m_bSupportingAxisPositioning(false) + , m_bShowAxisOrigin(false) + , m_bIsCrossingAxisIsCategoryAxis(false) + , m_bSupportingCategoryPositioning(false) + , m_bComplexCategoriesAxis( false ) + , m_nNbPoints( 0 ) +{ + std::u16string_view aParticleID = ObjectIdentifier::getParticleID( m_aObjectCID ); + m_bAffectsMultipleObjects = (aParticleID == u"ALLELEMENTS"); +} +ObjectPropertiesDialogParameter::~ObjectPropertiesDialogParameter() +{ +} + +void ObjectPropertiesDialogParameter::init( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + m_xChartDocument = xChartModel; + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aObjectCID, xChartModel ); + rtl::Reference< ChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + bool bHasSeriesProperties = (m_eObjectType==OBJECTTYPE_DATA_SERIES); + bool bHasDataPointproperties = (m_eObjectType==OBJECTTYPE_DATA_POINT); + + if( bHasSeriesProperties || bHasDataPointproperties ) + { + m_bHasGeometryProperties = ChartTypeHelper::isSupportingGeometryProperties( xChartType, nDimensionCount ); + m_bHasAreaProperties = ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ); + m_bHasSymbolProperties = ChartTypeHelper::isSupportingSymbolProperties( xChartType, nDimensionCount ); + m_bIsPieChartDataPoint = bHasDataPointproperties && ChartTypeHelper::isSupportingStartingAngle( xChartType ); + + if( bHasSeriesProperties ) + { + m_bHasStatisticProperties = ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ); + m_bProvidesSecondaryYAxis = ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ); + m_bProvidesOverlapAndGapWidth = ChartTypeHelper::isSupportingOverlapAndGapWidthProperties( xChartType, nDimensionCount ); + m_bProvidesBarConnectors = ChartTypeHelper::isSupportingBarConnectors( xChartType, nDimensionCount ); + m_bProvidesStartingAngle = ChartTypeHelper::isSupportingStartingAngle( xChartType ); + + m_bProvidesMissingValueTreatments = ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) + .hasElements(); + } + } + + if( m_eObjectType == OBJECTTYPE_DATA_ERRORS_X || + m_eObjectType == OBJECTTYPE_DATA_ERRORS_Y || + m_eObjectType == OBJECTTYPE_DATA_ERRORS_Z) + m_bHasStatisticProperties = true; + + if( m_eObjectType == OBJECTTYPE_AXIS ) + { + //show scale properties only for a single axis not for multiselection + m_bHasScaleProperties = !m_bAffectsMultipleObjects; + + if( m_bHasScaleProperties ) + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aObjectCID, xChartModel ); + if( xAxis.is() ) + { + //no scale page for series axis + ScaleData aData( xAxis->getScaleData() ); + if( aData.AxisType == chart2::AxisType::SERIES ) + m_bHasScaleProperties = false; + if( aData.AxisType != chart2::AxisType::SERIES ) + m_bHasNumberProperties = true; + + //is the crossing main axis a category axes?: + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, xDiagram ) ); + uno::Reference< XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( xAxis, xCooSys ) ); + if( xCrossingMainAxis.is() ) + { + ScaleData aScale( xCrossingMainAxis->getScaleData() ); + m_bIsCrossingAxisIsCategoryAxis = ( aScale.AxisType == chart2::AxisType::CATEGORY ); + if( m_bIsCrossingAxisIsCategoryAxis ) + { + if (xChartModel) + m_aCategories = DiagramHelper::getExplicitSimpleCategories( *xChartModel ); + } + } + + sal_Int32 nCooSysIndex=0; + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) ) + { + xChartType = AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( xDiagram, nAxisIndex ); + //show positioning controls only if they make sense + m_bSupportingAxisPositioning = ChartTypeHelper::isSupportingAxisPositioning( xChartType, nDimensionCount, nDimensionIndex ); + + //show axis origin only for secondary y axis + if( nDimensionIndex==1 && nAxisIndex==1 && ChartTypeHelper::isSupportingBaseValue( xChartType ) ) + m_bShowAxisOrigin = true; + + if ( nDimensionIndex == 0 && ( aData.AxisType == chart2::AxisType::CATEGORY || aData.AxisType == chart2::AxisType::DATE ) ) + { + if (xChartModel) + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, *xChartModel ); + m_bComplexCategoriesAxis = aExplicitCategoriesProvider.hasComplexCategories(); + } + + if (!m_bComplexCategoriesAxis) + m_bSupportingCategoryPositioning = ChartTypeHelper::isSupportingCategoryPositioning( xChartType, nDimensionCount ); + } + } + } + } + + //no staggering of labels for 3D axis + m_bCanAxisLabelsBeStaggered = nDimensionCount==2; + } + + if( m_eObjectType == OBJECTTYPE_DATA_CURVE ) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSeqs( xSeries->getDataSequences2()); + Sequence< double > aXValues, aYValues; + bool bXValuesFound = false, bYValuesFound = false; + m_nNbPoints = 0; + for( std::size_t i=0; + ! (bXValuesFound && bYValuesFound) && i xSeq( aDataSeqs[i]->getValues()); + Reference< XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + OUString aRole; + if( xProp->getPropertyValue( "Role" ) >>= aRole ) + { + if( !bXValuesFound && aRole == "values-x" ) + { + aXValues = DataSequenceToDoubleSequence( xSeq ); + bXValuesFound = true; + } + else if( !bYValuesFound && aRole == "values-y" ) + { + aYValues = DataSequenceToDoubleSequence( xSeq ); + bYValuesFound = true; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + if( !bXValuesFound && bYValuesFound ) + { + // initialize with 1, 2, ... + //first category (index 0) matches with real number 1.0 + aXValues.realloc( aYValues.getLength() ); + auto pXValues = aXValues.getArray(); + for( sal_Int32 i=0; i pAutoSymbolGraphic ) +{ + m_oSymbolShapeProperties.emplace(std::move(rSymbolShapeProperties)); + m_pAutoSymbolGraphic = std::move(pAutoSymbolGraphic); +} + +void SchAttribTabDlg::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_fAxisMinorStepWidthForErrorBarDecimals = fMinorStepWidth; +} + +SchAttribTabDlg::SchAttribTabDlg(weld::Window* pParent, + const SfxItemSet* pAttr, + const ObjectPropertiesDialogParameter* pDialogParameter, + const ViewElementListProvider* pViewElementListProvider, + const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier) + : SfxTabDialogController(pParent, "modules/schart/ui/attributedialog.ui", "AttributeDialog", pAttr) + , m_pParameter( pDialogParameter ) + , m_pViewElementListProvider( pViewElementListProvider ) + , m_pNumberFormatter(nullptr) + , m_fAxisMinorStepWidthForErrorBarDecimals(0.1) + , m_bOKPressed(false) +{ + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + m_pNumberFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + + m_xDialog->set_title(pDialogParameter->getLocalizedName()); + + switch (pDialogParameter->getObjectType()) + { + case OBJECTTYPE_TITLE: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("alignment", SchResId(STR_PAGE_ALIGNMENT), SchAlignmentTabPage::Create); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + + case OBJECTTYPE_LEGEND: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("legendpos", SchResId(STR_PAGE_POSITION), SchLegendPosTabPage::Create); + if (SvtCJKOptions::IsAsianTypographyEnabled()) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + if( m_pParameter->ProvidesSecondaryYAxis() || m_pParameter->ProvidesOverlapAndGapWidth() || m_pParameter->ProvidesMissingValueTreatments() ) + AddTabPage("options", SchResId(STR_PAGE_OPTIONS),SchOptionTabPage::Create); + if( m_pParameter->ProvidesStartingAngle()) + AddTabPage("polaroptions", SchResId(STR_PAGE_OPTIONS), PolarOptionsTabPage::Create); + if (m_pParameter->IsPieChartDataPoint()) + AddTabPage("datapointoption", SchResId(STR_PAGE_OPTIONS), DataPointOptionTabPage::Create); + + if( m_pParameter->HasGeometryProperties() ) + AddTabPage("layout", SchResId(STR_PAGE_LAYOUT), SchLayoutTabPage::Create); + + if(m_pParameter->HasAreaProperties()) + { + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + } + AddTabPage("border", SchResId( m_pParameter->HasAreaProperties() ? STR_PAGE_BORDER : STR_PAGE_LINE ), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_LABELS: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("datalabels", SchResId(STR_OBJECT_DATALABELS), DataLabelsTabPage::Create); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + + break; + + case OBJECTTYPE_AXIS: + { + if( m_pParameter->HasScaleProperties() ) + { + AddTabPage("scale", SchResId(STR_PAGE_SCALE), ScaleTabPage::Create); + //no positioning page for z axes so far as the tickmarks are not shown so far + AddTabPage("axispos", SchResId(STR_PAGE_POSITIONING), AxisPositionsTabPage::Create); + } + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + AddTabPage("axislabel", SchResId(STR_OBJECT_LABEL), SchAxisLabelTabPage::Create); + if( m_pParameter->HasNumberProperties() ) + AddTabPage("numberformat", SchResId(STR_PAGE_NUMBERS), RID_SVXPAGE_NUMBERFORMAT); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + if( SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("asian", SchResId(STR_PAGE_ASIAN), RID_SVXPAGE_PARA_ASIAN); + break; + } + + case OBJECTTYPE_DATA_ERRORS_X: + AddTabPage("xerrorbar", SchResId(STR_PAGE_XERROR_BARS), ErrorBarsTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_ERRORS_Y: + AddTabPage("yerrorbar", SchResId(STR_PAGE_YERROR_BARS), ErrorBarsTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_ERRORS_Z: + break; + + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_STOCK_RANGE: + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_CURVE: + AddTabPage("trendline", SchResId(STR_PAGE_TRENDLINE_TYPE), TrendlineTabPage::Create); + AddTabPage("border", SchResId(STR_PAGE_LINE), RID_SVXPAGE_LINE); + break; + + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + case OBJECTTYPE_PAGE: + case OBJECTTYPE_DIAGRAM_FLOOR: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + break; + + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_AXIS_UNITLABEL: + case OBJECTTYPE_UNKNOWN: + // nothing + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + AddTabPage("border", SchResId(STR_PAGE_BORDER), RID_SVXPAGE_LINE); + AddTabPage("area", SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); + AddTabPage("transparent", SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); + AddTabPage("fontname", SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); + AddTabPage("effects", SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("numberformat", SchResId(STR_PAGE_NUMBERS), RID_SVXPAGE_NUMBERFORMAT); + if (SvtCTLOptions().IsCTLFontEnabled()) + { + /* When rotation is supported for equation text boxes, use + SchAlignmentTabPage::Create here. The special + SchAlignmentTabPage::CreateWithoutRotation can be deleted. */ + AddTabPage("alignment", SchResId(STR_PAGE_ALIGNMENT), SchAlignmentTabPage::CreateWithoutRotation); + } + break; + default: + break; + } + + // used to find out if user left the dialog with OK. When OK is pressed but + // no changes were done, Cancel is returned by the SfxTabDialog. See method + // DialogWasClosedWithOK. + GetOKButton().connect_clicked(LINK(this, SchAttribTabDlg, OKPressed)); +} + +SchAttribTabDlg::~SchAttribTabDlg() +{ +} + +void SchAttribTabDlg::PageCreated(const OString& rId, SfxTabPage &rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "border") + { + aSet.Put (SvxColorListItem(m_pViewElementListProvider->GetColorTable(),SID_COLOR_TABLE)); + aSet.Put (SvxDashListItem(m_pViewElementListProvider->GetDashList(),SID_DASH_LIST)); + aSet.Put (SvxLineEndListItem(m_pViewElementListProvider->GetLineEndList(),SID_LINEEND_LIST)); + aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put (SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + + if( m_pParameter->HasSymbolProperties() ) + { + aSet.Put(OfaPtrItem(SID_OBJECT_LIST,m_pViewElementListProvider->GetSymbolList())); + if( m_oSymbolShapeProperties ) + aSet.Put(SfxTabDialogItem(SID_ATTR_SET, *m_oSymbolShapeProperties)); + if( m_pAutoSymbolGraphic ) + aSet.Put(SvxGraphicItem(*m_pAutoSymbolGraphic)); + } + rPage.PageCreated(aSet); + } + else if (rId == "area") + { + aSet.Put(SvxColorListItem(m_pViewElementListProvider->GetColorTable(),SID_COLOR_TABLE)); + aSet.Put(SvxGradientListItem(m_pViewElementListProvider->GetGradientList(),SID_GRADIENT_LIST)); + aSet.Put(SvxHatchListItem(m_pViewElementListProvider->GetHatchList(),SID_HATCH_LIST)); + aSet.Put(SvxBitmapListItem(m_pViewElementListProvider->GetBitmapList(),SID_BITMAP_LIST)); + aSet.Put(SvxPatternListItem(m_pViewElementListProvider->GetPatternList(),SID_PATTERN_LIST)); + aSet.Put(SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put(SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + rPage.PageCreated(aSet); + } + else if (rId == "transparent") + { + aSet.Put (SfxUInt16Item(SID_PAGE_TYPE,0)); + aSet.Put (SfxUInt16Item(SID_DLG_TYPE,nNoArrowNoShadowDlg)); + rPage.PageCreated(aSet); + } + else if (rId == "fontname") + { + aSet.Put (SvxFontListItem(m_pViewElementListProvider->getFontList(), SID_ATTR_CHAR_FONTLIST)); + rPage.PageCreated(aSet); + } + else if (rId == "effects") + { + aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP)); + rPage.PageCreated(aSet); + } + else if (rId == "axislabel") + { + bool bShowStaggeringControls = m_pParameter->CanAxisLabelsBeStaggered(); + auto & rLabelPage = static_cast(rPage); + rLabelPage.ShowStaggeringControls( bShowStaggeringControls ); + rLabelPage.SetComplexCategories( m_pParameter->IsComplexCategoriesAxis() ); + } + else if (rId == "axispos") + { + AxisPositionsTabPage* pPage = dynamic_cast< AxisPositionsTabPage* >( &rPage ); + if(pPage) + { + pPage->SetNumFormatter( m_pNumberFormatter ); + if( m_pParameter->IsCrossingAxisIsCategoryAxis() ) + { + pPage->SetCrossingAxisIsCategoryAxis( m_pParameter->IsCrossingAxisIsCategoryAxis() ); + pPage->SetCategories( m_pParameter->GetCategories() ); + } + pPage->SupportAxisPositioning( m_pParameter->IsSupportingAxisPositioning() ); + pPage->SupportCategoryPositioning( m_pParameter->IsSupportingCategoryPositioning() ); + } + } + else if (rId == "scale") + { + ScaleTabPage* pScaleTabPage = dynamic_cast< ScaleTabPage* >( &rPage ); + if(pScaleTabPage) + { + pScaleTabPage->SetNumFormatter( m_pNumberFormatter ); + pScaleTabPage->ShowAxisOrigin( m_pParameter->ShowAxisOrigin() ); + } + } + else if (rId == "datalabels") + { + DataLabelsTabPage* pLabelPage = dynamic_cast< DataLabelsTabPage* >( &rPage ); + if( pLabelPage ) + pLabelPage->SetNumberFormatter( m_pNumberFormatter ); + } + else if (rId == "numberformat") + { + aSet.Put (SvxNumberInfoItem( m_pNumberFormatter, SID_ATTR_NUMBERFORMAT_INFO)); + rPage.PageCreated(aSet); + } + else if (rId == "xerrorbar") + { + ErrorBarsTabPage * pTabPage = dynamic_cast< ErrorBarsTabPage * >( &rPage ); + OSL_ASSERT( pTabPage ); + if( pTabPage ) + { + pTabPage->SetAxisMinorStepWidthForErrorBarDecimals( m_fAxisMinorStepWidthForErrorBarDecimals ); + pTabPage->SetErrorBarType( ErrorBarResources::ERROR_BAR_X ); + pTabPage->SetChartDocumentForRangeChoosing( m_pParameter->getDocument()); + } + } + else if (rId == "yerrorbar") + { + ErrorBarsTabPage * pTabPage = dynamic_cast< ErrorBarsTabPage * >( &rPage ); + OSL_ASSERT( pTabPage ); + if( pTabPage ) + { + pTabPage->SetAxisMinorStepWidthForErrorBarDecimals( m_fAxisMinorStepWidthForErrorBarDecimals ); + pTabPage->SetErrorBarType( ErrorBarResources::ERROR_BAR_Y ); + pTabPage->SetChartDocumentForRangeChoosing( m_pParameter->getDocument()); + } + } + else if (rId == "options") + { + SchOptionTabPage* pTabPage = dynamic_cast< SchOptionTabPage* >( &rPage ); + if( pTabPage && m_pParameter ) + pTabPage->Init( m_pParameter->ProvidesSecondaryYAxis(), m_pParameter->ProvidesOverlapAndGapWidth(), + m_pParameter->ProvidesBarConnectors() ); + } + else if (rId == "trendline") + { + TrendlineTabPage* pTrendlineTabPage = dynamic_cast< TrendlineTabPage* >( &rPage ); + if(pTrendlineTabPage) + { + pTrendlineTabPage->SetNumFormatter( m_pNumberFormatter ); + pTrendlineTabPage->SetNbPoints( m_pParameter->getNbPoints() ); + } + } +} + +IMPL_LINK(SchAttribTabDlg, OKPressed, weld::Button&, rButton, void) +{ + m_bOKPressed = true; + OkHdl(rButton); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ShapeFont.cxx b/chart2/source/controller/dialogs/dlg_ShapeFont.cxx new file mode 100644 index 000000000..f5fc702a2 --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ShapeFont.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +ShapeFontDialog::ShapeFontDialog(weld::Window* pParent, const SfxItemSet* pAttr, + const ViewElementListProvider* pViewElementListProvider) + : SfxTabDialogController(pParent, "modules/schart/ui/chardialog.ui", "CharDialog", pAttr) + , m_pViewElementListProvider(pViewElementListProvider) +{ + AddTabPage("font", RID_SVXPAGE_CHAR_NAME); + AddTabPage("fonteffects", RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("position", RID_SVXPAGE_CHAR_POSITION ); +} + +void ShapeFontDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + SfxAllItemSet aSet( *( GetInputSetImpl()->GetPool() ) ); + if (rId == "font") + { + aSet.Put( SvxFontListItem( m_pViewElementListProvider->getFontList(), SID_ATTR_CHAR_FONTLIST ) ); + rPage.PageCreated( aSet ); + } + else if (rId == "fonteffects") + { + aSet.Put( SfxUInt16Item( SID_DISABLE_CTL, DISABLE_CASEMAP ) ); + rPage.PageCreated( aSet ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx b/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx new file mode 100644 index 000000000..e5b422cea --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_ShapeParagraph.cxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +ShapeParagraphDialog::ShapeParagraphDialog(weld::Window* pParent, + const SfxItemSet* pAttr) + : SfxTabDialogController(pParent, "modules/schart/ui/paradialog.ui", "ParagraphDialog", pAttr) +{ + AddTabPage("labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH); + AddTabPage("labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH ); + if (SvtCJKOptions::IsAsianTypographyEnabled()) + { + AddTabPage("labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN); + } + else + { + RemoveTabPage("labelTP_PARA_ASIAN"); + } + AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR); +} + +void ShapeParagraphDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + if (rId == "labelTP_TABULATOR") + { + SfxAllItemSet aSet( *( GetInputSetImpl()->GetPool() ) ); + TabulatorDisableFlags const nFlags(( TabulatorDisableFlags::TypeMask &~TabulatorDisableFlags::TypeLeft ) | + ( TabulatorDisableFlags::FillMask &~TabulatorDisableFlags::FillNone )); + aSet.Put( SfxUInt16Item( SID_SVXTABULATORTABPAGE_DISABLEFLAGS, static_cast(nFlags)) ); + rPage.PageCreated( aSet ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/dlg_View3D.cxx b/chart2/source/controller/dialogs/dlg_View3D.cxx new file mode 100644 index 000000000..abc2645de --- /dev/null +++ b/chart2/source/controller/dialogs/dlg_View3D.cxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "tp_3D_SceneGeometry.hxx" +#include "tp_3D_SceneAppearance.hxx" +#include "tp_3D_SceneIllumination.hxx" +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +sal_uInt16 View3DDialog::m_nLastPageId = 0; + +View3DDialog::View3DDialog(weld::Window* pParent, const rtl::Reference<::chart::ChartModel> & xChartModel) + : GenericDialogController(pParent, "modules/schart/ui/3dviewdialog.ui", "3DViewDialog") + , m_aControllerLocker(xChartModel) + , m_xTabControl(m_xBuilder->weld_notebook("tabcontrol")) +{ + rtl::Reference< Diagram > xSceneProperties = ChartModelHelper::findDiagram( xChartModel ); + + m_xTabControl->append_page("geometry", SchResId(STR_PAGE_PERSPECTIVE)); + m_xGeometry.reset(new ThreeD_SceneGeometry_TabPage(m_xTabControl->get_page("geometry"), xSceneProperties, m_aControllerLocker)); + + m_xTabControl->append_page("appearance", SchResId(STR_PAGE_APPEARANCE)); + m_xAppearance.reset(new ThreeD_SceneAppearance_TabPage(m_xTabControl->get_page("appearance"), xChartModel, m_aControllerLocker)); + + m_xTabControl->append_page("illumination", SchResId(STR_PAGE_ILLUMINATION)); + m_xIllumination.reset(new ThreeD_SceneIllumination_TabPage(m_xTabControl->get_page("illumination"), m_xDialog.get(), + xSceneProperties, xChartModel)); + + m_xTabControl->connect_enter_page(LINK(this, View3DDialog, ActivatePageHdl)); + + m_xTabControl->set_current_page(m_nLastPageId); +} + +IMPL_LINK(View3DDialog, ActivatePageHdl, const OString&, rPage, void) +{ + if (rPage == "appearance") + m_xAppearance->ActivatePage(); +} + +View3DDialog::~View3DDialog() +{ + m_nLastPageId = m_xTabControl->get_current_page(); +} + +short View3DDialog::run() +{ + short nResult = GenericDialogController::run(); + if (nResult == RET_OK && m_xGeometry) + m_xGeometry->commitPendingChanges(); + return nResult; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_BarGeometry.cxx b/chart2/source/controller/dialogs/res_BarGeometry.cxx new file mode 100644 index 000000000..97befbe1f --- /dev/null +++ b/chart2/source/controller/dialogs/res_BarGeometry.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +BarGeometryResources::BarGeometryResources(weld::Builder* pBuilder) + : m_xFT_Geometry(pBuilder->weld_label("shapeft")) + , m_xLB_Geometry(pBuilder->weld_tree_view("shape")) +{ + for (size_t i = 0; i < std::size(CHART_TYPE); ++i) + m_xLB_Geometry->append_text(SchResId(CHART_TYPE[i])); + m_xLB_Geometry->set_size_request(-1, + m_xLB_Geometry->get_height_rows(SAL_N_ELEMENTS(CHART_TYPE))); +} + +void BarGeometryResources::connect_changed(const Link& rLink) +{ + m_xLB_Geometry->connect_changed(rLink); +} + +void BarGeometryResources::set_visible(bool bShow) +{ + m_xFT_Geometry->set_visible(bShow); + m_xLB_Geometry->set_visible(bShow); +} + +void BarGeometryResources::set_sensitive(bool bEnable) +{ + m_xFT_Geometry->set_sensitive(bEnable); + m_xLB_Geometry->set_sensitive(bEnable); +} + +sal_Int32 BarGeometryResources::get_selected_index() const +{ + return m_xLB_Geometry->get_selected_index(); +} + +void BarGeometryResources::select(sal_Int32 nPos) +{ + if (nPos < m_xLB_Geometry->n_children()) + m_xLB_Geometry->select(nPos); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_DataLabel.cxx b/chart2/source/controller/dialogs/res_DataLabel.cxx new file mode 100644 index 000000000..3c6950e8e --- /dev/null +++ b/chart2/source/controller/dialogs/res_DataLabel.cxx @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "res_DataLabel.hxx" + +#include +#include +#include "dlg_NumberFormat.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +namespace +{ + +const std::u16string_view our_aLBEntryMap[] = {u" ", u", ", u"; ", u"\n", u". "}; + +bool lcl_ReadNumberFormatFromItemSet( const SfxItemSet& rSet, TypedWhichId nValueWhich, TypedWhichId nSourceFormatWhich, sal_uInt32& rnFormatKeyOut, bool& rbSourceFormatOut, bool& rbSourceFormatMixedStateOut ) +{ + bool bSet = false; + if( const SfxUInt32Item* pNumItem = rSet.GetItemIfSet( nValueWhich ) ) + { + rnFormatKeyOut = pNumItem->GetValue(); + bSet = true; + } + + rbSourceFormatMixedStateOut=true; + if( const SfxBoolItem * pBoolItem = rSet.GetItemIfSet( nSourceFormatWhich ) ) + { + rbSourceFormatOut = pBoolItem->GetValue(); + rbSourceFormatMixedStateOut=false; + } + return bSet; +} + +void lcl_setBoolItemToCheckBox(const SfxItemSet& rInAttrs, TypedWhichId nWhichId, weld::CheckButton& rCheckbox) +{ + if( const SfxBoolItem* pPoolItem = rInAttrs.GetItemIfSet(nWhichId) ) + rCheckbox.set_active(pPoolItem->GetValue()); + else + rCheckbox.set_state(TRISTATE_INDET); +} + +}//end anonymous namespace + +DataLabelResources::DataLabelResources(weld::Builder* pBuilder, weld::Window* pParent, const SfxItemSet& rInAttrs) + : m_pNumberFormatter(nullptr) + , m_bNumberFormatMixedState(true) + , m_bPercentFormatMixedState(true) + , m_nNumberFormatForValue(0) + , m_nNumberFormatForPercent(11) + , m_bSourceFormatMixedState(true) + , m_bPercentSourceMixedState(true) + , m_bSourceFormatForValue(true) + , m_bSourceFormatForPercent(true) + , m_pWindow(pParent) + , m_pPool(rInAttrs.GetPool()) + , m_xCBNumber(pBuilder->weld_check_button("CB_VALUE_AS_NUMBER")) + , m_xPB_NumberFormatForValue(pBuilder->weld_button("PB_NUMBERFORMAT")) + , m_xCBPercent(pBuilder->weld_check_button("CB_VALUE_AS_PERCENTAGE")) + , m_xPB_NumberFormatForPercent(pBuilder->weld_button("PB_PERCENT_NUMBERFORMAT")) + , m_xFT_NumberFormatForPercent(pBuilder->weld_label("STR_DLG_NUMBERFORMAT_FOR_PERCENTAGE_VALUE")) + , m_xCBCategory(pBuilder->weld_check_button("CB_CATEGORY")) + , m_xCBSymbol(pBuilder->weld_check_button("CB_SYMBOL")) + , m_xCBDataSeries(pBuilder->weld_check_button("CB_DATA_SERIES_NAME")) + , m_xCBWrapText(pBuilder->weld_check_button("CB_WRAP_TEXT")) + , m_xLB_Separator(pBuilder->weld_combo_box("LB_TEXT_SEPARATOR")) + , m_xLB_LabelPlacement(pBuilder->weld_combo_box("LB_LABEL_PLACEMENT")) + , m_xBxOrientation(pBuilder->weld_widget("boxORIENTATION")) + , m_xFT_Dial(pBuilder->weld_label("CT_LABEL_DIAL")) + , m_xNF_Degrees(pBuilder->weld_metric_spin_button("NF_LABEL_DEGREES", FieldUnit::DEGREE)) + , m_xBxTextDirection(pBuilder->weld_widget("boxTXT_DIRECTION")) + , m_xLB_TextDirection(new TextDirectionListBox(pBuilder->weld_combo_box("LB_LABEL_TEXTDIR"))) + , m_xDC_Dial(new svx::DialControl) + , m_xDC_DialWin(new weld::CustomWeld(*pBuilder, "CT_DIAL", *m_xDC_Dial)) + , m_xCBCustomLeaderLines(pBuilder->weld_check_button("CB_CUSTOM_LEADER_LINES")) +{ + m_xDC_Dial->SetText(m_xFT_Dial->get_label()); + + //fill label placement list + std::map< sal_Int32, OUString > aPlacementToStringMap; + for( sal_Int32 nEnum=0; nEnumget_count(); ++nEnum ) + aPlacementToStringMap[nEnum] = m_xLB_LabelPlacement->get_text(static_cast(nEnum)); + + + std::vector< sal_Int32 > aAvailablePlacementList; + if( const SfxIntegerListItem* pPlacementsItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS) ) + aAvailablePlacementList = pPlacementsItem->GetList(); + + m_xLB_LabelPlacement->clear(); + for( size_t nN=0; nN( nN ); + sal_Int32 nPlacement = aAvailablePlacementList[nN]; + m_aPlacementToListBoxMap[nPlacement]=nListBoxPos; + m_aListBoxToPlacementMap[nListBoxPos]=nPlacement; + m_xLB_LabelPlacement->append_text( aPlacementToStringMap[nPlacement] ); + } + + //some click handler + m_xPB_NumberFormatForValue->connect_clicked( LINK( this, DataLabelResources, NumberFormatDialogHdl ) ); + m_xPB_NumberFormatForPercent->connect_clicked( LINK( this, DataLabelResources, NumberFormatDialogHdl ) ); + m_xCBNumber->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBPercent->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBCategory->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBSymbol->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBDataSeries->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBWrapText->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + m_xCBCustomLeaderLines->connect_toggled( LINK( this, DataLabelResources, CheckHdl )); + + m_bNumberFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, m_nNumberFormatForValue, m_bSourceFormatForValue, m_bSourceFormatMixedState ); + m_bPercentFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SCHATTR_PERCENT_NUMBERFORMAT_VALUE, SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_nNumberFormatForPercent, m_bSourceFormatForPercent , m_bPercentSourceMixedState); + + if( const SfxBoolItem* pNoPercentValueItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_NO_PERCENTVALUE) ) + { + bool bForbidPercentValue = pNoPercentValueItem->GetValue(); + if( bForbidPercentValue ) + m_xCBPercent->set_sensitive(false); + } + + m_xDC_Dial->SetLinkedField(m_xNF_Degrees.get()); +} + +DataLabelResources::~DataLabelResources() +{ +} + +void DataLabelResources::SetNumberFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumberFormatter = pFormatter; +} + +IMPL_LINK(DataLabelResources, NumberFormatDialogHdl, weld::Button&, rButton, void) +{ + if( !m_pPool || !m_pNumberFormatter ) + { + OSL_FAIL("Missing item pool or number formatter"); + return; + } + + if (&rButton == m_xPB_NumberFormatForValue.get() && !m_xCBNumber->get_active()) + m_xCBNumber->set_active(true); + else if (&rButton == m_xPB_NumberFormatForPercent.get() && !m_xCBPercent->get_active()) + m_xCBPercent->set_active(true); + + SfxItemSet aNumberSet = NumberFormatDialog::CreateEmptyItemSetForNumberFormatDialog( *m_pPool ); + aNumberSet.Put (SvxNumberInfoItem( m_pNumberFormatter, SID_ATTR_NUMBERFORMAT_INFO)); + + bool bPercent = (&rButton == m_xPB_NumberFormatForPercent.get()); + + sal_uInt32& rnFormatKey = bPercent ? m_nNumberFormatForPercent : m_nNumberFormatForValue; + bool& rUseSourceFormat = bPercent ? m_bSourceFormatForPercent : m_bSourceFormatForValue; + bool& rbMixedState = bPercent ? m_bPercentFormatMixedState : m_bNumberFormatMixedState; + bool& rbSourceMixedState = bPercent ? m_bPercentSourceMixedState : m_bSourceFormatMixedState; + + if(!rbMixedState) + aNumberSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, rnFormatKey )); + aNumberSet.Put( SfxBoolItem( SID_ATTR_NUMBERFORMAT_SOURCE, rUseSourceFormat )); + + NumberFormatDialog aDlg(m_pWindow, aNumberSet); + if( bPercent ) + aDlg.set_title(m_xFT_NumberFormatForPercent->get_label()); + if (aDlg.run() != RET_OK) + return; + + const SfxItemSet* pResult = aDlg.GetOutputItemSet(); + if( pResult ) + { + bool bOldSource = rUseSourceFormat; + sal_uInt32 nOldFormat = rnFormatKey; + bool bOldMixedState = rbMixedState || rbSourceMixedState; + + rbMixedState = !lcl_ReadNumberFormatFromItemSet( *pResult, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, rnFormatKey, rUseSourceFormat, rbSourceMixedState ); + + //todo this maybe can be removed when the numberformatter dialog does handle mixed state for source format correctly + if( bOldMixedState && bOldSource == rUseSourceFormat && nOldFormat == rnFormatKey ) + rbMixedState = rbSourceMixedState = true; + } +} + +IMPL_LINK_NOARG(DataLabelResources, CheckHdl, weld::Toggleable&, void) +{ + EnableControls(); +} + +void DataLabelResources::EnableControls() +{ + m_xCBSymbol->set_sensitive( m_xCBNumber->get_active() || (m_xCBPercent->get_active() && m_xCBPercent->get_sensitive()) + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active()); + + m_xCBWrapText->set_sensitive( m_xCBNumber->get_active() || (m_xCBPercent->get_active() && m_xCBPercent->get_sensitive()) + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active() ); + + // Enable or disable separator, placement and direction based on the check + // box states. Note that the check boxes are tri-state. + { + tools::Long nNumberOfCheckedLabelParts = 0; + if (m_xCBNumber->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + if (m_xCBPercent->get_state() != TRISTATE_FALSE && m_xCBPercent->get_sensitive()) + ++nNumberOfCheckedLabelParts; + if (m_xCBCategory->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + if (m_xCBDataSeries->get_state() != TRISTATE_FALSE) + ++nNumberOfCheckedLabelParts; + + m_xLB_Separator->set_sensitive( nNumberOfCheckedLabelParts > 1 ); + + bool bEnableTextDir = nNumberOfCheckedLabelParts > 0; + m_xBxTextDirection->set_sensitive( bEnableTextDir ); + bool bEnablePlacement = nNumberOfCheckedLabelParts > 0 && m_xLB_LabelPlacement->get_count()>1; + m_xLB_LabelPlacement->set_sensitive( bEnablePlacement ); + } + + m_xPB_NumberFormatForValue->set_sensitive( m_pNumberFormatter && m_xCBNumber->get_active() ); + m_xPB_NumberFormatForPercent->set_sensitive( m_pNumberFormatter && m_xCBPercent->get_active() && m_xCBPercent->get_sensitive() ); + + bool bEnableRotation = (m_xCBNumber->get_active() || m_xCBPercent->get_active() + || m_xCBCategory->get_active() || m_xCBDataSeries->get_active()); + m_xBxOrientation->set_sensitive(bEnableRotation); +} + +void DataLabelResources::FillItemSet( SfxItemSet* rOutAttrs ) const +{ + if( m_xCBNumber->get_active() ) + { + if( !m_bNumberFormatMixedState ) + rOutAttrs->Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, m_nNumberFormatForValue )); + if( !m_bSourceFormatMixedState ) + rOutAttrs->Put( SfxBoolItem( SID_ATTR_NUMBERFORMAT_SOURCE, m_bSourceFormatForValue )); + } + if( m_xCBPercent->get_active() ) + { + if( !m_bPercentFormatMixedState ) + rOutAttrs->Put( SfxUInt32Item( SCHATTR_PERCENT_NUMBERFORMAT_VALUE, m_nNumberFormatForPercent )); + if( !m_bPercentSourceMixedState ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_bSourceFormatForPercent )); + } + + if( m_xCBNumber->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_NUMBER, m_xCBNumber->get_active() ) ); + if( m_xCBPercent->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_PERCENTAGE, m_xCBPercent->get_active() ) ); + if( m_xCBCategory->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_CATEGORY, m_xCBCategory->get_active() ) ); + if( m_xCBSymbol->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_SYMBOL, m_xCBSymbol->get_active()) ); + if( m_xCBDataSeries->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME, m_xCBDataSeries->get_active()) ); + if( m_xCBWrapText->get_state()!= TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_DATADESCR_WRAP_TEXT, m_xCBWrapText->get_active()) ); + if( m_xCBCustomLeaderLines->get_state() != TRISTATE_INDET ) + rOutAttrs->Put(SfxBoolItem( SCHATTR_DATADESCR_CUSTOM_LEADER_LINES, m_xCBCustomLeaderLines->get_active()) ); + + auto const aSep = our_aLBEntryMap[m_xLB_Separator->get_active()]; + rOutAttrs->Put( SfxStringItem( SCHATTR_DATADESCR_SEPARATOR, OUString(aSep)) ); + + std::map< sal_uInt16, sal_Int32 >::const_iterator aIt( m_aListBoxToPlacementMap.find(m_xLB_LabelPlacement->get_active()) ); + if(aIt!=m_aListBoxToPlacementMap.end()) + { + sal_Int32 nValue = aIt->second; + rOutAttrs->Put( SfxInt32Item( SCHATTR_DATADESCR_PLACEMENT, nValue ) ); + } + + if (m_xLB_TextDirection->get_active() != -1) + rOutAttrs->Put( SvxFrameDirectionItem( m_xLB_TextDirection->get_active_id(), EE_PARA_WRITINGDIR ) ); + + if( m_xDC_Dial->IsVisible() ) + { + Degree100 nDegrees = m_xDC_Dial->GetRotation(); + rOutAttrs->Put(SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + } +} + +void DataLabelResources::Reset(const SfxItemSet& rInAttrs) +{ + // default state + m_xCBSymbol->set_sensitive( false ); + + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_NUMBER, *m_xCBNumber ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_PERCENTAGE, *m_xCBPercent ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_CATEGORY, *m_xCBCategory ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_SYMBOL, *m_xCBSymbol ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME, *m_xCBDataSeries ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_WRAP_TEXT, *m_xCBWrapText ); + lcl_setBoolItemToCheckBox( rInAttrs, SCHATTR_DATADESCR_CUSTOM_LEADER_LINES, *m_xCBCustomLeaderLines ); + + m_bNumberFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_SOURCE, m_nNumberFormatForValue, m_bSourceFormatForValue, m_bSourceFormatMixedState ); + m_bPercentFormatMixedState = !lcl_ReadNumberFormatFromItemSet( rInAttrs, SCHATTR_PERCENT_NUMBERFORMAT_VALUE, SCHATTR_PERCENT_NUMBERFORMAT_SOURCE, m_nNumberFormatForPercent, m_bSourceFormatForPercent , m_bPercentSourceMixedState); + + if( const SfxStringItem* pSeparatorItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_SEPARATOR) ) + for(size_t i=0; i < std::size(our_aLBEntryMap); ++i ) + { + if( our_aLBEntryMap[i] == pSeparatorItem->GetValue()) + m_xLB_Separator->set_active( i ); + } + else + m_xLB_Separator->set_active( 0 ); + + if( const SfxInt32Item* pPlacementItem = rInAttrs.GetItemIfSet(SCHATTR_DATADESCR_PLACEMENT) ) + { + sal_Int32 nPlacement = pPlacementItem->GetValue(); + std::map< sal_Int32, sal_uInt16 >::const_iterator aIt( m_aPlacementToListBoxMap.find(nPlacement) ); + if(aIt!=m_aPlacementToListBoxMap.end()) + { + sal_uInt16 nPos = aIt->second; + m_xLB_LabelPlacement->set_active( nPos ); + } + else + m_xLB_LabelPlacement->set_active(-1); + } + else + m_xLB_LabelPlacement->set_active(-1); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs.GetItemIfSet(EE_PARA_WRITINGDIR) ) + m_xLB_TextDirection->set_active_id( pDirectionItem->GetValue() ); + + if( const SdrAngleItem* pAngleItem = rInAttrs.GetItemIfSet( SCHATTR_TEXT_DEGREES ) ) + { + Degree100 nDegrees = pAngleItem->GetValue(); + m_xDC_Dial->SetRotation( nDegrees ); + } + else + m_xDC_Dial->SetRotation( 0_deg100 ); + + EnableControls(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_DataLabel.hxx b/chart2/source/controller/dialogs/res_DataLabel.hxx new file mode 100644 index 000000000..56115b2a7 --- /dev/null +++ b/chart2/source/controller/dialogs/res_DataLabel.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +class SvNumberFormatter; +namespace chart { class TextDirectionListBox; } + +namespace chart +{ + +class DataLabelResources final +{ +public: + DataLabelResources(weld::Builder* pBuilder, weld::Window* pParent, const SfxItemSet& rInAttrs); + ~DataLabelResources(); + + void FillItemSet(SfxItemSet* rOutAttrs) const; + void Reset(const SfxItemSet& rInAttrs); + + void SetNumberFormatter( SvNumberFormatter* pFormatter ); + +private: + std::map< sal_Int32, sal_uInt16 > m_aPlacementToListBoxMap; + std::map< sal_uInt16, sal_Int32 > m_aListBoxToPlacementMap; + + SvNumberFormatter* m_pNumberFormatter; + bool m_bNumberFormatMixedState; + bool m_bPercentFormatMixedState; + sal_uInt32 m_nNumberFormatForValue; + sal_uInt32 m_nNumberFormatForPercent; + + bool m_bSourceFormatMixedState; + bool m_bPercentSourceMixedState; + bool m_bSourceFormatForValue; + bool m_bSourceFormatForPercent; + + weld::Window* m_pWindow; + SfxItemPool* m_pPool; + + std::unique_ptr m_xCBNumber; + std::unique_ptr m_xPB_NumberFormatForValue; + std::unique_ptr m_xCBPercent; + std::unique_ptr m_xPB_NumberFormatForPercent; + std::unique_ptr m_xFT_NumberFormatForPercent; + std::unique_ptr m_xCBCategory; + std::unique_ptr m_xCBSymbol; + std::unique_ptr m_xCBDataSeries; + std::unique_ptr m_xCBWrapText; + + std::unique_ptr m_xLB_Separator; + std::unique_ptr m_xLB_LabelPlacement; + + std::unique_ptr m_xBxOrientation; + std::unique_ptr m_xFT_Dial; + std::unique_ptr m_xNF_Degrees; + + std::unique_ptr m_xBxTextDirection; + + std::unique_ptr m_xLB_TextDirection; + std::unique_ptr m_xDC_Dial; + std::unique_ptr m_xDC_DialWin; + + std::unique_ptr m_xCBCustomLeaderLines; + + DECL_LINK(NumberFormatDialogHdl, weld::Button&, void ); + DECL_LINK(CheckHdl, weld::Toggleable&, void ); + void EnableControls(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_ErrorBar.cxx b/chart2/source/controller/dialogs/res_ErrorBar.cxx new file mode 100644 index 000000000..12fabc659 --- /dev/null +++ b/chart2/source/controller/dialogs/res_ErrorBar.cxx @@ -0,0 +1,716 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CHART_LB_FUNCTION_STD_ERROR 0 +#define CHART_LB_FUNCTION_STD_DEV 1 +#define CHART_LB_FUNCTION_VARIANCE 2 +#define CHART_LB_FUNCTION_ERROR_MARGIN 3 + +using namespace ::com::sun::star; + +namespace +{ +void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pController) +{ + weld::Window* pWeldDialog = pController->getDialog(); + pWeldDialog->set_modal(!bEnable); + pWeldDialog->set_visible(!bEnable); +} + +sal_uInt16 lcl_getLbEntryPosByErrorKind( SvxChartKindError eErrorKind ) +{ + sal_uInt16 nResult = 0; + switch( eErrorKind ) + { + // for these cases select the default in the list box + case SvxChartKindError::NONE: + case SvxChartKindError::Percent: + case SvxChartKindError::Const: + case SvxChartKindError::Range: + nResult = CHART_LB_FUNCTION_STD_DEV; + break; + case SvxChartKindError::Variant: + nResult = CHART_LB_FUNCTION_VARIANCE; + break; + case SvxChartKindError::Sigma: + nResult = CHART_LB_FUNCTION_STD_DEV; + break; + case SvxChartKindError::BigError: + nResult = CHART_LB_FUNCTION_ERROR_MARGIN; + break; + case SvxChartKindError::StdError: + nResult = CHART_LB_FUNCTION_STD_ERROR; + break; + } + return nResult; +} +} // anonymous namespace + +namespace chart +{ + +ErrorBarResources::ErrorBarResources(weld::Builder* pParent, weld::DialogController* pController, + const SfxItemSet& rInAttrs, bool bNoneAvailable, + tErrorBarType eType /* = ERROR_BAR_Y */ ) + : m_eErrorKind( SvxChartKindError::NONE ) + , m_eIndicate( SvxChartIndicate::Both ) + , m_bErrorKindUnique( true ) + , m_bIndicatorUnique( true ) + , m_bRangePosUnique( true ) + , m_bRangeNegUnique( true ) + , m_eErrorBarType( eType ) + , m_nConstDecimalDigits( 1 ) + , m_nConstSpinSize( 1 ) + , m_fPlusValue(0.0) + , m_fMinusValue(0.0) + , m_pController(pController) + , m_pCurrentRangeChoosingField( nullptr ) + , m_bHasInternalDataProvider( true ) + , m_bEnableDataTableDialog( true ) + , m_xRbNone(pParent->weld_radio_button("RB_NONE")) + , m_xRbConst(pParent->weld_radio_button("RB_CONST")) + , m_xRbPercent(pParent->weld_radio_button("RB_PERCENT")) + , m_xRbFunction(pParent->weld_radio_button("RB_FUNCTION")) + , m_xRbRange(pParent->weld_radio_button("RB_RANGE")) + , m_xLbFunction(pParent->weld_combo_box("LB_FUNCTION")) + , m_xFlParameters(pParent->weld_frame("framePARAMETERS")) + , m_xBxPositive(pParent->weld_widget("boxPOSITIVE")) + , m_xMfPositive(pParent->weld_metric_spin_button("MF_POSITIVE", FieldUnit::NONE)) + , m_xEdRangePositive(pParent->weld_entry("ED_RANGE_POSITIVE")) + , m_xIbRangePositive(pParent->weld_button("IB_RANGE_POSITIVE")) + , m_xBxNegative(pParent->weld_widget("boxNEGATIVE")) + , m_xMfNegative(pParent->weld_metric_spin_button("MF_NEGATIVE", FieldUnit::NONE)) + , m_xEdRangeNegative(pParent->weld_entry("ED_RANGE_NEGATIVE")) + , m_xIbRangeNegative(pParent->weld_button("IB_RANGE_NEGATIVE")) + , m_xCbSyncPosNeg(pParent->weld_check_button("CB_SYN_POS_NEG")) + , m_xRbBoth(pParent->weld_radio_button("RB_BOTH")) + , m_xRbPositive(pParent->weld_radio_button("RB_POSITIVE")) + , m_xRbNegative(pParent->weld_radio_button("RB_NEGATIVE")) + , m_xFiBoth(pParent->weld_image("FI_BOTH")) + , m_xFiPositive(pParent->weld_image("FI_POSITIVE")) + , m_xFiNegative(pParent->weld_image("FI_NEGATIVE")) + , m_xUIStringPos(pParent->weld_label("STR_DATA_SELECT_RANGE_FOR_POSITIVE_ERRORBARS")) + , m_xUIStringNeg(pParent->weld_label("STR_DATA_SELECT_RANGE_FOR_NEGATIVE_ERRORBARS")) + , m_xUIStringRbRange(pParent->weld_label("STR_CONTROLTEXT_ERROR_BARS_FROM_DATA")) +{ + if( bNoneAvailable ) + m_xRbNone->connect_toggled(LINK(this, ErrorBarResources, CategoryChosen)); + else + m_xRbNone->hide(); + + m_xRbConst->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbPercent->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbFunction->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xRbRange->connect_toggled( LINK( this, ErrorBarResources, CategoryChosen )); + m_xLbFunction->connect_changed( LINK( this, ErrorBarResources, CategoryChosen2 )); + + m_xCbSyncPosNeg->set_active( false ); + m_xCbSyncPosNeg->connect_toggled( LINK( this, ErrorBarResources, SynchronizePosAndNeg )); + + m_xMfPositive->connect_value_changed( LINK( this, ErrorBarResources, PosValueChanged )); + m_xEdRangePositive->connect_changed( LINK( this, ErrorBarResources, RangeChanged )); + m_xEdRangeNegative->connect_changed( LINK( this, ErrorBarResources, RangeChanged )); + + m_xRbPositive->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + m_xRbNegative->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + m_xRbBoth->connect_toggled( LINK( this, ErrorBarResources, IndicatorChanged )); + + m_xIbRangePositive->connect_clicked( LINK( this, ErrorBarResources, ChooseRange )); + m_xIbRangeNegative->connect_clicked( LINK( this, ErrorBarResources, ChooseRange )); + + FillValueSets(); + Reset( rInAttrs ); +} + +ErrorBarResources::~ErrorBarResources() +{ +} + +void ErrorBarResources::SetErrorBarType( tErrorBarType eNewType ) +{ + if( m_eErrorBarType != eNewType ) + { + m_eErrorBarType = eNewType; + FillValueSets(); + } +} + +void ErrorBarResources::SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) +{ + if( xChartDocument.is()) + { + m_bHasInternalDataProvider = xChartDocument->hasInternalDataProvider(); + uno::Reference< beans::XPropertySet > xProps( static_cast(xChartDocument.get()), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableDataTableDialog") >>= m_bEnableDataTableDialog; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + m_apRangeSelectionHelper.reset( new RangeSelectionHelper( xChartDocument )); + + // has internal data provider => rename "cell range" to "from data" + OSL_ASSERT(m_apRangeSelectionHelper); + if( m_bHasInternalDataProvider ) + { + m_xRbRange->set_label(m_xUIStringRbRange->get_label()); + m_xRbRange->set_help_id(HID_SCH_ERROR_BARS_FROM_DATA); + } + + if( m_xRbRange->get_active()) + { + isRangeFieldContentValid( *m_xEdRangePositive ); + isRangeFieldContentValid( *m_xEdRangeNegative ); + } +} + +void ErrorBarResources::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + if( fMinorStepWidth < 0 ) + fMinorStepWidth = -fMinorStepWidth; + + sal_Int32 nExponent = static_cast< sal_Int32 >( ::rtl::math::approxFloor( log10( fMinorStepWidth ))); + if( nExponent <= 0 ) + { + // one digit precision more + m_nConstDecimalDigits = static_cast< sal_uInt16 >( (-nExponent) + 1 ); + m_nConstSpinSize = 10; + } + else + { + m_nConstDecimalDigits = 0; + m_nConstSpinSize = static_cast< sal_Int64 >( pow( 10.0, static_cast(nExponent) )); + } +} + +void ErrorBarResources::UpdateControlStates() +{ + // function + bool bIsFunction = m_xRbFunction->get_active(); + m_xLbFunction->set_sensitive( bIsFunction ); + + // range buttons + m_xRbRange->set_sensitive( !m_bHasInternalDataProvider || m_bEnableDataTableDialog ); + bool bShowRange = m_xRbRange->get_active(); + bool bCanChooseRange = + ( bShowRange && + m_apRangeSelectionHelper && + m_apRangeSelectionHelper->hasRangeSelection()); + + m_xMfPositive->set_visible( ! bShowRange ); + m_xMfNegative->set_visible( ! bShowRange ); + + // use range but without range chooser => hide controls + m_xEdRangePositive->set_visible( bShowRange && ! m_bHasInternalDataProvider ); + m_xIbRangePositive->set_visible( bCanChooseRange ); + m_xEdRangeNegative->set_visible( bShowRange && ! m_bHasInternalDataProvider ); + m_xIbRangeNegative->set_visible( bCanChooseRange ); + + bool bShowPosNegAndSync = ! (bShowRange && m_bHasInternalDataProvider); + m_xFlParameters->set_visible( bShowPosNegAndSync ); + + // unit for metric fields + bool bIsErrorMargin( + ( m_xRbFunction->get_active()) && + ( m_xLbFunction->get_active() == CHART_LB_FUNCTION_ERROR_MARGIN )); + bool bIsPercentage( m_xRbPercent->get_active() || bIsErrorMargin ); + FieldUnit eFieldUnit = FieldUnit::NONE; + + if( bIsPercentage ) + { + eFieldUnit = FieldUnit::PERCENT; + m_xMfPositive->set_digits( 1 ); + m_xMfPositive->set_increments(10, 100, FieldUnit::NONE); + m_xMfNegative->set_digits( 1 ); + m_xMfNegative->set_increments(10, 100, FieldUnit::NONE); + } + else + { + m_xMfPositive->set_digits( m_nConstDecimalDigits ); + m_xMfPositive->set_increments(m_nConstSpinSize, m_nConstSpinSize * 10, FieldUnit::NONE); + m_xMfNegative->set_digits( m_nConstDecimalDigits ); + m_xMfNegative->set_increments(m_nConstSpinSize, m_nConstSpinSize * 10, FieldUnit::NONE); + } + + sal_Int32 nPlusValue = static_cast< sal_Int32 >( m_fPlusValue * pow(10.0,m_xMfPositive->get_digits()) ); + sal_Int32 nMinusValue = static_cast< sal_Int32 >( m_fMinusValue * pow(10.0,m_xMfNegative->get_digits()) ); + + m_xMfPositive->set_value(nPlusValue, FieldUnit::NONE); + m_xMfNegative->set_value(nMinusValue, FieldUnit::NONE); + + m_xMfPositive->set_unit(eFieldUnit); + m_xMfNegative->set_unit(eFieldUnit); + + // positive and negative value fields + bool bPosEnabled = ( m_xRbPositive->get_active() || m_xRbBoth->get_active()); + bool bNegEnabled = ( m_xRbNegative->get_active() || m_xRbBoth->get_active()); + if( !( bPosEnabled || bNegEnabled )) + { + // all three controls are not checked -> ambiguous state + bPosEnabled = true; + bNegEnabled = true; + } + + // functions with only one parameter + bool bOneParameterCategory = + bIsErrorMargin || m_xRbPercent->get_active(); + if( bOneParameterCategory ) + { + m_xCbSyncPosNeg->set_active(true); + } + + if( m_xCbSyncPosNeg->get_active()) + { + bPosEnabled = true; + bNegEnabled = false; + } + + // all functions except error margin take no arguments + if( m_xRbFunction->get_active() && ( m_xLbFunction->get_active() != CHART_LB_FUNCTION_ERROR_MARGIN )) + { + bPosEnabled = false; + bNegEnabled = false; + } + + // enable/disable pos/neg fields + m_xBxPositive->set_sensitive( bPosEnabled ); + m_xBxNegative->set_sensitive( bNegEnabled ); + if( bShowRange ) + { + m_xEdRangePositive->set_sensitive( bPosEnabled ); + m_xIbRangePositive->set_sensitive( bPosEnabled ); + m_xEdRangeNegative->set_sensitive( bNegEnabled ); + m_xIbRangeNegative->set_sensitive( bNegEnabled ); + } + else + { + m_xMfPositive->set_sensitive( bPosEnabled ); + m_xMfNegative->set_sensitive( bNegEnabled ); + } + + m_xCbSyncPosNeg->set_sensitive( !bOneParameterCategory && ( bPosEnabled || bNegEnabled )); + + // mark invalid entries in the range fields + if( bShowRange && ! m_bHasInternalDataProvider ) + { + isRangeFieldContentValid( *m_xEdRangePositive ); + isRangeFieldContentValid( *m_xEdRangeNegative ); + } +} + +IMPL_LINK_NOARG( ErrorBarResources, CategoryChosen2, weld::ComboBox&, void ) +{ + CategoryChosen(*m_xRbConst); +} + +IMPL_LINK_NOARG( ErrorBarResources, CategoryChosen, weld::Toggleable&, void ) +{ + m_bErrorKindUnique = true; + SvxChartKindError eOldError = m_eErrorKind; + + if( m_xRbNone->get_active()) + m_eErrorKind = SvxChartKindError::NONE; + else if( m_xRbConst->get_active()) + m_eErrorKind = SvxChartKindError::Const; + else if( m_xRbPercent->get_active()) + m_eErrorKind = SvxChartKindError::Percent; + else if( m_xRbRange->get_active()) + m_eErrorKind = SvxChartKindError::Range; + else if( m_xRbFunction->get_active()) + { + switch( m_xLbFunction->get_active()) + { + case CHART_LB_FUNCTION_STD_ERROR: + m_eErrorKind = SvxChartKindError::StdError; break; + case CHART_LB_FUNCTION_STD_DEV: + m_eErrorKind = SvxChartKindError::Sigma; break; + case CHART_LB_FUNCTION_VARIANCE: + m_eErrorKind = SvxChartKindError::Variant; break; + case CHART_LB_FUNCTION_ERROR_MARGIN: + m_eErrorKind = SvxChartKindError::BigError; break; + default: + m_bErrorKindUnique = false; + } + } + else + { + OSL_FAIL( "Unknown category chosen" ); + m_bErrorKindUnique = false; + } + + // changed to range + if( m_eErrorKind == SvxChartKindError::Range && + eOldError != SvxChartKindError::Range ) + { + m_xCbSyncPosNeg->set_active( + (!m_xEdRangePositive->get_text().isEmpty()) && + m_xEdRangePositive->get_text() == m_xEdRangeNegative->get_text()); + } + // changed from range + else if( m_eErrorKind != SvxChartKindError::Range && + eOldError == SvxChartKindError::Range ) + { + m_xCbSyncPosNeg->set_active( m_xMfPositive->get_value(FieldUnit::NONE) == m_xMfNegative->get_value(FieldUnit::NONE)); + } + + UpdateControlStates(); +} + +IMPL_LINK_NOARG(ErrorBarResources, SynchronizePosAndNeg, weld::Toggleable&, void) +{ + UpdateControlStates(); + PosValueChanged( *m_xMfPositive ); +} + +IMPL_LINK_NOARG(ErrorBarResources, PosValueChanged, weld::MetricSpinButton&, void) +{ + if( m_xCbSyncPosNeg->get_active()) + { + if( m_xRbRange->get_active()) + { + m_xEdRangeNegative->set_text( m_xEdRangePositive->get_text()); + m_bRangeNegUnique = m_bRangePosUnique; + } + else + m_xMfNegative->set_value(m_xMfPositive->get_value(FieldUnit::NONE), FieldUnit::NONE); + } +} + +IMPL_LINK_NOARG(ErrorBarResources, IndicatorChanged, weld::Toggleable&, void) +{ + m_bIndicatorUnique = true; + if( m_xRbBoth->get_active()) + m_eIndicate = SvxChartIndicate::Both; + else if( m_xRbPositive->get_active()) + m_eIndicate = SvxChartIndicate::Up; + else if( m_xRbNegative->get_active()) + m_eIndicate = SvxChartIndicate::Down; + else + m_bIndicatorUnique = false; + + UpdateControlStates(); +} + +IMPL_LINK(ErrorBarResources, ChooseRange, weld::Button&, rButton, void) +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (!m_apRangeSelectionHelper) + return; + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + + OUString aUIString; + + if (&rButton == m_xIbRangePositive.get()) + { + m_pCurrentRangeChoosingField = m_xEdRangePositive.get(); + aUIString = m_xUIStringPos->get_label(); + } + else + { + m_pCurrentRangeChoosingField = m_xEdRangeNegative.get(); + aUIString = m_xUIStringNeg->get_label(); + } + + lcl_enableRangeChoosing(true, m_pController); + m_apRangeSelectionHelper->chooseRange( + m_pCurrentRangeChoosingField->get_text(), + aUIString, *this ); +} + +IMPL_LINK( ErrorBarResources, RangeChanged, weld::Entry&, rEdit, void ) +{ + if( &rEdit == m_xEdRangePositive.get() ) + { + m_bRangePosUnique = true; + PosValueChanged( *m_xMfPositive ); + } + else + { + m_bRangeNegUnique = true; + } + + isRangeFieldContentValid( rEdit ); +} + +void ErrorBarResources::Reset(const SfxItemSet& rInAttrs) +{ + const SfxPoolItem *pPoolItem = nullptr; + + // category + m_eErrorKind = SvxChartKindError::NONE; + SfxItemState aState = rInAttrs.GetItemState( SCHATTR_STAT_KIND_ERROR, true, &pPoolItem ); + m_bErrorKindUnique = ( aState != SfxItemState::DONTCARE ); + + if( aState == SfxItemState::SET ) + m_eErrorKind = static_cast(pPoolItem)->GetValue(); + + m_xLbFunction->set_active( lcl_getLbEntryPosByErrorKind( m_eErrorKind )); + + if( m_bErrorKindUnique ) + { + switch( m_eErrorKind ) + { + case SvxChartKindError::NONE: + m_xRbNone->set_active(true); + break; + case SvxChartKindError::Percent: + m_xRbPercent->set_active(true); + break; + case SvxChartKindError::Const: + m_xRbConst->set_active(true); + break; + case SvxChartKindError::StdError: + case SvxChartKindError::Variant: + case SvxChartKindError::Sigma: + case SvxChartKindError::BigError: + m_xRbFunction->set_active(true); + break; + case SvxChartKindError::Range: + m_xRbRange->set_active(true); + break; + } + } + else + { + m_xRbNone->set_active( false ); + m_xRbConst->set_active( false ); + m_xRbPercent->set_active( false ); + m_xRbFunction->set_active( false ); + } + + // parameters + if( const SvxDoubleItem* pDoubleItem = rInAttrs.GetItemIfSet( SCHATTR_STAT_CONSTPLUS ) ) + { + m_fPlusValue = pDoubleItem->GetValue(); + } + + if( const SvxDoubleItem* pStatItem = rInAttrs.GetItemIfSet( SCHATTR_STAT_CONSTMINUS ) ) + { + m_fMinusValue = pStatItem->GetValue(); + + if( m_eErrorKind != SvxChartKindError::Range && + m_fPlusValue == m_fMinusValue ) + m_xCbSyncPosNeg->set_active(true); + } + + // indicator + aState = rInAttrs.GetItemState( SCHATTR_STAT_INDICATE, true, &pPoolItem ); + m_bIndicatorUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET) + m_eIndicate = static_cast(pPoolItem)->GetValue(); + + if( m_bIndicatorUnique ) + { + switch( m_eIndicate ) + { + case SvxChartIndicate::NONE : + // no longer used, use both as default + m_eIndicate = SvxChartIndicate::Both; + [[fallthrough]]; // to BOTH + case SvxChartIndicate::Both : + m_xRbBoth->set_active(true); break; + case SvxChartIndicate::Up : + m_xRbPositive->set_active(true); break; + case SvxChartIndicate::Down : + m_xRbNegative->set_active(true); break; + } + } + else + { + m_xRbBoth->set_active( false ); + m_xRbPositive->set_active( false ); + m_xRbNegative->set_active( false ); + } + + // ranges + aState = rInAttrs.GetItemState( SCHATTR_STAT_RANGE_POS, true, &pPoolItem ); + m_bRangePosUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + OUString sRangePositive = static_cast< const SfxStringItem * >( pPoolItem )->GetValue(); + m_xEdRangePositive->set_text( sRangePositive ); + } + + aState = rInAttrs.GetItemState( SCHATTR_STAT_RANGE_NEG, true, &pPoolItem ); + m_bRangeNegUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + OUString sRangeNegative = static_cast< const SfxStringItem * >( pPoolItem )->GetValue(); + m_xEdRangeNegative->set_text( sRangeNegative ); + if( m_eErrorKind == SvxChartKindError::Range && + !sRangeNegative.isEmpty() && + sRangeNegative == m_xEdRangePositive->get_text() ) + m_xCbSyncPosNeg->set_active(true); + } + + UpdateControlStates(); +} + +void ErrorBarResources::FillItemSet(SfxItemSet& rOutAttrs) const +{ + if( m_bErrorKindUnique ) + rOutAttrs.Put( SvxChartKindErrorItem( m_eErrorKind, SCHATTR_STAT_KIND_ERROR )); + if( m_bIndicatorUnique ) + rOutAttrs.Put( SvxChartIndicateItem( m_eIndicate, SCHATTR_STAT_INDICATE )); + + if( m_bErrorKindUnique ) + { + if( m_eErrorKind == SvxChartKindError::Range ) + { + OUString aPosRange; + OUString aNegRange; + if( m_bHasInternalDataProvider ) + { + // the strings aPosRange/aNegRange have to be set to a non-empty + // arbitrary string to generate error-bar sequences + aPosRange = "x"; + aNegRange = aPosRange; + } + else + { + aPosRange = m_xEdRangePositive->get_text(); + if( m_xCbSyncPosNeg->get_active()) + aNegRange = aPosRange; + else + aNegRange = m_xEdRangeNegative->get_text(); + } + + if( m_bRangePosUnique ) + rOutAttrs.Put( SfxStringItem( SCHATTR_STAT_RANGE_POS, aPosRange )); + if( m_bRangeNegUnique ) + rOutAttrs.Put( SfxStringItem( SCHATTR_STAT_RANGE_NEG, aNegRange )); + } + else if( m_eErrorKind == SvxChartKindError::Const || + m_eErrorKind == SvxChartKindError::Percent || + m_eErrorKind == SvxChartKindError::BigError ) + { + double fPosValue = static_cast< double >( m_xMfPositive->get_value(FieldUnit::NONE)) / + pow( 10.0, m_xMfPositive->get_digits()); + double fNegValue = 0.0; + + if( m_xCbSyncPosNeg->get_active()) + fNegValue = fPosValue; + else + fNegValue = static_cast< double >( m_xMfNegative->get_value(FieldUnit::NONE)) / + pow( 10.0, m_xMfNegative->get_digits()); + + rOutAttrs.Put( SvxDoubleItem( fPosValue, SCHATTR_STAT_CONSTPLUS )); + rOutAttrs.Put( SvxDoubleItem( fNegValue, SCHATTR_STAT_CONSTMINUS )); + } + } + + rOutAttrs.Put( SfxBoolItem( SCHATTR_STAT_ERRORBAR_TYPE , m_eErrorBarType == ERROR_BAR_Y )); +} + +void ErrorBarResources::FillValueSets() +{ + if( m_eErrorBarType == ERROR_BAR_Y ) + { + m_xFiNegative->set_from_icon_name(BMP_INDICATE_DOWN); + m_xFiPositive->set_from_icon_name(BMP_INDICATE_UP); + m_xFiBoth->set_from_icon_name(BMP_INDICATE_BOTH_VERTI); + } + else if( m_eErrorBarType == ERROR_BAR_X ) + { + m_xFiNegative->set_from_icon_name(BMP_INDICATE_LEFT); + m_xFiPositive->set_from_icon_name(BMP_INDICATE_RIGHT); + m_xFiBoth->set_from_icon_name(BMP_INDICATE_BOTH_HORI); + } +} + +void ErrorBarResources::listeningFinished( + const OUString & rNewRange ) +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (!m_apRangeSelectionHelper) + return; + + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + // stop listening + m_apRangeSelectionHelper->stopRangeListening(); + + // change edit field +// if( m_pParentWindow ) +// { +// m_pParentWindow->ToTop(); +// m_pParentWindow->grab_focus(); +// } + + if( m_pCurrentRangeChoosingField ) + { + m_pCurrentRangeChoosingField->set_text( aRange ); + m_pCurrentRangeChoosingField->grab_focus(); + PosValueChanged( *m_xMfPositive ); + } + + m_pCurrentRangeChoosingField = nullptr; + + UpdateControlStates(); + lcl_enableRangeChoosing(false, m_pController); +} + +void ErrorBarResources::disposingRangeSelection() +{ + OSL_ASSERT(m_apRangeSelectionHelper); + if (m_apRangeSelectionHelper) + m_apRangeSelectionHelper->stopRangeListening( false ); +} + +void ErrorBarResources::isRangeFieldContentValid(weld::Entry& rEdit) +{ + OUString aRange( rEdit.get_text()); + bool bIsValid = ( aRange.isEmpty() ) || + ( m_apRangeSelectionHelper && + m_apRangeSelectionHelper->verifyCellRange( aRange )); + + if( bIsValid || !rEdit.get_sensitive()) + { + rEdit.set_message_type(weld::EntryMessageType::Normal); + } + else + { + rEdit.set_message_type(weld::EntryMessageType::Error); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_LegendPosition.cxx b/chart2/source/controller/dialogs/res_LegendPosition.cxx new file mode 100644 index 000000000..c461d20c5 --- /dev/null +++ b/chart2/source/controller/dialogs/res_LegendPosition.cxx @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +//itemset stuff +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LegendPositionResources::LegendPositionResources(weld::Builder& rBuilder) + : m_xRbtLeft(rBuilder.weld_radio_button("left")) + , m_xRbtRight(rBuilder.weld_radio_button("right")) + , m_xRbtTop(rBuilder.weld_radio_button("top")) + , m_xRbtBottom(rBuilder.weld_radio_button("bottom")) +{ + impl_setRadioButtonToggleHdl(); +} + +LegendPositionResources::LegendPositionResources(weld::Builder& rBuilder, + const uno::Reference< uno::XComponentContext >& xCC) + : m_xCC(xCC) + , m_xCbxShow(rBuilder.weld_check_button("show")) + , m_xRbtLeft(rBuilder.weld_radio_button("left")) + , m_xRbtRight(rBuilder.weld_radio_button("right")) + , m_xRbtTop(rBuilder.weld_radio_button("top")) + , m_xRbtBottom(rBuilder.weld_radio_button("bottom")) +{ + m_xCbxShow->connect_toggled( LINK( this, LegendPositionResources, PositionEnableHdl ) ); + impl_setRadioButtonToggleHdl(); +} + +void LegendPositionResources::impl_setRadioButtonToggleHdl() +{ + m_xRbtLeft->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtTop->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtRight->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); + m_xRbtBottom->connect_toggled( LINK( this, LegendPositionResources, PositionChangeHdl ) ); +} + +LegendPositionResources::~LegendPositionResources() +{ +} + +void LegendPositionResources::writeToResources( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + try + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + uno::Reference< beans::XPropertySet > xProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xProp.is() ) + { + //show + bool bShowLegend = false; + xProp->getPropertyValue( "Show" ) >>= bShowLegend; + if (m_xCbxShow) + m_xCbxShow->set_active( bShowLegend ); + PositionEnable(); + + //position + chart2::LegendPosition ePos; + xProp->getPropertyValue( "AnchorPosition" ) >>= ePos; + switch( ePos ) + { + case chart2::LegendPosition_LINE_START: + m_xRbtLeft->set_active(true); + break; + case chart2::LegendPosition_PAGE_START: + m_xRbtTop->set_active(true); + break; + case chart2::LegendPosition_PAGE_END: + m_xRbtBottom->set_active(true); + break; + case chart2::LegendPosition_LINE_END: + default: + m_xRbtRight->set_active(true); + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void LegendPositionResources::writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const +{ + try + { + bool bShowLegend = m_xCbxShow && m_xCbxShow->get_active(); + ChartModel& rModel = *xChartModel; + rtl::Reference< Legend > xProp = LegendHelper::getLegend(rModel, m_xCC, bShowLegend); + if( xProp.is() ) + { + //show + xProp->setPropertyValue( "Show" , uno::Any( bShowLegend )); + + //position + chart2::LegendPosition eNewPos; + css::chart::ChartLegendExpansion eExp = css::chart::ChartLegendExpansion_HIGH; + + if( m_xRbtLeft->get_active() ) + eNewPos = chart2::LegendPosition_LINE_START; + else if( m_xRbtRight->get_active() ) + { + eNewPos = chart2::LegendPosition_LINE_END; + } + else if( m_xRbtTop->get_active() ) + { + eNewPos = chart2::LegendPosition_PAGE_START; + eExp = css::chart::ChartLegendExpansion_WIDE; + } + else if( m_xRbtBottom->get_active() ) + { + eNewPos = chart2::LegendPosition_PAGE_END; + eExp = css::chart::ChartLegendExpansion_WIDE; + } + + xProp->setPropertyValue( "AnchorPosition" , uno::Any( eNewPos )); + xProp->setPropertyValue( "Expansion" , uno::Any( eExp )); + xProp->setPropertyValue( "RelativePosition" , uno::Any()); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +IMPL_LINK_NOARG(LegendPositionResources, PositionEnableHdl, weld::Toggleable&, void) +{ + PositionEnable(); +} + +void LegendPositionResources::PositionEnable() +{ + bool bEnable = !m_xCbxShow || m_xCbxShow->get_active(); + + m_xRbtLeft->set_sensitive( bEnable ); + m_xRbtTop->set_sensitive( bEnable ); + m_xRbtRight->set_sensitive( bEnable ); + m_xRbtBottom->set_sensitive( bEnable ); + + m_aChangeLink.Call(nullptr); +} + +void LegendPositionResources::initFromItemSet( const SfxItemSet& rInAttrs ) +{ + if( const SfxInt32Item* pPosItem = rInAttrs.GetItemIfSet( SCHATTR_LEGEND_POS ) ) + { + chart2::LegendPosition nLegendPosition = static_cast(pPosItem->GetValue()); + switch( nLegendPosition ) + { + case chart2::LegendPosition_LINE_START: + m_xRbtLeft->set_active(true); + break; + case chart2::LegendPosition_PAGE_START: + m_xRbtTop->set_active(true); + break; + case chart2::LegendPosition_LINE_END: + m_xRbtRight->set_active(true); + break; + case chart2::LegendPosition_PAGE_END: + m_xRbtBottom->set_active(true); + break; + default: + break; + } + } + + const SfxBoolItem* pShowItem; + if( m_xCbxShow && (pShowItem = rInAttrs.GetItemIfSet( SCHATTR_LEGEND_SHOW )) ) + { + m_xCbxShow->set_active(pShowItem->GetValue()); + } +} + +void LegendPositionResources::writeToItemSet( SfxItemSet& rOutAttrs ) const +{ + chart2::LegendPosition nLegendPosition = chart2::LegendPosition_LINE_END; + if( m_xRbtLeft->get_active() ) + nLegendPosition = chart2::LegendPosition_LINE_START; + else if( m_xRbtTop->get_active() ) + nLegendPosition = chart2::LegendPosition_PAGE_START; + else if( m_xRbtRight->get_active() ) + nLegendPosition = chart2::LegendPosition_LINE_END; + else if( m_xRbtBottom->get_active() ) + nLegendPosition = chart2::LegendPosition_PAGE_END; + rOutAttrs.Put( SfxInt32Item(SCHATTR_LEGEND_POS, static_cast(nLegendPosition) ) ); + + rOutAttrs.Put( SfxBoolItem(SCHATTR_LEGEND_SHOW, !m_xCbxShow || m_xCbxShow->get_active()) ); +} + +IMPL_LINK (LegendPositionResources, PositionChangeHdl, weld::Toggleable&, rRadio, void) +{ + //for each radio click there are coming two change events + //first uncheck of previous button -> ignore that call + //the second call gives the check of the new button + if( rRadio.get_active() ) + m_aChangeLink.Call(nullptr); +} + +void LegendPositionResources::SetChangeHdl( const Link& rLink ) +{ + m_aChangeLink = rLink; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Titles.cxx b/chart2/source/controller/dialogs/res_Titles.cxx new file mode 100644 index 000000000..59b0f00b9 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Titles.cxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +TitleResources::TitleResources(weld::Builder& rBuilder, bool bShowSecondaryAxesTitle) + : m_xFT_Main(rBuilder.weld_label("labelMainTitle")) + , m_xFT_Sub(rBuilder.weld_label("labelSubTitle")) + , m_xEd_Main(rBuilder.weld_entry("maintitle")) + , m_xEd_Sub(rBuilder.weld_entry("subtitle")) + , m_xFT_XAxis(rBuilder.weld_label("labelPrimaryXaxis")) + , m_xFT_YAxis(rBuilder.weld_label("labelPrimaryYaxis")) + , m_xFT_ZAxis(rBuilder.weld_label("labelPrimaryZaxis")) + , m_xEd_XAxis(rBuilder.weld_entry("primaryXaxis")) + , m_xEd_YAxis(rBuilder.weld_entry("primaryYaxis")) + , m_xEd_ZAxis(rBuilder.weld_entry("primaryZaxis")) + , m_xFT_SecondaryXAxis(rBuilder.weld_label("labelSecondaryXAxis")) + , m_xFT_SecondaryYAxis(rBuilder.weld_label("labelSecondaryYAxis")) + , m_xEd_SecondaryXAxis(rBuilder.weld_entry("secondaryXaxis")) + , m_xEd_SecondaryYAxis(rBuilder.weld_entry("secondaryYaxis")) +{ + m_xFT_SecondaryXAxis->set_visible(bShowSecondaryAxesTitle); + m_xFT_SecondaryYAxis->set_visible(bShowSecondaryAxesTitle); + m_xEd_SecondaryXAxis->set_visible(bShowSecondaryAxesTitle); + m_xEd_SecondaryYAxis->set_visible(bShowSecondaryAxesTitle); +} + +TitleResources::~TitleResources() {} + +void TitleResources::connect_changed(const Link& rLink) +{ + m_xEd_Main->connect_changed(rLink); + m_xEd_Sub->connect_changed(rLink); + m_xEd_XAxis->connect_changed(rLink); + m_xEd_YAxis->connect_changed(rLink); + m_xEd_ZAxis->connect_changed(rLink); + m_xEd_SecondaryXAxis->connect_changed(rLink); + m_xEd_SecondaryYAxis->connect_changed(rLink); +} + +bool TitleResources::get_value_changed_from_saved() const +{ + return m_xEd_Main->get_value_changed_from_saved() || m_xEd_Sub->get_value_changed_from_saved() + || m_xEd_XAxis->get_value_changed_from_saved() + || m_xEd_YAxis->get_value_changed_from_saved() + || m_xEd_ZAxis->get_value_changed_from_saved() + || m_xEd_SecondaryXAxis->get_value_changed_from_saved() + || m_xEd_SecondaryYAxis->get_value_changed_from_saved(); +} + +void TitleResources::save_value() +{ + m_xEd_Main->save_value(); + m_xEd_Sub->save_value(); + m_xEd_XAxis->save_value(); + m_xEd_YAxis->save_value(); + m_xEd_ZAxis->save_value(); + m_xEd_SecondaryXAxis->save_value(); + m_xEd_SecondaryYAxis->save_value(); +} + +void TitleResources::writeToResources(const TitleDialogData& rInput) +{ + m_xFT_Main->set_sensitive(rInput.aPossibilityList[0]); + m_xFT_Sub->set_sensitive(rInput.aPossibilityList[1]); + m_xFT_XAxis->set_sensitive(rInput.aPossibilityList[2]); + m_xFT_YAxis->set_sensitive(rInput.aPossibilityList[3]); + m_xFT_ZAxis->set_sensitive(rInput.aPossibilityList[4]); + m_xFT_SecondaryXAxis->set_sensitive(rInput.aPossibilityList[5]); + m_xFT_SecondaryYAxis->set_sensitive(rInput.aPossibilityList[6]); + + m_xEd_Main->set_sensitive(rInput.aPossibilityList[0]); + m_xEd_Sub->set_sensitive(rInput.aPossibilityList[1]); + m_xEd_XAxis->set_sensitive(rInput.aPossibilityList[2]); + m_xEd_YAxis->set_sensitive(rInput.aPossibilityList[3]); + m_xEd_ZAxis->set_sensitive(rInput.aPossibilityList[4]); + m_xEd_SecondaryXAxis->set_sensitive(rInput.aPossibilityList[5]); + m_xEd_SecondaryYAxis->set_sensitive(rInput.aPossibilityList[6]); + + m_xEd_Main->set_text(rInput.aTextList[0]); + m_xEd_Sub->set_text(rInput.aTextList[1]); + m_xEd_XAxis->set_text(rInput.aTextList[2]); + m_xEd_YAxis->set_text(rInput.aTextList[3]); + m_xEd_ZAxis->set_text(rInput.aTextList[4]); + m_xEd_SecondaryXAxis->set_text(rInput.aTextList[5]); + m_xEd_SecondaryYAxis->set_text(rInput.aTextList[6]); +} + +void TitleResources::readFromResources(TitleDialogData& rOutput) +{ + sal_Bool* pExistenceList = rOutput.aExistenceList.getArray(); + pExistenceList[0] = !m_xEd_Main->get_text().isEmpty(); + pExistenceList[1] = !m_xEd_Sub->get_text().isEmpty(); + pExistenceList[2] = !m_xEd_XAxis->get_text().isEmpty(); + pExistenceList[3] = !m_xEd_YAxis->get_text().isEmpty(); + pExistenceList[4] = !m_xEd_ZAxis->get_text().isEmpty(); + pExistenceList[5] = !m_xEd_SecondaryXAxis->get_text().isEmpty(); + pExistenceList[6] = !m_xEd_SecondaryYAxis->get_text().isEmpty(); + + auto pTextList = rOutput.aTextList.getArray(); + pTextList[0] = m_xEd_Main->get_text(); + pTextList[1] = m_xEd_Sub->get_text(); + pTextList[2] = m_xEd_XAxis->get_text(); + pTextList[3] = m_xEd_YAxis->get_text(); + pTextList[4] = m_xEd_ZAxis->get_text(); + pTextList[5] = m_xEd_SecondaryXAxis->get_text(); + pTextList[6] = m_xEd_SecondaryYAxis->get_text(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Trendline.cxx b/chart2/source/controller/dialogs/res_Trendline.cxx new file mode 100644 index 000000000..647c071b1 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Trendline.cxx @@ -0,0 +1,438 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "res_Trendline.hxx" +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace css::chart2; + +namespace chart +{ + +static void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue ) +{ + Formatter& rFieldFormatter = rFmtField.GetFormatter(); + rFieldFormatter.SetValue(fValue); + rFieldFormatter.SetDefaultValue( fValue ); +} + +TrendlineResources::TrendlineResources(weld::Builder& rBuilder, const SfxItemSet& rInAttrs) + : m_eTrendLineType(SvxChartRegress::Linear) + , m_bTrendLineUnique(true) + , m_pNumFormatter(nullptr) + , m_nNbPoints(0) + , m_xRB_Linear(rBuilder.weld_radio_button("linear")) + , m_xRB_Logarithmic(rBuilder.weld_radio_button("logarithmic")) + , m_xRB_Exponential(rBuilder.weld_radio_button("exponential")) + , m_xRB_Power(rBuilder.weld_radio_button("power")) + , m_xRB_Polynomial(rBuilder.weld_radio_button("polynomial")) + , m_xRB_MovingAverage(rBuilder.weld_radio_button("movingAverage")) + , m_xFI_Linear(rBuilder.weld_image("imageLinear")) + , m_xFI_Logarithmic(rBuilder.weld_image("imageLogarithmic")) + , m_xFI_Exponential(rBuilder.weld_image("imageExponential")) + , m_xFI_Power(rBuilder.weld_image("imagePower")) + , m_xFI_Polynomial(rBuilder.weld_image("imagePolynomial")) + , m_xFI_MovingAverage(rBuilder.weld_image("imageMovingAverage")) + , m_xNF_Degree(rBuilder.weld_spin_button("degree")) + , m_xNF_Period(rBuilder.weld_spin_button("period")) + , m_xEE_Name(rBuilder.weld_entry("entry_name")) + , m_xFmtFld_ExtrapolateForward(rBuilder.weld_formatted_spin_button("extrapolateForward")) + , m_xFmtFld_ExtrapolateBackward(rBuilder.weld_formatted_spin_button("extrapolateBackward")) + , m_xCB_SetIntercept(rBuilder.weld_check_button("setIntercept")) + , m_xFmtFld_InterceptValue(rBuilder.weld_formatted_spin_button("interceptValue")) + , m_xCB_ShowEquation(rBuilder.weld_check_button("showEquation")) + , m_xEE_XName(rBuilder.weld_entry("entry_Xname")) + , m_xEE_YName(rBuilder.weld_entry("entry_Yname")) + , m_xCB_ShowCorrelationCoeff(rBuilder.weld_check_button("showCorrelationCoefficient")) + , m_xCB_RegressionMovingType(rBuilder.weld_combo_box("combo_moving_type")) +{ + FillValueSets(); + + Formatter& rForwardFormatter = m_xFmtFld_ExtrapolateForward->GetFormatter(); + rForwardFormatter.ClearMinValue(); + rForwardFormatter.ClearMaxValue(); + Formatter& rBackwardFormatter = m_xFmtFld_ExtrapolateBackward->GetFormatter(); + rBackwardFormatter.ClearMinValue(); + rBackwardFormatter.ClearMaxValue(); + Formatter& rInterceptFormatter = m_xFmtFld_InterceptValue->GetFormatter(); + rInterceptFormatter.ClearMinValue(); + rInterceptFormatter.ClearMaxValue(); + + Link aLink = LINK(this, TrendlineResources, SelectTrendLine); + m_xRB_Linear->connect_toggled( aLink ); + m_xRB_Logarithmic->connect_toggled( aLink ); + m_xRB_Exponential->connect_toggled( aLink ); + m_xRB_Power->connect_toggled( aLink ); + m_xRB_Polynomial->connect_toggled( aLink ); + m_xRB_MovingAverage->connect_toggled( aLink ); + + Link aLink2 = LINK(this, TrendlineResources, ChangeSpinValue); + m_xNF_Degree->connect_value_changed(aLink2); + m_xNF_Period->connect_value_changed(aLink2); + m_xFmtFld_InterceptValue->connect_value_changed(LINK(this, TrendlineResources, ChangeFormattedValue)); + + m_xCB_ShowEquation->connect_toggled(LINK(this, TrendlineResources, ShowEquation)); + + Reset( rInAttrs ); + UpdateControlStates(); +} + +TrendlineResources::~TrendlineResources() +{} + +IMPL_LINK_NOARG(TrendlineResources, SelectTrendLine, weld::Toggleable&, void) +{ + if (m_xRB_Linear->get_active()) + m_eTrendLineType = SvxChartRegress::Linear; + else if (m_xRB_Logarithmic->get_active()) + m_eTrendLineType = SvxChartRegress::Log; + else if (m_xRB_Exponential->get_active()) + m_eTrendLineType = SvxChartRegress::Exp; + else if (m_xRB_Power->get_active()) + m_eTrendLineType = SvxChartRegress::Power; + else if (m_xRB_Polynomial->get_active()) + m_eTrendLineType = SvxChartRegress::Polynomial; + else if (m_xRB_MovingAverage->get_active()) + m_eTrendLineType = SvxChartRegress::MovingAverage; + m_bTrendLineUnique = true; + + UpdateControlStates(); +} + +void TrendlineResources::Reset( const SfxItemSet& rInAttrs ) +{ + if( const SfxStringItem* pCurveNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_CURVE_NAME ) ) + { + OUString aName = pCurveNameItem->GetValue(); + m_xEE_Name->set_text(aName); + } + else + { + m_xEE_Name->set_text(""); + } + if( const SfxStringItem* pRegressionXNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_XNAME ) ) + { + OUString aName = pRegressionXNameItem->GetValue(); + m_xEE_XName->set_text(aName); + } + else + { + m_xEE_XName->set_text("x"); + } + if( const SfxStringItem* pRegressionYNameItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_YNAME ) ) + { + OUString aName = pRegressionYNameItem->GetValue(); + m_xEE_YName->set_text(aName); + } + else + { + m_xEE_YName->set_text("f(x)"); + } + + const SfxPoolItem* pPoolItem = nullptr; + SfxItemState aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_TYPE, true, &pPoolItem ); + m_bTrendLineUnique = ( aState != SfxItemState::DONTCARE ); + if( aState == SfxItemState::SET ) + { + const SvxChartRegressItem * pItem = dynamic_cast< const SvxChartRegressItem * >( pPoolItem ); + if( pItem ) + { + m_eTrendLineType = pItem->GetValue(); + } + } + + if( const SfxInt32Item* pDegreeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_DEGREE ) ) + { + sal_Int32 nDegree = pDegreeItem->GetValue(); + m_xNF_Degree->set_value( nDegree ); + } + else + { + m_xNF_Degree->set_value( 2 ); + } + + m_xNF_Degree->save_value(); + + if( const SfxInt32Item* pPeriodItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_PERIOD ) ) + { + sal_Int32 nPeriod = pPeriodItem->GetValue(); + m_xNF_Period->set_value( nPeriod ); + } + else + { + m_xNF_Period->set_value( 2 ); + } + + m_xNF_Period->save_value(); + + double nValue = 0.0; + if( const SvxDoubleItem* pForwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) ) + { + nValue = pForwardItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_ExtrapolateForward, nValue); + + nValue = 0.0; + if( const SvxDoubleItem* pBackwardItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) ) + { + nValue = pBackwardItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_ExtrapolateBackward, nValue); + + nValue = 0.0; + if( const SvxDoubleItem* pValueItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_INTERCEPT_VALUE ) ) + { + nValue = pValueItem->GetValue() ; + } + lcl_setValue(*m_xFmtFld_InterceptValue, nValue); + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SET_INTERCEPT, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_SetIntercept->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_SetIntercept->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_EQUATION, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_ShowEquation->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_ShowEquation->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_COEFF, true, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_INDET); + } + else + { + if( aState == SfxItemState::SET ) + m_xCB_ShowCorrelationCoeff->set_active( static_cast< const SfxBoolItem * >( pPoolItem )->GetValue()); + } + + if( const SfxInt32Item* pMovingTypeItem = rInAttrs.GetItemIfSet( SCHATTR_REGRESSION_MOVING_TYPE ) ) + { + sal_Int32 nMovingType = pMovingTypeItem->GetValue(); + if (nMovingType == MovingAverageType::Prior) + m_xCB_RegressionMovingType->set_active(0); + else if (nMovingType == MovingAverageType::Central) + m_xCB_RegressionMovingType->set_active(1); + else if (nMovingType == MovingAverageType::AveragedAbscissa) + m_xCB_RegressionMovingType->set_active(2); + } + else + { + m_xCB_RegressionMovingType->set_active(0); + } + + if( !m_bTrendLineUnique ) + return; + + switch( m_eTrendLineType ) + { + case SvxChartRegress::Linear : + m_xRB_Linear->set_active(true); + break; + case SvxChartRegress::Log : + m_xRB_Logarithmic->set_active(true); + break; + case SvxChartRegress::Exp : + m_xRB_Exponential->set_active(true); + break; + case SvxChartRegress::Power : + m_xRB_Power->set_active(true); + break; + case SvxChartRegress::Polynomial : + m_xRB_Polynomial->set_active(true); + break; + case SvxChartRegress::MovingAverage : + m_xRB_MovingAverage->set_active(true); + break; + default: + break; + } +} + +void TrendlineResources::FillItemSet(SfxItemSet* rOutAttrs) const +{ + if( m_bTrendLineUnique ) + rOutAttrs->Put( SvxChartRegressItem( m_eTrendLineType, SCHATTR_REGRESSION_TYPE )); + + if (m_eTrendLineType == SvxChartRegress::MovingAverage) + { + sal_Int32 nType = MovingAverageType::Prior; + if (m_xCB_RegressionMovingType->get_active() == 1) + nType = MovingAverageType::Central; + else if (m_xCB_RegressionMovingType->get_active() == 2) + nType = MovingAverageType::AveragedAbscissa; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_REGRESSION_MOVING_TYPE, nType)); + } + + if( m_xCB_ShowEquation->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_EQUATION, m_xCB_ShowEquation->get_active() )); + + if( m_xCB_ShowCorrelationCoeff->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_COEFF, m_xCB_ShowCorrelationCoeff->get_active() )); + + OUString aName = m_xEE_Name->get_text(); + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_CURVE_NAME, aName)); + aName = m_xEE_XName->get_text(); + if ( aName.isEmpty() ) + aName = "x"; + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_XNAME, aName)); + aName = m_xEE_YName->get_text(); + if ( aName.isEmpty() ) + aName = "f(x)"; + rOutAttrs->Put(SfxStringItem(SCHATTR_REGRESSION_YNAME, aName)); + + sal_Int32 aDegree = m_xNF_Degree->get_value(); + rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_DEGREE, aDegree ) ); + + sal_Int32 aPeriod = m_xNF_Period->get_value(); + rOutAttrs->Put(SfxInt32Item( SCHATTR_REGRESSION_PERIOD, aPeriod ) ); + + sal_uInt32 nIndex = 0; + double aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateForward->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) ); + + aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_ExtrapolateBackward->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) ); + + if( m_xCB_SetIntercept->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_REGRESSION_SET_INTERCEPT, m_xCB_SetIntercept->get_active() )); + + aValue = 0.0; + (void)m_pNumFormatter->IsNumberFormat(m_xFmtFld_InterceptValue->get_text(),nIndex,aValue); + rOutAttrs->Put(SvxDoubleItem( aValue, SCHATTR_REGRESSION_INTERCEPT_VALUE ) ); +} + +void TrendlineResources::FillValueSets() +{ + m_xFI_Linear->set_from_icon_name(BMP_REGRESSION_LINEAR); + m_xFI_Logarithmic->set_from_icon_name(BMP_REGRESSION_LOG); + m_xFI_Exponential->set_from_icon_name(BMP_REGRESSION_EXP); + m_xFI_Power->set_from_icon_name(BMP_REGRESSION_POWER); + m_xFI_Polynomial->set_from_icon_name(BMP_REGRESSION_POLYNOMIAL); + m_xFI_MovingAverage->set_from_icon_name(BMP_REGRESSION_MOVING_AVERAGE); +} + +void TrendlineResources::UpdateControlStates() +{ + if( m_nNbPoints > 0 ) + { + sal_Int32 nMaxValue = m_nNbPoints - 1 + (m_xCB_SetIntercept->get_active() ? 1 : 0); + m_xNF_Degree->set_max(nMaxValue); + m_xNF_Period->set_max(m_nNbPoints - 1); + } + bool bMovingAverage = ( m_eTrendLineType == SvxChartRegress::MovingAverage ); + bool bPolynomial = ( m_eTrendLineType == SvxChartRegress::Polynomial ); + bool bInterceptAvailable = ( m_eTrendLineType == SvxChartRegress::Linear ) + || ( m_eTrendLineType == SvxChartRegress::Polynomial ) + || ( m_eTrendLineType == SvxChartRegress::Exp ); + m_xFmtFld_ExtrapolateForward->set_sensitive( !bMovingAverage ); + m_xFmtFld_ExtrapolateBackward->set_sensitive( !bMovingAverage ); + m_xCB_SetIntercept->set_sensitive( bInterceptAvailable ); + m_xFmtFld_InterceptValue->set_sensitive( bInterceptAvailable ); + if( bMovingAverage ) + { + m_xCB_ShowEquation->set_state(TRISTATE_FALSE); + m_xCB_ShowCorrelationCoeff->set_state(TRISTATE_FALSE); + } + m_xCB_ShowEquation->set_sensitive( !bMovingAverage ); + m_xCB_ShowCorrelationCoeff->set_sensitive( !bMovingAverage ); + m_xCB_RegressionMovingType->set_sensitive(bMovingAverage); + m_xNF_Period->set_sensitive(bMovingAverage); + m_xNF_Degree->set_sensitive(bPolynomial); + m_xEE_XName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() ); + m_xEE_YName->set_sensitive( !bMovingAverage && m_xCB_ShowEquation->get_active() ); +} + +IMPL_LINK(TrendlineResources, ChangeSpinValue, weld::SpinButton&, rNumericField, void) +{ + if (&rNumericField == m_xNF_Degree.get()) + { + if (!m_xRB_Polynomial->get_active() && m_xNF_Degree->get_value_changed_from_saved()) + { + m_xRB_Polynomial->set_active(true); + SelectTrendLine(*m_xRB_Polynomial); + } + } + else if (&rNumericField == m_xNF_Period.get()) + { + if (!m_xRB_MovingAverage->get_active() && m_xNF_Period->get_value_changed_from_saved()) + { + m_xRB_MovingAverage->set_active(true); + SelectTrendLine(*m_xRB_MovingAverage); + } + } + UpdateControlStates(); +} + +IMPL_LINK_NOARG(TrendlineResources, ChangeFormattedValue, weld::FormattedSpinButton&, void) +{ + if (!m_xCB_SetIntercept->get_active()) + m_xCB_SetIntercept->set_active(true); + UpdateControlStates(); +} + +void TrendlineResources::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumFormatter = pFormatter; + m_xFmtFld_ExtrapolateForward->GetFormatter().SetFormatter(m_pNumFormatter); + m_xFmtFld_ExtrapolateBackward->GetFormatter().SetFormatter(m_pNumFormatter); + m_xFmtFld_InterceptValue->GetFormatter().SetFormatter(m_pNumFormatter); +} + +void TrendlineResources::SetNbPoints( sal_Int32 nNbPoints ) +{ + m_nNbPoints = nNbPoints; + UpdateControlStates(); +} + +IMPL_LINK_NOARG(TrendlineResources, ShowEquation, weld::Toggleable&, void) +{ + m_xEE_XName->set_sensitive(m_xCB_ShowEquation->get_active()); + m_xEE_YName->set_sensitive(m_xCB_ShowEquation->get_active()); + UpdateControlStates(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Trendline.hxx b/chart2/source/controller/dialogs/res_Trendline.hxx new file mode 100644 index 000000000..e520d6da3 --- /dev/null +++ b/chart2/source/controller/dialogs/res_Trendline.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace weld { class Builder; } +namespace weld { class CheckButton; } +namespace weld { class ComboBox; } +namespace weld { class Entry; } +namespace weld { class FormattedSpinButton; } +namespace weld { class Image; } +namespace weld { class RadioButton; } +namespace weld { class SpinButton; } +namespace weld { class Toggleable; } + +class SvNumberFormatter; + +namespace chart +{ + +class TrendlineResources final +{ +public: + TrendlineResources(weld::Builder& rParent, const SfxItemSet& rInAttrs); + ~TrendlineResources(); + + void Reset(const SfxItemSet& rInAttrs); + void FillItemSet(SfxItemSet* rOutAttrs) const; + + void FillValueSets(); + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNbPoints( sal_Int32 nNbPoints ); + +private: + SvxChartRegress m_eTrendLineType; + + bool m_bTrendLineUnique; + + SvNumberFormatter* m_pNumFormatter; + sal_Int32 m_nNbPoints; + + std::unique_ptr m_xRB_Linear; + std::unique_ptr m_xRB_Logarithmic; + std::unique_ptr m_xRB_Exponential; + std::unique_ptr m_xRB_Power; + std::unique_ptr m_xRB_Polynomial; + std::unique_ptr m_xRB_MovingAverage; + + std::unique_ptr m_xFI_Linear; + std::unique_ptr m_xFI_Logarithmic; + std::unique_ptr m_xFI_Exponential; + std::unique_ptr m_xFI_Power; + std::unique_ptr m_xFI_Polynomial; + std::unique_ptr m_xFI_MovingAverage; + + std::unique_ptr m_xNF_Degree; + std::unique_ptr m_xNF_Period; + std::unique_ptr m_xEE_Name; + std::unique_ptr m_xFmtFld_ExtrapolateForward; + std::unique_ptr m_xFmtFld_ExtrapolateBackward; + std::unique_ptr m_xCB_SetIntercept; + std::unique_ptr m_xFmtFld_InterceptValue; + std::unique_ptr m_xCB_ShowEquation; + std::unique_ptr m_xEE_XName; + std::unique_ptr m_xEE_YName; + std::unique_ptr m_xCB_ShowCorrelationCoeff; + std::unique_ptr m_xCB_RegressionMovingType; + + void UpdateControlStates(); + DECL_LINK(SelectTrendLine, weld::Toggleable&, void); + DECL_LINK(ChangeSpinValue, weld::SpinButton&, void); + DECL_LINK(ChangeFormattedValue, weld::FormattedSpinButton&, void); + DECL_LINK(ShowEquation, weld::Toggleable&, void); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx new file mode 100644 index 000000000..c2a84536f --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_3D_SceneAppearance.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ + +struct lcl_ModelProperties +{ + drawing::ShadeMode m_aShadeMode; + sal_Int32 m_nRoundedEdges; + sal_Int32 m_nObjectLines; + ::chart::ThreeDLookScheme m_eScheme; + + lcl_ModelProperties() + : m_aShadeMode(drawing::ShadeMode_FLAT) + , m_nRoundedEdges(-1) + , m_nObjectLines(-1) + , m_eScheme(::chart::ThreeDLookScheme::ThreeDLookScheme_Unknown) + {} +}; + +lcl_ModelProperties lcl_getPropertiesFromModel( rtl::Reference<::chart::ChartModel> const & xModel ) +{ + lcl_ModelProperties aProps; + try + { + rtl::Reference< ::chart::Diagram > xDiagram( ::chart::ChartModelHelper::findDiagram( xModel ) ); + xDiagram->getPropertyValue( "D3DSceneShadeMode" ) >>= aProps.m_aShadeMode; + ::chart::ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, aProps.m_nRoundedEdges, aProps.m_nObjectLines ); + aProps.m_eScheme = ::chart::ThreeDHelper::detectScheme( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aProps; +} + +void lcl_setShadeModeAtModel( rtl::Reference<::chart::ChartModel> const & xModel, drawing::ShadeMode aShadeMode ) +{ + try + { + rtl::Reference< ::chart::Diagram > xDiaProp = ::chart::ChartModelHelper::findDiagram( xModel ); + xDiaProp->setPropertyValue( "D3DSceneShadeMode" , uno::Any( aShadeMode )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +namespace chart +{ + +#define POS_3DSCHEME_SIMPLE 0 +#define POS_3DSCHEME_REALISTIC 1 +#define POS_3DSCHEME_CUSTOM 2 + +ThreeD_SceneAppearance_TabPage::ThreeD_SceneAppearance_TabPage(weld::Container* pParent, + const rtl::Reference<::chart::ChartModel>& xChartModel, + ControllerLockHelper& rControllerLockHelper) + : m_xChartModel(xChartModel) + , m_bUpdateOtherControls(true) + , m_bCommitToModel(true) + , m_rControllerLockHelper(rControllerLockHelper) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneAppearance.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3D_SceneAppearance")) + , m_xLB_Scheme(m_xBuilder->weld_combo_box("LB_SCHEME")) + , m_xCB_Shading(m_xBuilder->weld_check_button("CB_SHADING")) + , m_xCB_ObjectLines(m_xBuilder->weld_check_button("CB_OBJECTLINES")) + , m_xCB_RoundedEdge(m_xBuilder->weld_check_button("CB_ROUNDEDEDGE")) +{ + m_aCustom = m_xLB_Scheme->get_text(POS_3DSCHEME_CUSTOM); + m_xLB_Scheme->remove(POS_3DSCHEME_CUSTOM); + + m_xLB_Scheme->connect_changed( LINK( this, ThreeD_SceneAppearance_TabPage, SelectSchemeHdl ) ); + + m_xCB_RoundedEdge->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines ) ); + m_xCB_Shading->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectShading ) ); + m_xCB_ObjectLines->connect_toggled( LINK( this, ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines ) ); + + initControlsFromModel(); +} + +ThreeD_SceneAppearance_TabPage::~ThreeD_SceneAppearance_TabPage() +{ +} + +void ThreeD_SceneAppearance_TabPage::ActivatePage() +{ + updateScheme(); +} + +void ThreeD_SceneAppearance_TabPage::applyRoundedEdgeAndObjectLinesToModel() +{ + if(!m_bCommitToModel) + return; + + sal_Int32 nObjectLines = -1; + + switch( m_xCB_ObjectLines->get_state()) + { + case TRISTATE_FALSE: + nObjectLines = 0; + break; + case TRISTATE_TRUE: + nObjectLines = 1; + break; + case TRISTATE_INDET: + nObjectLines = -1; + break; + } + + sal_Int32 nCurrentRoundedEdges = -1; + switch( m_xCB_RoundedEdge->get_state() ) + { + case TRISTATE_FALSE: + nCurrentRoundedEdges = 0; + break; + case TRISTATE_TRUE: + nCurrentRoundedEdges = 5; + break; + case TRISTATE_INDET: + nCurrentRoundedEdges = -1; + break; + } + + // locked controllers + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + ThreeDHelper::setRoundedEdgesAndObjectLines( + ::chart::ChartModelHelper::findDiagram( m_xChartModel ), nCurrentRoundedEdges, nObjectLines ); +} + +void ThreeD_SceneAppearance_TabPage::applyShadeModeToModel() +{ + if(!m_bCommitToModel) + return; + + drawing::ShadeMode aShadeMode = drawing::ShadeMode_PHONG; + + switch( m_xCB_Shading->get_state()) + { + case TRISTATE_FALSE: + aShadeMode = drawing::ShadeMode_FLAT; + break; + case TRISTATE_TRUE: + aShadeMode = drawing::ShadeMode_SMOOTH; + break; + case TRISTATE_INDET: + // nothing + break; + } + + lcl_setShadeModeAtModel( m_xChartModel, aShadeMode ); +} + +void ThreeD_SceneAppearance_TabPage::initControlsFromModel() +{ + m_bCommitToModel = false; + m_bUpdateOtherControls = false; + + lcl_ModelProperties aProps( lcl_getPropertiesFromModel( m_xChartModel )); + + if(aProps.m_aShadeMode == drawing::ShadeMode_FLAT) + { + m_xCB_Shading->set_active(false); + } + else if(aProps.m_aShadeMode == drawing::ShadeMode_SMOOTH) + { + m_xCB_Shading->set_active(true); + } + else + { + m_xCB_Shading->set_state(TRISTATE_INDET); + } + + if(aProps.m_nObjectLines == 0) + { + m_xCB_ObjectLines->set_active(false); + } + else if(aProps.m_nObjectLines==1) + { + m_xCB_ObjectLines->set_active(true); + } + else + { + m_xCB_ObjectLines->set_state(TRISTATE_INDET); + } + + if(aProps.m_nRoundedEdges >= 5) + { + m_xCB_RoundedEdge->set_active(true); + } + else if(aProps.m_nRoundedEdges<0) + { + m_xCB_RoundedEdge->set_state(TRISTATE_INDET); + } + else + { + m_xCB_RoundedEdge->set_active(false); + } + m_xCB_RoundedEdge->set_sensitive( !m_xCB_ObjectLines->get_active() ); + + updateScheme(); + + m_bCommitToModel = true; + m_bUpdateOtherControls = true; +} + +void ThreeD_SceneAppearance_TabPage::updateScheme() +{ + lcl_ModelProperties aProps( lcl_getPropertiesFromModel( m_xChartModel )); + + if (m_xLB_Scheme->get_count() == (POS_3DSCHEME_CUSTOM+1)) + m_xLB_Scheme->remove(POS_3DSCHEME_CUSTOM); + switch( aProps.m_eScheme ) + { + case ThreeDLookScheme::ThreeDLookScheme_Simple: + m_xLB_Scheme->set_active( POS_3DSCHEME_SIMPLE ); + break; + case ThreeDLookScheme::ThreeDLookScheme_Realistic: + m_xLB_Scheme->set_active( POS_3DSCHEME_REALISTIC ); + break; + case ThreeDLookScheme::ThreeDLookScheme_Unknown: + { + m_xLB_Scheme->insert_text(POS_3DSCHEME_CUSTOM, m_aCustom); + m_xLB_Scheme->set_active(POS_3DSCHEME_CUSTOM); + } + break; + } +} + +IMPL_LINK_NOARG(ThreeD_SceneAppearance_TabPage, SelectSchemeHdl, weld::ComboBox&, void) +{ + if( !m_bUpdateOtherControls ) + return; + + { + // locked controllers + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + rtl::Reference< Diagram > xDiagram = ::chart::ChartModelHelper::findDiagram( m_xChartModel ); + + if( m_xLB_Scheme->get_active() == POS_3DSCHEME_REALISTIC ) + ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme::ThreeDLookScheme_Realistic ); + else if( m_xLB_Scheme->get_active() == POS_3DSCHEME_SIMPLE ) + ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme::ThreeDLookScheme_Simple ); + else + { + OSL_FAIL( "Invalid Entry selected" ); + } + } + + // update other controls + initControlsFromModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneAppearance_TabPage, SelectShading, weld::Toggleable&, void) +{ + if( !m_bUpdateOtherControls ) + return; + + applyShadeModeToModel(); + updateScheme(); +} + +IMPL_LINK(ThreeD_SceneAppearance_TabPage, SelectRoundedEdgeOrObjectLines, weld::Toggleable&, rCheckBox, void) +{ + if( !m_bUpdateOtherControls ) + return; + + if (&rCheckBox == m_xCB_ObjectLines.get()) + { + m_bUpdateOtherControls = false; + m_xCB_RoundedEdge->set_sensitive( !m_xCB_ObjectLines->get_active() ); + if(!m_xCB_RoundedEdge->get_sensitive()) + m_xCB_RoundedEdge->set_active(false); + m_bUpdateOtherControls = true; + } + + applyRoundedEdgeAndObjectLinesToModel(); + updateScheme(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx new file mode 100644 index 000000000..9d255c076 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneAppearance.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart { class ControllerLockHelper; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +class ThreeD_SceneAppearance_TabPage +{ +public: + ThreeD_SceneAppearance_TabPage( + weld::Container* pParent, + const rtl::Reference<::chart::ChartModel> & xChartModel, + ControllerLockHelper & rControllerLockHelper ); + void ActivatePage(); + ~ThreeD_SceneAppearance_TabPage(); + +private: + DECL_LINK( SelectSchemeHdl, weld::ComboBox&, void ); + DECL_LINK( SelectShading, weld::Toggleable&, void ); + DECL_LINK( SelectRoundedEdgeOrObjectLines, weld::Toggleable&, void ); + + void initControlsFromModel(); + void applyShadeModeToModel(); + void applyRoundedEdgeAndObjectLinesToModel(); + void updateScheme(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + + bool m_bUpdateOtherControls; + bool m_bCommitToModel; + OUString m_aCustom; + + ControllerLockHelper& m_rControllerLockHelper; + + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xLB_Scheme; + std::unique_ptr m_xCB_Shading; + std::unique_ptr m_xCB_ObjectLines; + std::unique_ptr m_xCB_RoundedEdge; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx new file mode 100644 index 000000000..df1d8e907 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.cxx @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_3D_SceneGeometry.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; + +namespace +{ + +void lcl_SetMetricFieldLimits(weld::MetricSpinButton& rField, sal_Int64 nLimit) +{ + rField.set_range(-1*nLimit, nLimit, FieldUnit::DEGREE); +} + +} + +ThreeD_SceneGeometry_TabPage::ThreeD_SceneGeometry_TabPage(weld::Container* pParent, + const rtl::Reference< ::chart::Diagram > & xDiagram, + ControllerLockHelper & rControllerLockHelper) + : m_xDiagram( xDiagram ) + , m_aAngleTimer("chart2 ThreeD_SceneGeometry_TabPage m_aAngleTimer") + , m_aPerspectiveTimer("chart2 ThreeD_SceneGeometry_TabPage m_aPerspectiveTimer") + , m_nXRotation(0) + , m_nYRotation(0) + , m_nZRotation(0) + , m_bAngleChangePending( false ) + , m_bPerspectiveChangePending( false ) + , m_rControllerLockHelper( rControllerLockHelper ) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneGeometry.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3DSceneGeometry")) + , m_xCbxRightAngledAxes(m_xBuilder->weld_check_button("CBX_RIGHT_ANGLED_AXES")) + , m_xMFXRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_X_ROTATION", FieldUnit::DEGREE)) + , m_xMFYRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_Y_ROTATION", FieldUnit::DEGREE)) + , m_xFtZRotation(m_xBuilder->weld_label("FT_Z_ROTATION")) + , m_xMFZRotation(m_xBuilder->weld_metric_spin_button("MTR_FLD_Z_ROTATION", FieldUnit::DEGREE)) + , m_xCbxPerspective(m_xBuilder->weld_check_button("CBX_PERSPECTIVE")) + , m_xMFPerspective(m_xBuilder->weld_metric_spin_button("MTR_FLD_PERSPECTIVE", FieldUnit::PERCENT)) +{ + double fXAngle, fYAngle, fZAngle; + ThreeDHelper::getRotationAngleFromDiagram( m_xDiagram, fXAngle, fYAngle, fZAngle ); + + fXAngle = basegfx::rad2deg(fXAngle); + fYAngle = basegfx::rad2deg(fYAngle); + fZAngle = basegfx::rad2deg(fZAngle); + + OSL_ENSURE( fZAngle>=-90 && fZAngle<=90, "z angle is out of valid range" ); + + lcl_SetMetricFieldLimits( *m_xMFZRotation, 90 ); + + m_nXRotation = NormAngle180( + ::basegfx::fround(fXAngle * pow(10.0, m_xMFXRotation->get_digits()))); + m_nYRotation = NormAngle180( + ::basegfx::fround(-1.0 * fYAngle * pow(10.0, m_xMFYRotation->get_digits()))); + m_nZRotation = NormAngle180( + ::basegfx::fround(-1.0 * fZAngle * pow(10.0, m_xMFZRotation->get_digits()))); + + m_xMFXRotation->set_value(m_nXRotation, FieldUnit::DEGREE); + m_xMFYRotation->set_value(m_nYRotation, FieldUnit::DEGREE); + m_xMFZRotation->set_value(m_nZRotation, FieldUnit::DEGREE); + + const int nTimeout = 4*EDIT_UPDATEDATA_TIMEOUT; + m_aAngleTimer.SetTimeout(nTimeout); + m_aAngleTimer.SetInvokeHandler( LINK( this, ThreeD_SceneGeometry_TabPage, AngleChanged ) ); + + Link aAngleEditedLink( LINK( this, ThreeD_SceneGeometry_TabPage, AngleEdited )); + m_xMFXRotation->connect_value_changed( aAngleEditedLink ); + m_xMFYRotation->connect_value_changed( aAngleEditedLink ); + m_xMFZRotation->connect_value_changed( aAngleEditedLink ); + + drawing::ProjectionMode aProjectionMode = drawing::ProjectionMode_PERSPECTIVE; + m_xDiagram->getPropertyValue( "D3DScenePerspective" ) >>= aProjectionMode; + m_xCbxPerspective->set_active( aProjectionMode == drawing::ProjectionMode_PERSPECTIVE ); + m_xCbxPerspective->connect_toggled( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveToggled )); + + sal_Int32 nPerspectivePercentage = 20; + m_xDiagram->getPropertyValue( "Perspective" ) >>= nPerspectivePercentage; + m_xMFPerspective->set_value(nPerspectivePercentage, FieldUnit::PERCENT); + + m_aPerspectiveTimer.SetTimeout(nTimeout); + m_aPerspectiveTimer.SetInvokeHandler( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveChanged ) ); + m_xMFPerspective->connect_value_changed( LINK( this, ThreeD_SceneGeometry_TabPage, PerspectiveEdited ) ); + m_xMFPerspective->set_sensitive( m_xCbxPerspective->get_active() ); + + //RightAngledAxes + if (ChartTypeHelper::isSupportingRightAngledAxes(DiagramHelper::getChartTypeByIndex(m_xDiagram, 0))) + { + bool bRightAngledAxes = false; + m_xDiagram->getPropertyValue( "RightAngledAxes" ) >>= bRightAngledAxes; + m_xCbxRightAngledAxes->connect_toggled( LINK( this, ThreeD_SceneGeometry_TabPage, RightAngledAxesToggled )); + m_xCbxRightAngledAxes->set_active( bRightAngledAxes ); + RightAngledAxesToggled(*m_xCbxRightAngledAxes); + } + else + { + m_xCbxRightAngledAxes->set_sensitive(false); + } +} + +ThreeD_SceneGeometry_TabPage::~ThreeD_SceneGeometry_TabPage() +{ +} + +void ThreeD_SceneGeometry_TabPage::commitPendingChanges() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + if( m_bAngleChangePending ) + applyAnglesToModel(); + if( m_bPerspectiveChangePending ) + applyPerspectiveToModel(); +} + +void ThreeD_SceneGeometry_TabPage::applyAnglesToModel() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + double fXAngle = 0.0, fYAngle = 0.0, fZAngle = 0.0; + + if (m_xMFZRotation->get_sensitive()) + m_nZRotation = m_xMFZRotation->get_value(FieldUnit::DEGREE); + + fXAngle = double(m_nXRotation)/pow(10.0,m_xMFXRotation->get_digits()); + fYAngle = double(-1.0*m_nYRotation)/pow(10.0,m_xMFYRotation->get_digits()); + fZAngle = double(-1.0*m_nZRotation)/pow(10.0,m_xMFZRotation->get_digits()); + + fXAngle = basegfx::deg2rad(fXAngle); + fYAngle = basegfx::deg2rad(fYAngle); + fZAngle = basegfx::deg2rad(fZAngle); + + ThreeDHelper::setRotationAngleToDiagram( m_xDiagram, fXAngle, fYAngle, fZAngle ); + + m_bAngleChangePending = false; + m_aAngleTimer.Stop(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, AngleEdited, weld::MetricSpinButton&, void) +{ + m_nXRotation = m_xMFXRotation->get_value(FieldUnit::DEGREE); + m_nYRotation = m_xMFYRotation->get_value(FieldUnit::DEGREE); + + m_bAngleChangePending = true; + + m_aAngleTimer.Start(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, AngleChanged, Timer *, void) +{ + applyAnglesToModel(); +} + +void ThreeD_SceneGeometry_TabPage::applyPerspectiveToModel() +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + drawing::ProjectionMode aMode = m_xCbxPerspective->get_active() + ? drawing::ProjectionMode_PERSPECTIVE + : drawing::ProjectionMode_PARALLEL; + + try + { + m_xDiagram->setPropertyValue( "D3DScenePerspective" , uno::Any( aMode )); + m_xDiagram->setPropertyValue( "Perspective" , uno::Any( static_cast(m_xMFPerspective->get_value(FieldUnit::PERCENT)) )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + m_bPerspectiveChangePending = false; + m_aPerspectiveTimer.Stop(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveEdited, weld::MetricSpinButton&, void) +{ + m_bPerspectiveChangePending = true; + m_aPerspectiveTimer.Start(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveChanged, Timer *, void) +{ + applyPerspectiveToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, PerspectiveToggled, weld::Toggleable&, void) +{ + m_xMFPerspective->set_sensitive(m_xCbxPerspective->get_active()); + applyPerspectiveToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneGeometry_TabPage, RightAngledAxesToggled, weld::Toggleable&, void) +{ + ControllerLockHelperGuard aGuard( m_rControllerLockHelper ); + + bool bEnableZ = !m_xCbxRightAngledAxes->get_active(); + m_xFtZRotation->set_sensitive( bEnableZ ); + m_xMFZRotation->set_sensitive( bEnableZ ); + if (!bEnableZ) + { + m_nXRotation = m_xMFXRotation->get_value(FieldUnit::DEGREE); + m_nYRotation = m_xMFYRotation->get_value(FieldUnit::DEGREE); + m_nZRotation = m_xMFZRotation->get_value(FieldUnit::DEGREE); + + m_xMFXRotation->set_value(static_cast(ThreeDHelper::getValueClippedToRange(static_cast(m_nXRotation), ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes())), FieldUnit::DEGREE); + m_xMFYRotation->set_value(static_cast(ThreeDHelper::getValueClippedToRange(static_cast(m_nYRotation), ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes())), FieldUnit::DEGREE); + m_xMFZRotation->set_text(""); + + lcl_SetMetricFieldLimits( *m_xMFXRotation, static_cast(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes())); + lcl_SetMetricFieldLimits( *m_xMFYRotation, static_cast(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes())); + } + else + { + lcl_SetMetricFieldLimits( *m_xMFXRotation, 180 ); + lcl_SetMetricFieldLimits( *m_xMFYRotation, 180 ); + + m_xMFXRotation->set_value(m_nXRotation, FieldUnit::DEGREE); + m_xMFYRotation->set_value(m_nYRotation, FieldUnit::DEGREE); + m_xMFZRotation->set_value(m_nZRotation, FieldUnit::DEGREE); + } + + ThreeDHelper::switchRightAngledAxes( m_xDiagram, m_xCbxRightAngledAxes->get_active() ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx new file mode 100644 index 000000000..4bcdd8ca6 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneGeometry.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace chart { class ControllerLockHelper; } + +namespace chart +{ +class Diagram; + +class ThreeD_SceneGeometry_TabPage +{ +public: + ThreeD_SceneGeometry_TabPage(weld::Container* pWindow, + const rtl::Reference< ::chart::Diagram > & xDiagram, + ControllerLockHelper & rControllerLockHelper); + ~ThreeD_SceneGeometry_TabPage(); + + // has to be called in case the dialog was closed with OK + void commitPendingChanges(); + + // is called by timer to apply changes to model + DECL_LINK( AngleChanged, Timer *, void); + // is called immediately when a field changes + DECL_LINK( AngleEdited, weld::MetricSpinButton&, void ); + + // is called by timer to apply changes to model + DECL_LINK( PerspectiveChanged, Timer *, void); + // is called immediately when a field changes + DECL_LINK( PerspectiveEdited, weld::MetricSpinButton&, void ); + DECL_LINK( PerspectiveToggled, weld::Toggleable&, void ); + DECL_LINK( RightAngledAxesToggled, weld::Toggleable&, void ); + +private: + void applyAnglesToModel(); + void applyPerspectiveToModel(); + + rtl::Reference< ::chart::Diagram > m_xDiagram; + + Timer m_aAngleTimer; + Timer m_aPerspectiveTimer; + + //to keep old values when switching to right angled axes + sal_Int64 m_nXRotation; + sal_Int64 m_nYRotation; + sal_Int64 m_nZRotation; + + bool m_bAngleChangePending; + bool m_bPerspectiveChangePending; + + ControllerLockHelper & m_rControllerLockHelper; + + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xCbxRightAngledAxes; + std::unique_ptr m_xMFXRotation; + std::unique_ptr m_xMFYRotation; + std::unique_ptr m_xFtZRotation; + std::unique_ptr m_xMFZRotation; + std::unique_ptr m_xCbxPerspective; + std::unique_ptr m_xMFPerspective; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx new file mode 100644 index 000000000..abfa395ca --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.cxx @@ -0,0 +1,531 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_3D_SceneIllumination.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace { + +struct LightSource +{ + Color nDiffuseColor; + css::drawing::Direction3D aDirection; + bool bIsEnabled; + + LightSource() : + nDiffuseColor( 0xcccccc ), + aDirection( 1.0, 1.0, -1.0 ), + bIsEnabled( false ) + {} +}; + +} + +struct LightSourceInfo +{ + LightButton* pButton; + LightSource aLightSource; + + LightSourceInfo(); + void initButtonFromSource(); +}; + +LightSourceInfo::LightSourceInfo() + : pButton(nullptr) +{ + aLightSource.nDiffuseColor = Color(0xffffff); // white + aLightSource.aDirection = drawing::Direction3D(1,1,1); + aLightSource.bIsEnabled = false; +} + +void LightSourceInfo::initButtonFromSource() +{ + if (!pButton) + return; + pButton->switchLightOn(aLightSource.bIsEnabled); +} + +namespace +{ + OUString lcl_makeColorName(const Color& rColor) + { + OUString aStr = SvxResId(RID_SVXFLOAT3D_FIX_R) + + OUString::number(rColor.GetRed()) + + " " + + SvxResId(RID_SVXFLOAT3D_FIX_G) + + OUString::number(rColor.GetGreen()) + + " " + + SvxResId(RID_SVXFLOAT3D_FIX_B) + + OUString::number(rColor.GetBlue()); + return aStr; + } + + void lcl_selectColor(ColorListBox& rListBox, const Color& rColor) + { + rListBox.SetNoSelection(); + rListBox.SelectEntry(std::make_pair(rColor, lcl_makeColorName(rColor))); + } + + ::chart::LightSource lcl_getLightSourceFromProperties( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + sal_Int32 nIndex ) + { + ::chart::LightSource aResult; + if( 0 <= nIndex && nIndex < 8 ) + { + OUString aIndex( OUString::number( nIndex + 1 )); + + try + { + xSceneProperties->getPropertyValue( "D3DSceneLightColor" + aIndex ) >>= aResult.nDiffuseColor; + xSceneProperties->getPropertyValue( "D3DSceneLightDirection" + aIndex ) >>= aResult.aDirection; + xSceneProperties->getPropertyValue( "D3DSceneLightOn" + aIndex ) >>= aResult.bIsEnabled; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return aResult; + } + + void lcl_setLightSource( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const ::chart::LightSource & rLightSource, + sal_Int32 nIndex ) + { + if( 0 > nIndex || nIndex >= 8 ) + return; + + OUString aIndex( OUString::number( nIndex + 1 )); + + try + { + xSceneProperties->setPropertyValue( "D3DSceneLightColor" + aIndex, + uno::Any( rLightSource.nDiffuseColor )); + xSceneProperties->setPropertyValue( "D3DSceneLightDirection" + aIndex, + uno::Any( rLightSource.aDirection )); + xSceneProperties->setPropertyValue( "D3DSceneLightOn" + aIndex, + uno::Any( rLightSource.bIsEnabled )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + Color lcl_getAmbientColor( + const uno::Reference< beans::XPropertySet > & xSceneProperties ) + { + Color nResult; + try + { + xSceneProperties->getPropertyValue("D3DSceneAmbientColor") >>= nResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nResult; + } + + void lcl_setAmbientColor( + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const Color & rColor ) + { + try + { + xSceneProperties->setPropertyValue("D3DSceneAmbientColor", + uno::Any( rColor )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +ThreeD_SceneIllumination_TabPage::ThreeD_SceneIllumination_TabPage(weld::Container* pParent, + weld::Window* pTopLevel, + const uno::Reference< beans::XPropertySet > & xSceneProperties, + const rtl::Reference<::chart::ChartModel>& xChartModel) + : m_xSceneProperties( xSceneProperties ) + , m_aTimerTriggeredControllerLock( xChartModel ) + , m_bInCommitToModel( false ) + , m_aModelChangeListener( LINK( this, ThreeD_SceneIllumination_TabPage, fillControlsFromModel ) ) + , m_xChartModel( xChartModel ) + , m_pTopLevel(pTopLevel) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/schart/ui/tp_3D_SceneIllumination.ui")) + , m_xContainer(m_xBuilder->weld_container("tp_3D_SceneIllumination")) + , m_xBtn_Light1(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_1"))) + , m_xBtn_Light2(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_2"))) + , m_xBtn_Light3(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_3"))) + , m_xBtn_Light4(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_4"))) + , m_xBtn_Light5(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_5"))) + , m_xBtn_Light6(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_6"))) + , m_xBtn_Light7(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_7"))) + , m_xBtn_Light8(new LightButton(m_xBuilder->weld_toggle_button("BTN_LIGHT_8"))) + , m_xLB_LightSource(new ColorListBox(m_xBuilder->weld_menu_button("LB_LIGHTSOURCE"), [this]{ return m_pTopLevel; })) + , m_xBtn_LightSource_Color(m_xBuilder->weld_button("BTN_LIGHTSOURCE_COLOR")) + , m_xLB_AmbientLight(new ColorListBox(m_xBuilder->weld_menu_button("LB_AMBIENTLIGHT"), [this]{ return m_pTopLevel; })) + , m_xBtn_AmbientLight_Color(m_xBuilder->weld_button("BTN_AMBIENT_COLOR")) + , m_xHoriScale(m_xBuilder->weld_scale("hori")) + , m_xVertScale(m_xBuilder->weld_scale("vert")) + , m_xBtn_Corner(m_xBuilder->weld_button("corner")) + , m_xPreview(new Svx3DLightControl) + , m_xPreviewWnd(new weld::CustomWeld(*m_xBuilder, "CTL_LIGHT_PREVIEW", *m_xPreview)) + , m_xCtl_Preview(new SvxLightCtl3D(*m_xPreview, *m_xHoriScale, *m_xVertScale, *m_xBtn_Corner)) +{ + m_pLightSourceInfoList.reset(new LightSourceInfo[8]); + m_pLightSourceInfoList[0].pButton = m_xBtn_Light1.get(); + m_pLightSourceInfoList[1].pButton = m_xBtn_Light2.get(); + m_pLightSourceInfoList[2].pButton = m_xBtn_Light3.get(); + m_pLightSourceInfoList[3].pButton = m_xBtn_Light4.get(); + m_pLightSourceInfoList[4].pButton = m_xBtn_Light5.get(); + m_pLightSourceInfoList[5].pButton = m_xBtn_Light6.get(); + m_pLightSourceInfoList[6].pButton = m_xBtn_Light7.get(); + m_pLightSourceInfoList[7].pButton = m_xBtn_Light8.get(); + + fillControlsFromModel(nullptr); + + m_xBtn_Light1->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light2->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light3->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light4->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light5->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light6->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light7->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + m_xBtn_Light8->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl ) ); + + m_xLB_AmbientLight->SetSelectHdl( LINK( this, ThreeD_SceneIllumination_TabPage, SelectColorHdl ) ); + m_xLB_LightSource->SetSelectHdl( LINK( this, ThreeD_SceneIllumination_TabPage, SelectColorHdl ) ); + + m_xBtn_AmbientLight_Color->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ColorDialogHdl ) ); + m_xBtn_LightSource_Color->connect_clicked( LINK( this, ThreeD_SceneIllumination_TabPage, ColorDialogHdl ) ); + + m_xCtl_Preview->SetUserInteractiveChangeCallback( LINK( this, ThreeD_SceneIllumination_TabPage, PreviewChangeHdl ) ); + m_xCtl_Preview->SetUserSelectionChangeCallback( LINK( this, ThreeD_SceneIllumination_TabPage, PreviewSelectHdl ) ); + + ClickLightSourceButtonHdl(*m_xBtn_Light2->get_widget()); + + m_aModelChangeListener.startListening( uno::Reference< util::XModifyBroadcaster >(m_xSceneProperties, uno::UNO_QUERY) ); +} + +ThreeD_SceneIllumination_TabPage::~ThreeD_SceneIllumination_TabPage() +{ +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, fillControlsFromModel, void*, void) +{ + if( m_bInCommitToModel )//don't read own changes + return; + + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + m_pLightSourceInfoList[nL].aLightSource = lcl_getLightSourceFromProperties( m_xSceneProperties, nL ); + for( nL=0; nL<8; nL++) + m_pLightSourceInfoList[nL].initButtonFromSource(); + + lcl_selectColor( *m_xLB_AmbientLight, lcl_getAmbientColor( m_xSceneProperties )); + + updatePreview(); +} + +void ThreeD_SceneIllumination_TabPage::applyLightSourceToModel( sal_uInt32 nLightNumber ) +{ + ControllerLockGuardUNO aGuard( m_xChartModel ); + m_bInCommitToModel = true; + sal_Int32 nIndex( nLightNumber ); + lcl_setLightSource( m_xSceneProperties, m_pLightSourceInfoList[nIndex].aLightSource, nIndex ); + m_bInCommitToModel = false; +} + +void ThreeD_SceneIllumination_TabPage::applyLightSourcesToModel() +{ + m_aTimerTriggeredControllerLock.startTimer(); + ControllerLockGuardUNO aGuard( m_xChartModel ); + for( sal_Int32 nL=0; nL<8; nL++) + applyLightSourceToModel( nL ); + m_aTimerTriggeredControllerLock.startTimer(); +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, PreviewChangeHdl, SvxLightCtl3D*, void) +{ + m_aTimerTriggeredControllerLock.startTimer(); + + //update m_pLightSourceInfoList from preview + const SfxItemSet a3DLightAttributes(m_xCtl_Preview->GetSvx3DLightControl().Get3DAttributes()); + LightSourceInfo* pInfo = &m_pLightSourceInfoList[0]; + + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_1).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_1).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_1).GetValue()); + + pInfo = &m_pLightSourceInfoList[1]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_2).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_2).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_2).GetValue()); + + pInfo = &m_pLightSourceInfoList[2]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_3).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_3).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_3).GetValue()); + + pInfo = &m_pLightSourceInfoList[3]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_4).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_4).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_4).GetValue()); + + pInfo = &m_pLightSourceInfoList[4]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_5).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_5).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_5).GetValue()); + + pInfo = &m_pLightSourceInfoList[5]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_6).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_6).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_6).GetValue()); + + pInfo = &m_pLightSourceInfoList[6]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_7).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_7).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_7).GetValue()); + + pInfo = &m_pLightSourceInfoList[7]; + pInfo->aLightSource.nDiffuseColor = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTCOLOR_8).GetValue(); + pInfo->aLightSource.bIsEnabled = a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTON_8).GetValue(); + pInfo->aLightSource.aDirection = B3DVectorToDirection3D(a3DLightAttributes.Get(SDRATTR_3DSCENE_LIGHTDIRECTION_8).GetValue()); + + applyLightSourcesToModel(); +} + +IMPL_LINK_NOARG(ThreeD_SceneIllumination_TabPage, PreviewSelectHdl, SvxLightCtl3D*, void) +{ + sal_uInt32 nLightNumber = m_xCtl_Preview->GetSvx3DLightControl().GetSelectedLight(); + if(nLightNumber<8) + { + LightButton* pButton = m_pLightSourceInfoList[nLightNumber].pButton; + if(!pButton->get_active()) + ClickLightSourceButtonHdl(*pButton->get_widget()); + + applyLightSourcesToModel(); + } +} + +IMPL_LINK( ThreeD_SceneIllumination_TabPage, ColorDialogHdl, weld::Button&, rButton, void ) +{ + bool bIsAmbientLight = (&rButton == m_xBtn_AmbientLight_Color.get()); + ColorListBox* pListBox = bIsAmbientLight ? m_xLB_AmbientLight.get() : m_xLB_LightSource.get(); + + SvColorDialog aColorDlg; + aColorDlg.SetColor( pListBox->GetSelectEntryColor() ); + if( aColorDlg.Execute(m_pTopLevel) != RET_OK ) + return; + + Color aColor( aColorDlg.GetColor()); + lcl_selectColor( *pListBox, aColor ); + if( bIsAmbientLight ) + { + m_bInCommitToModel = true; + lcl_setAmbientColor( m_xSceneProperties, aColor ); + m_bInCommitToModel = false; + } + else + { + //get active lightsource: + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + pInfo = &m_pLightSourceInfoList[nL]; + if(pInfo->pButton->get_active()) + break; + pInfo = nullptr; + } + if(pInfo) + applyLightSourceToModel( nL ); + } + SelectColorHdl( *pListBox ); +} + +IMPL_LINK( ThreeD_SceneIllumination_TabPage, SelectColorHdl, ColorListBox&, rBox, void ) +{ + ColorListBox* pListBox = &rBox; + if (pListBox == m_xLB_AmbientLight.get()) + { + m_bInCommitToModel = true; + lcl_setAmbientColor( m_xSceneProperties, pListBox->GetSelectEntryColor()); + m_bInCommitToModel = false; + } + else if (pListBox == m_xLB_LightSource.get()) + { + //get active lightsource: + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + pInfo = &m_pLightSourceInfoList[nL]; + if (pInfo->pButton->get_active()) + break; + pInfo = nullptr; + } + if(pInfo) + { + pInfo->aLightSource.nDiffuseColor = pListBox->GetSelectEntryColor(); + applyLightSourceToModel( nL ); + } + } + updatePreview(); +} + +IMPL_LINK(ThreeD_SceneIllumination_TabPage, ClickLightSourceButtonHdl, weld::Button&, rBtn, void) +{ + LightButton* pButton = nullptr; + LightSourceInfo* pInfo = nullptr; + sal_Int32 nL=0; + for( nL=0; nL<8; nL++) + { + if (m_pLightSourceInfoList[nL].pButton->get_widget() == &rBtn) + { + pButton = m_pLightSourceInfoList[nL].pButton; + pInfo = &m_pLightSourceInfoList[nL]; + break; + } + } + + assert(pInfo); + + bool bIsChecked = pInfo->pButton->get_prev_active(); + + ControllerLockGuardUNO aGuard( m_xChartModel ); + for (sal_Int32 i = 0; i < 8; ++i) + { + LightButton* pLightButton = m_pLightSourceInfoList[i].pButton; + if (pLightButton == pButton) + { + pLightButton->set_active(true); + if (!pLightButton->get_widget()->has_focus()) + pLightButton->get_widget()->grab_focus(); + m_pLightSourceInfoList[i].pButton->set_prev_active(true); + } + else + { + pLightButton->set_active(false); + m_pLightSourceInfoList[i].pButton->set_prev_active(false); + } + } + + //update light button + if (bIsChecked) + { + pButton->switchLightOn(!pButton->isLightOn()); + pInfo->aLightSource.bIsEnabled=pButton->isLightOn(); + applyLightSourceToModel( nL ); + } + + //update color list box + lcl_selectColor( *m_xLB_LightSource, pInfo->aLightSource.nDiffuseColor ); + updatePreview(); +} + +void ThreeD_SceneIllumination_TabPage::updatePreview() +{ + SfxItemSet aItemSet(m_xCtl_Preview->GetSvx3DLightControl().Get3DAttributes()); + LightSourceInfo* pInfo = &m_pLightSourceInfoList[0]; + + // AmbientColor + aItemSet.Put(makeSvx3DAmbientcolorItem(m_xLB_AmbientLight->GetSelectEntryColor())); + + aItemSet.Put(makeSvx3DLightcolor1Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff1Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection1Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[1]; + aItemSet.Put(makeSvx3DLightcolor2Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff2Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection2Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[2]; + aItemSet.Put(makeSvx3DLightcolor3Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff3Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection3Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[3]; + aItemSet.Put(makeSvx3DLightcolor4Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff4Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection4Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[4]; + aItemSet.Put(makeSvx3DLightcolor5Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff5Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection5Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[5]; + aItemSet.Put(makeSvx3DLightcolor6Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff6Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection6Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[6]; + aItemSet.Put(makeSvx3DLightcolor7Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff7Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection7Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + pInfo = &m_pLightSourceInfoList[7]; + aItemSet.Put(makeSvx3DLightcolor8Item(pInfo->aLightSource.nDiffuseColor)); + aItemSet.Put(makeSvx3DLightOnOff8Item(pInfo->aLightSource.bIsEnabled)); + aItemSet.Put(makeSvx3DLightDirection8Item(Direction3DToB3DVector(pInfo->aLightSource.aDirection))); + + // set lights and ambient light + m_xCtl_Preview->GetSvx3DLightControl().Set3DAttributes(aItemSet); + + // select light + for(sal_uInt32 a(0); a < 8; a++) + { + if (m_pLightSourceInfoList[a].pButton->get_active()) + { + m_xCtl_Preview->GetSvx3DLightControl().SelectLight(a); + m_xCtl_Preview->CheckSelection(); + break; + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx new file mode 100644 index 000000000..7ad91e225 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_3D_SceneIllumination.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::beans +{ +class XPropertySet; +} + +class ColorListBox; +class LightButton; + +namespace chart +{ +struct LightSourceInfo; +class ChartModel; + +class ThreeD_SceneIllumination_TabPage +{ +public: + ThreeD_SceneIllumination_TabPage( + weld::Container* pParent, weld::Window* pTopLevel, + const css::uno::Reference& xSceneProperties, + const rtl::Reference<::chart::ChartModel>& xChartModel); + ~ThreeD_SceneIllumination_TabPage(); + +private: + DECL_LINK(ClickLightSourceButtonHdl, weld::Button&, void); + DECL_LINK(SelectColorHdl, ColorListBox&, void); + DECL_LINK(ColorDialogHdl, weld::Button&, void); + DECL_LINK(PreviewChangeHdl, SvxLightCtl3D*, void); + DECL_LINK(PreviewSelectHdl, SvxLightCtl3D*, void); + + void updatePreview(); + +private: + DECL_LINK(fillControlsFromModel, void*, void); + + void applyLightSourceToModel(sal_uInt32 nLightNumber); + void applyLightSourcesToModel(); + + std::unique_ptr m_pLightSourceInfoList; + + css::uno::Reference m_xSceneProperties; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + bool m_bInCommitToModel; + + ModifyListenerCallBack m_aModelChangeListener; + rtl::Reference<::chart::ChartModel> m_xChartModel; + + weld::Window* m_pTopLevel; + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xBtn_Light1; + std::unique_ptr m_xBtn_Light2; + std::unique_ptr m_xBtn_Light3; + std::unique_ptr m_xBtn_Light4; + std::unique_ptr m_xBtn_Light5; + std::unique_ptr m_xBtn_Light6; + std::unique_ptr m_xBtn_Light7; + std::unique_ptr m_xBtn_Light8; + std::unique_ptr m_xLB_LightSource; + std::unique_ptr m_xBtn_LightSource_Color; + std::unique_ptr m_xLB_AmbientLight; + std::unique_ptr m_xBtn_AmbientLight_Color; + std::unique_ptr m_xHoriScale; + std::unique_ptr m_xVertScale; + std::unique_ptr m_xBtn_Corner; + std::unique_ptr m_xPreview; + std::unique_ptr m_xPreviewWnd; + std::unique_ptr m_xCtl_Preview; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisLabel.cxx b/chart2/source/controller/dialogs/tp_AxisLabel.cxx new file mode 100644 index 000000000..2f7d0b743 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisLabel.cxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_AxisLabel.hxx" + +#include +#include + +#include +#include +#include +#include + +namespace chart +{ + +SchAxisLabelTabPage::SchAxisLabelTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_axisLabel.ui", "AxisLabelTabPage", &rInAttrs) + , m_bShowStaggeringControls( true ) + , m_nInitialDegrees( 0 ) + , m_bHasInitialDegrees( true ) + , m_bInitialStacking( false ) + , m_bHasInitialStacking( true ) + , m_bComplexCategories( false ) + , m_xCbShowDescription(m_xBuilder->weld_check_button("showlabelsCB")) + , m_xFlOrder(m_xBuilder->weld_label("orderL")) + , m_xRbSideBySide(m_xBuilder->weld_radio_button("tile")) + , m_xRbUpDown(m_xBuilder->weld_radio_button("odd")) + , m_xRbDownUp(m_xBuilder->weld_radio_button("even")) + , m_xRbAuto(m_xBuilder->weld_radio_button("auto")) + , m_xFlTextFlow(m_xBuilder->weld_label("textflowL")) + , m_xCbTextOverlap(m_xBuilder->weld_check_button("overlapCB")) + , m_xCbTextBreak(m_xBuilder->weld_check_button("breakCB")) + , m_xFtABCD(m_xBuilder->weld_label("labelABCD")) + , m_xFlOrient(m_xBuilder->weld_label("labelTextOrient")) + , m_xFtRotate(m_xBuilder->weld_label("degreeL")) + , m_xNfRotate(m_xBuilder->weld_metric_spin_button("OrientDegree", FieldUnit::DEGREE)) + , m_xCbStacked(m_xBuilder->weld_check_button("stackedCB")) + , m_xFtTextDirection(m_xBuilder->weld_label("textdirL")) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("textdirLB"))) + , m_xCtrlDial(new svx::DialControl) + , m_xCtrlDialWin(new weld::CustomWeld(*m_xBuilder, "dialCtrl", *m_xCtrlDial)) +{ + m_xCtrlDial->SetText(m_xFtABCD->get_label()); + m_xCtrlDial->SetLinkedField(m_xNfRotate.get()); + m_xCtrlDialWin->set_sensitive(true); + m_xNfRotate->set_sensitive(true); + m_xCbStacked->set_sensitive(true); + m_xFtRotate->set_sensitive(true); + + m_xCbStacked->connect_toggled(LINK(this, SchAxisLabelTabPage, StackedToggleHdl)); + m_xCbShowDescription->connect_toggled(LINK(this, SchAxisLabelTabPage, ToggleShowLabel)); +} + +SchAxisLabelTabPage::~SchAxisLabelTabPage() +{ + m_xCtrlDialWin.reset(); + m_xCtrlDial.reset(); + m_xLbTextDirection.reset(); +} + +std::unique_ptr SchAxisLabelTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrs) +{ + return std::make_unique(pPage, pController, *rAttrs); +} + +bool SchAxisLabelTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + bool bStacked = false; + if (m_xCbStacked->get_state() != TRISTATE_INDET ) + { + bStacked = m_xCbStacked->get_state() == TRISTATE_TRUE; + if( !m_bHasInitialStacking || (bStacked != m_bInitialStacking) ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_TEXT_STACKED, bStacked ) ); + } + + if( m_xCtrlDial->HasRotation() ) + { + Degree100 nDegrees = bStacked ? 0_deg100 : m_xCtrlDial->GetRotation(); + if( !m_bHasInitialDegrees || (nDegrees != m_nInitialDegrees) ) + rOutAttrs->Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + } + + if( m_bShowStaggeringControls ) + { + SvxChartTextOrder eOrder = SvxChartTextOrder::SideBySide; + bool bRadioButtonChecked = true; + + if( m_xRbUpDown->get_active()) + eOrder = SvxChartTextOrder::UpDown; + else if( m_xRbDownUp->get_active()) + eOrder = SvxChartTextOrder::DownUp; + else if( m_xRbAuto->get_active()) + eOrder = SvxChartTextOrder::Auto; + else if( m_xRbSideBySide->get_active()) + eOrder = SvxChartTextOrder::SideBySide; + else + bRadioButtonChecked = false; + + if( bRadioButtonChecked ) + rOutAttrs->Put( SvxChartTextOrderItem( eOrder, SCHATTR_AXIS_LABEL_ORDER )); + } + + if( m_xCbTextOverlap->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_LABEL_OVERLAP, m_xCbTextOverlap->get_active() ) ); + if( m_xCbTextBreak->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_LABEL_BREAK, m_xCbTextBreak->get_active() ) ); + if( m_xCbShowDescription->get_state() != TRISTATE_INDET ) + rOutAttrs->Put( SfxBoolItem( SCHATTR_AXIS_SHOWDESCR, m_xCbShowDescription->get_active() ) ); + + if (m_xLbTextDirection->get_active() != -1) + rOutAttrs->Put( SvxFrameDirectionItem( m_xLbTextDirection->get_active_id(), EE_PARA_WRITINGDIR ) ); + + return true; +} + +void SchAxisLabelTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + const SfxPoolItem* pPoolItem = nullptr; + + // show description + SfxItemState aState = rInAttrs->GetItemState( SCHATTR_AXIS_SHOWDESCR, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbShowDescription->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbShowDescription->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + m_xCbShowDescription->hide(); + } + + // Rotation as orient item or in degrees ---------- + + // check new degree item + m_nInitialDegrees = 0_deg100; + aState = rInAttrs->GetItemState( SCHATTR_TEXT_DEGREES, false, &pPoolItem ); + if( aState == SfxItemState::SET ) + m_nInitialDegrees = static_cast< const SdrAngleItem * >( pPoolItem )->GetValue(); + + m_bHasInitialDegrees = aState != SfxItemState::DONTCARE; + if( m_bHasInitialDegrees ) + m_xCtrlDial->SetRotation( m_nInitialDegrees ); + else + m_xCtrlDial->SetNoRotation(); + + // check stacked item + m_bInitialStacking = false; + aState = rInAttrs->GetItemState( SCHATTR_TEXT_STACKED, false, &pPoolItem ); + if( aState == SfxItemState::SET ) + m_bInitialStacking = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + + m_bHasInitialStacking = aState != SfxItemState::DONTCARE; + if( m_bHasInitialDegrees ) + m_xCbStacked->set_state(m_bInitialStacking ? TRISTATE_TRUE : TRISTATE_FALSE); + else + m_xCbStacked->set_state(TRISTATE_INDET); + StackedToggleHdl(*m_xCbStacked); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet( EE_PARA_WRITINGDIR ) ) + m_xLbTextDirection->set_active_id( pDirectionItem->GetValue() ); + + // Text overlap ---------- + aState = rInAttrs->GetItemState( SCHATTR_AXIS_LABEL_OVERLAP, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbTextOverlap->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbTextOverlap->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + m_xCbTextOverlap->hide(); + } + + // text break ---------- + aState = rInAttrs->GetItemState( SCHATTR_AXIS_LABEL_BREAK, false, &pPoolItem ); + if( aState == SfxItemState::DONTCARE ) + { + m_xCbTextBreak->set_state( TRISTATE_INDET ); + } + else + { + bool bCheck = false; + if( aState == SfxItemState::SET ) + bCheck = static_cast< const SfxBoolItem * >( pPoolItem )->GetValue(); + m_xCbTextBreak->set_active( bCheck ); + + if( aState != SfxItemState::DEFAULT && aState != SfxItemState::SET ) + { + m_xCbTextBreak->hide(); + if( ! m_xCbTextOverlap->get_visible() ) + m_xFlTextFlow->hide(); + } + } + + // text order ---------- + if( m_bShowStaggeringControls ) + { + if( const SvxChartTextOrderItem* pOrderItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_LABEL_ORDER, false ) ) + { + SvxChartTextOrder eOrder = pOrderItem->GetValue(); + + switch( eOrder ) + { + case SvxChartTextOrder::SideBySide: + m_xRbSideBySide->set_active(true); + break; + case SvxChartTextOrder::UpDown: + m_xRbUpDown->set_active(true); + break; + case SvxChartTextOrder::DownUp: + m_xRbDownUp->set_active(true); + break; + case SvxChartTextOrder::Auto: + m_xRbAuto->set_active(true); + break; + } + } + } + + ToggleShowLabel(*m_xCbShowDescription); +} + +void SchAxisLabelTabPage::ShowStaggeringControls( bool bShowStaggeringControls ) +{ + m_bShowStaggeringControls = bShowStaggeringControls; + + if( !m_bShowStaggeringControls ) + { + m_xRbSideBySide->hide(); + m_xRbUpDown->hide(); + m_xRbDownUp->hide(); + m_xRbAuto->hide(); + m_xFlOrder->hide(); + } +} + +void SchAxisLabelTabPage::SetComplexCategories( bool bComplexCategories ) +{ + m_bComplexCategories = bComplexCategories; +} + +// event handling routines + +IMPL_LINK_NOARG(SchAxisLabelTabPage, StackedToggleHdl, weld::Toggleable&, void) +{ + bool bActive = m_xCbStacked->get_active() && m_xCbStacked->get_sensitive(); + m_xNfRotate->set_sensitive(!bActive); + m_xCtrlDialWin->set_sensitive(!bActive); + m_xCtrlDial->StyleUpdated(); + m_xFtRotate->set_sensitive(!bActive); +} + +IMPL_LINK_NOARG(SchAxisLabelTabPage, ToggleShowLabel, weld::Toggleable&, void) +{ + bool bEnable = ( m_xCbShowDescription->get_state() != TRISTATE_FALSE ); + + m_xCbStacked->set_sensitive(bEnable); + StackedToggleHdl(*m_xCbStacked); + + m_xFlOrder->set_sensitive( bEnable ); + m_xRbSideBySide->set_sensitive( bEnable ); + m_xRbUpDown->set_sensitive( bEnable ); + m_xRbDownUp->set_sensitive( bEnable ); + m_xRbAuto->set_sensitive( bEnable ); + + m_xFlTextFlow->set_sensitive( bEnable ); + m_xCbTextOverlap->set_sensitive( bEnable && !m_bComplexCategories ); + m_xCbTextBreak->set_sensitive( bEnable ); + + m_xFtTextDirection->set_sensitive( bEnable ); + m_xLbTextDirection->set_sensitive( bEnable ); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisLabel.hxx b/chart2/source/controller/dialogs/tp_AxisLabel.hxx new file mode 100644 index 000000000..a94a030fe --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisLabel.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class TextDirectionListBox; } +namespace weld { + class CheckButton; + class CustomWeld; + class Label; + class RadioButton; + class SpinButton; + class ToggleButton; +} + +namespace chart +{ + +class SchAxisLabelTabPage : public SfxTabPage +{ +private: + bool m_bShowStaggeringControls; + + Degree100 m_nInitialDegrees; + bool m_bHasInitialDegrees; /// false = DialControl in tristate + bool m_bInitialStacking; + bool m_bHasInitialStacking; /// false = checkbox in tristate + bool m_bComplexCategories; + + std::unique_ptr m_xCbShowDescription; + std::unique_ptr m_xFlOrder; + std::unique_ptr m_xRbSideBySide; + std::unique_ptr m_xRbUpDown; + std::unique_ptr m_xRbDownUp; + std::unique_ptr m_xRbAuto; + std::unique_ptr m_xFlTextFlow; + std::unique_ptr m_xCbTextOverlap; + std::unique_ptr m_xCbTextBreak; + std::unique_ptr m_xFtABCD; + std::unique_ptr m_xFlOrient; + std::unique_ptr m_xFtRotate; + std::unique_ptr m_xNfRotate; + std::unique_ptr m_xCbStacked; + std::unique_ptr m_xFtTextDirection; + std::unique_ptr m_xLbTextDirection; + std::unique_ptr m_xCtrlDial; + std::unique_ptr m_xCtrlDialWin; + + DECL_LINK(StackedToggleHdl, weld::Toggleable&, void); + DECL_LINK(ToggleShowLabel, weld::Toggleable&, void); + +public: + SchAxisLabelTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchAxisLabelTabPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + + void ShowStaggeringControls( bool bShowStaggeringControls ); + void SetComplexCategories( bool bComplexCategories ); +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisPositions.cxx b/chart2/source/controller/dialogs/tp_AxisPositions.cxx new file mode 100644 index 000000000..75e662fbb --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisPositions.cxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_AxisPositions.hxx" + +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +AxisPositionsTabPage::AxisPositionsTabPage(weld::Container* pPage, weld::DialogController* pController,const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_AxisPositions.ui", "tp_AxisPositions", &rInAttrs) + , m_pNumFormatter(nullptr) + , m_bCrossingAxisIsCategoryAxis(false) + , m_bSupportAxisPositioning(false) + , m_bSupportCategoryPositioning(false) + , m_xFL_AxisLine(m_xBuilder->weld_frame("FL_AXIS_LINE")) + , m_xLB_CrossesAt(m_xBuilder->weld_combo_box("LB_CROSSES_OTHER_AXIS_AT")) + , m_xED_CrossesAt(m_xBuilder->weld_formatted_spin_button("EDT_CROSSES_OTHER_AXIS_AT")) + , m_xED_CrossesAtCategory(m_xBuilder->weld_combo_box( "EDT_CROSSES_OTHER_AXIS_AT_CATEGORY")) + , m_xCB_AxisBetweenCategories(m_xBuilder->weld_check_button("CB_AXIS_BETWEEN_CATEGORIES")) + , m_xFL_Position(m_xBuilder->weld_frame("FL_POSITION")) + , m_xRB_On(m_xBuilder->weld_radio_button("RB_ON")) + , m_xRB_Between(m_xBuilder->weld_radio_button("RB_BETWEEN")) + , m_xFL_Labels(m_xBuilder->weld_frame("FL_LABELS")) + , m_xLB_PlaceLabels(m_xBuilder->weld_combo_box("LB_PLACE_LABELS")) + , m_xED_LabelDistance(m_xBuilder->weld_formatted_spin_button("EDT_AXIS_LABEL_DISTANCE")) + , m_xCB_TicksInner(m_xBuilder->weld_check_button("CB_TICKS_INNER")) + , m_xCB_TicksOuter(m_xBuilder->weld_check_button("CB_TICKS_OUTER")) + , m_xCB_MinorInner(m_xBuilder->weld_check_button("CB_MINOR_INNER")) + , m_xCB_MinorOuter(m_xBuilder->weld_check_button("CB_MINOR_OUTER")) + , m_xBxPlaceTicks(m_xBuilder->weld_widget("boxPLACE_TICKS")) + , m_xLB_PlaceTicks(m_xBuilder->weld_combo_box("LB_PLACE_TICKS")) +{ + m_xLB_CrossesAt->connect_changed(LINK(this, AxisPositionsTabPage, CrossesAtSelectHdl)); + m_xLB_PlaceLabels->connect_changed(LINK(this, AxisPositionsTabPage, PlaceLabelsSelectHdl)); + + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.ClearMinValue(); + rCrossFormatter.ClearMaxValue(); + Formatter& rDistanceFormatter = m_xED_CrossesAt->GetFormatter(); + rDistanceFormatter.ClearMinValue(); + rDistanceFormatter.ClearMaxValue(); +} + +AxisPositionsTabPage::~AxisPositionsTabPage() +{ +} + +std::unique_ptr AxisPositionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool AxisPositionsTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + // axis line + sal_Int32 nPos = m_xLB_CrossesAt->get_active(); + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_POSITION, nPos+1 )); + if( nPos==2 ) + { + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + double fCrossover = rCrossFormatter.GetValue(); + if( m_bCrossingAxisIsCategoryAxis ) + fCrossover = m_xED_CrossesAtCategory->get_active()+1; + rOutAttrs->Put(SvxDoubleItem(fCrossover,SCHATTR_AXIS_POSITION_VALUE)); + } + + // shifted category position + if (m_xFL_Position->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION, m_xRB_Between->get_active())); + + // labels + sal_Int32 nLabelPos = m_xLB_PlaceLabels->get_active(); + if (nLabelPos != -1) + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_LABEL_POSITION, nLabelPos )); + + // tick marks + sal_Int32 nTicks=0; + sal_Int32 nMinorTicks=0; + + if(m_xCB_MinorInner->get_active()) + nMinorTicks|=CHAXIS_MARK_INNER; + if(m_xCB_MinorOuter->get_active()) + nMinorTicks|=CHAXIS_MARK_OUTER; + if(m_xCB_TicksInner->get_active()) + nTicks|=CHAXIS_MARK_INNER; + if(m_xCB_TicksOuter->get_active()) + nTicks|=CHAXIS_MARK_OUTER; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_TICKS,nTicks)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_HELPTICKS,nMinorTicks)); + + sal_Int32 nMarkPos = m_xLB_PlaceTicks->get_active(); + if (nMarkPos != -1) + rOutAttrs->Put( SfxInt32Item( SCHATTR_AXIS_MARK_POSITION, nMarkPos )); + + return true; +} + +void AxisPositionsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + //init and enable controls + m_xED_CrossesAt->set_visible( !m_bCrossingAxisIsCategoryAxis ); + m_xED_CrossesAtCategory->set_visible( m_bCrossingAxisIsCategoryAxis ); + if (m_bCrossingAxisIsCategoryAxis) + { + for( auto const & cat : std::as_const(m_aCategories) ) + m_xED_CrossesAtCategory->append_text(cat); + } + + if( m_xLB_CrossesAt->get_count() > 3 ) + { + if( m_bCrossingAxisIsCategoryAxis ) + m_xLB_CrossesAt->remove(2); + else + m_xLB_CrossesAt->remove(3); + } + + //fill controls + + //axis line + if(SfxInt32Item const * pPositionItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_POSITION)) + { + bool bZero = false; + sal_Int32 nPos = pPositionItem->GetValue(); + if(nPos==0) + { + //switch to value + bZero = true; + nPos = 2; + } + else + nPos--; + + if( nPos < m_xLB_CrossesAt->get_count() ) + m_xLB_CrossesAt->set_active( nPos ); + CrossesAtSelectHdl( *m_xLB_CrossesAt ); + + const SvxDoubleItem* pPosValueItem; + if( (pPosValueItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_POSITION_VALUE)) || bZero ) + { + double fCrossover = 0.0; + if( !bZero ) + fCrossover = pPosValueItem->GetValue(); + if( m_bCrossingAxisIsCategoryAxis ) + m_xED_CrossesAtCategory->set_active( static_cast(::rtl::math::round(fCrossover-1.0)) ); + else + { + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.SetValue(fCrossover); + } + } + else + { + m_xED_CrossesAtCategory->set_active(-1); + m_xED_CrossesAt->set_text(""); + } + } + else + { + m_xLB_CrossesAt->set_active(-1); + m_xED_CrossesAt->set_sensitive( false ); + } + + // shifted category position + const SfxBoolItem* pCatPosItem; + if (m_bSupportCategoryPositioning && (pCatPosItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION))) + { + if (pCatPosItem->GetValue()) + m_xRB_Between->set_active(true); + else + m_xRB_On->set_active(true); + } + else + m_xFL_Position->hide(); + + // Labels + if( const SfxInt32Item* pLabelPosItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_LABEL_POSITION, false) ) + { + sal_Int32 nPos = pLabelPosItem->GetValue(); + if( nPos < m_xLB_PlaceLabels->get_count() ) + m_xLB_PlaceLabels->set_active( nPos ); + } + else + m_xLB_PlaceLabels->set_active(-1); + PlaceLabelsSelectHdl( *m_xLB_PlaceLabels ); + + // Tick marks + tools::Long nTicks = 0, nMinorTicks = 0; + if (const SfxInt32Item* pTicksItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_TICKS)) + nTicks = pTicksItem->GetValue(); + if (const SfxInt32Item* pHelpTicksItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_HELPTICKS)) + nMinorTicks = pHelpTicksItem->GetValue(); + + m_xCB_TicksInner->set_active(bool(nTicks&CHAXIS_MARK_INNER)); + m_xCB_TicksOuter->set_active(bool(nTicks&CHAXIS_MARK_OUTER)); + m_xCB_MinorInner->set_active(bool(nMinorTicks&CHAXIS_MARK_INNER)); + m_xCB_MinorOuter->set_active(bool(nMinorTicks&CHAXIS_MARK_OUTER)); + + // Tick position + if( const SfxInt32Item* pMarkPosItem = rInAttrs->GetItemIfSet( SCHATTR_AXIS_MARK_POSITION, false) ) + { + sal_Int32 nPos = pMarkPosItem->GetValue(); + if( nPos < m_xLB_PlaceTicks->get_count() ) + m_xLB_PlaceTicks->set_active( nPos ); + } + else + m_xLB_PlaceTicks->set_active(-1); + + if( !m_bSupportAxisPositioning ) + { + m_xFL_AxisLine->hide(); + m_xFL_Labels->hide(); + m_xBxPlaceTicks->hide(); + } + else if( !AxisHelper::isAxisPositioningEnabled() ) + { + m_xFL_AxisLine->set_sensitive(false); + m_xFL_Labels->set_sensitive(false); + m_xBxPlaceTicks->set_sensitive(false); + //todo: maybe set a special help id to all those controls + } +} + +DeactivateRC AxisPositionsTabPage::DeactivatePage(SfxItemSet* pItemSet) +{ + if( pItemSet ) + FillItemSet( pItemSet ); + + return DeactivateRC::LeavePage; +} + +void AxisPositionsTabPage::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + m_pNumFormatter = pFormatter; + Formatter& rCrossFormatter = m_xED_CrossesAt->GetFormatter(); + rCrossFormatter.SetFormatter(m_pNumFormatter); + rCrossFormatter.UseInputStringForFormatting(); + + if( const SfxUInt32Item* pNumFormatItem = GetItemSet().GetItemIfSet(SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT) ) + { + sal_uLong nFmt = pNumFormatItem->GetValue(); + rCrossFormatter.SetFormatKey(nFmt); + } +} + +void AxisPositionsTabPage::SetCrossingAxisIsCategoryAxis( bool bCrossingAxisIsCategoryAxis ) +{ + m_bCrossingAxisIsCategoryAxis = bCrossingAxisIsCategoryAxis; +} + +void AxisPositionsTabPage::SetCategories( const css::uno::Sequence< OUString >& rCategories ) +{ + m_aCategories = rCategories; +} + +void AxisPositionsTabPage::SupportAxisPositioning( bool bSupportAxisPositioning ) +{ + m_bSupportAxisPositioning = bSupportAxisPositioning; +} + +void AxisPositionsTabPage::SupportCategoryPositioning( bool bSupportCategoryPositioning ) +{ + m_bSupportCategoryPositioning = bSupportCategoryPositioning; +} + +IMPL_LINK_NOARG(AxisPositionsTabPage, CrossesAtSelectHdl, weld::ComboBox&, void) +{ + sal_Int32 nPos = m_xLB_CrossesAt->get_active(); + m_xED_CrossesAt->set_visible( (nPos==2) && !m_bCrossingAxisIsCategoryAxis ); + m_xED_CrossesAtCategory->set_visible( (nPos==2) && m_bCrossingAxisIsCategoryAxis ); + + if (m_xED_CrossesAt->get_text().isEmpty()) + m_xED_CrossesAt->GetFormatter().SetValue(0.0); + if (m_xED_CrossesAtCategory->get_active() == -1) + m_xED_CrossesAtCategory->set_active(0); + + PlaceLabelsSelectHdl(*m_xLB_PlaceLabels); +} + +IMPL_LINK_NOARG(AxisPositionsTabPage, PlaceLabelsSelectHdl, weld::ComboBox&, void) +{ + sal_Int32 nLabelPos = m_xLB_PlaceLabels->get_active(); + + bool bEnableTickmarkPlacement = (nLabelPos>1); + if( bEnableTickmarkPlacement ) + { + sal_Int32 nAxisPos = m_xLB_CrossesAt->get_active(); + if( nLabelPos-2 == nAxisPos ) + bEnableTickmarkPlacement=false; + } + m_xBxPlaceTicks->set_sensitive(bEnableTickmarkPlacement); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_AxisPositions.hxx b/chart2/source/controller/dialogs/tp_AxisPositions.hxx new file mode 100644 index 000000000..d7f18242d --- /dev/null +++ b/chart2/source/controller/dialogs/tp_AxisPositions.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class AxisPositionsTabPage : public SfxTabPage +{ +public: + AxisPositionsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~AxisPositionsTabPage() override; + + static std::unique_ptr + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + virtual DeactivateRC DeactivatePage(SfxItemSet* pItemSet) override; + + void SetNumFormatter(SvNumberFormatter* pFormatter); + + void SetCrossingAxisIsCategoryAxis(bool bCrossingAxisIsCategoryAxis); + void SetCategories(const css::uno::Sequence& rCategories); + + void SupportAxisPositioning(bool bSupportAxisPositioning); + void SupportCategoryPositioning(bool bSupportCategoryPositioning); + +private: //methods: + DECL_LINK(CrossesAtSelectHdl, weld::ComboBox&, void); + DECL_LINK(PlaceLabelsSelectHdl, weld::ComboBox&, void); + +private: //member: + SvNumberFormatter* m_pNumFormatter; + + bool m_bCrossingAxisIsCategoryAxis; + css::uno::Sequence m_aCategories; + + bool m_bSupportAxisPositioning; + bool m_bSupportCategoryPositioning; + + std::unique_ptr m_xFL_AxisLine; + std::unique_ptr m_xLB_CrossesAt; + std::unique_ptr m_xED_CrossesAt; + std::unique_ptr m_xED_CrossesAtCategory; + std::unique_ptr m_xCB_AxisBetweenCategories; + + std::unique_ptr m_xFL_Position; + std::unique_ptr m_xRB_On; + std::unique_ptr m_xRB_Between; + + std::unique_ptr m_xFL_Labels; + std::unique_ptr m_xLB_PlaceLabels; + std::unique_ptr m_xED_LabelDistance; + + std::unique_ptr m_xCB_TicksInner; + std::unique_ptr m_xCB_TicksOuter; + + std::unique_ptr m_xCB_MinorInner; + std::unique_ptr m_xCB_MinorOuter; + + std::unique_ptr m_xBxPlaceTicks; + std::unique_ptr m_xLB_PlaceTicks; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ChartType.cxx b/chart2/source/controller/dialogs/tp_ChartType.cxx new file mode 100644 index 000000000..7a007f9da --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartType.cxx @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_ChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +ChartTypeTabPage::ChartTypeTabPage(weld::Container* pPage, weld::DialogController* pController, const rtl::Reference<::chart::ChartModel>& xChartModel, + bool bShowDescription) + : OWizardPage(pPage, pController, "modules/schart/ui/tp_ChartType.ui", "tp_ChartType") + , m_pDim3DLookResourceGroup( new Dim3DLookResourceGroup(m_xBuilder.get()) ) + , m_pStackingResourceGroup( new StackingResourceGroup(m_xBuilder.get()) ) + , m_pSplineResourceGroup( new SplineResourceGroup(m_xBuilder.get(), pController->getDialog()) ) + , m_pGeometryResourceGroup( new GeometryResourceGroup(m_xBuilder.get()) ) + , m_pSortByXValuesResourceGroup( new SortByXValuesResourceGroup(m_xBuilder.get()) ) + , m_xChartModel( xChartModel ) + , m_aChartTypeDialogControllerList(0) + , m_pCurrentMainType(nullptr) + , m_nChangingCalls(0) + , m_aTimerTriggeredControllerLock( m_xChartModel ) + , m_xFT_ChooseType(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xMainTypeList(m_xBuilder->weld_tree_view("charttype")) + , m_xSubTypeList(new ValueSet(m_xBuilder->weld_scrolled_window("subtypewin", true))) + , m_xSubTypeListWin(new weld::CustomWeld(*m_xBuilder, "subtype", *m_xSubTypeList)) +{ + Size aSize(m_xSubTypeList->GetDrawingArea()->get_ref_device().LogicToPixel(Size(150, 50), MapMode(MapUnit::MapAppFont))); + m_xSubTypeListWin->set_size_request(aSize.Width(), aSize.Height()); + + if (bShowDescription) + { + m_xFT_ChooseType->show(); + } + else + { + m_xFT_ChooseType->hide(); + } + + SetPageTitle(SchResId(STR_PAGE_CHARTTYPE)); + + m_xMainTypeList->connect_changed(LINK(this, ChartTypeTabPage, SelectMainTypeHdl)); + m_xSubTypeList->SetSelectHdl( LINK( this, ChartTypeTabPage, SelectSubTypeHdl ) ); + + m_xSubTypeList->SetStyle(m_xSubTypeList->GetStyle() | + WB_ITEMBORDER | WB_DOUBLEBORDER | WB_NAMEFIELD | WB_FLATVALUESET | WB_3DLOOK ); + m_xSubTypeList->SetColCount(4); + m_xSubTypeList->SetLineCount(1); + + bool bEnableComplexChartTypes = true; + uno::Reference< beans::XPropertySet > xProps( static_cast(m_xChartModel.get()), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableComplexChartTypes") >>= bEnableComplexChartTypes; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back( + std::make_unique()); + } + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + } + m_aChartTypeDialogControllerList.push_back( + std::make_unique()); + + for (auto const& elem : m_aChartTypeDialogControllerList) + { + m_xMainTypeList->append("", elem->getName(), elem->getImage()); + elem->setChangeListener( this ); + } + + m_xMainTypeList->set_size_request(m_xMainTypeList->get_preferred_size().Width(), -1); + + m_pDim3DLookResourceGroup->setChangeListener( this ); + m_pStackingResourceGroup->setChangeListener( this ); + m_pSplineResourceGroup->setChangeListener( this ); + m_pGeometryResourceGroup->setChangeListener( this ); + m_pSortByXValuesResourceGroup->setChangeListener( this ); +} + +ChartTypeTabPage::~ChartTypeTabPage() +{ + //delete all dialog controller + m_aChartTypeDialogControllerList.clear(); + + //delete all resource helper + m_pDim3DLookResourceGroup.reset(); + m_pStackingResourceGroup.reset(); + m_pSplineResourceGroup.reset(); + m_pGeometryResourceGroup.reset(); + m_pSortByXValuesResourceGroup.reset(); + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); +} + +ChartTypeParameter ChartTypeTabPage::getCurrentParamter() const +{ + ChartTypeParameter aParameter; + aParameter.nSubTypeIndex = static_cast(m_xSubTypeList->GetSelectedItemId()); + m_pDim3DLookResourceGroup->fillParameter( aParameter ); + m_pStackingResourceGroup->fillParameter( aParameter ); + m_pSplineResourceGroup->fillParameter( aParameter ); + m_pGeometryResourceGroup->fillParameter( aParameter ); + m_pSortByXValuesResourceGroup->fillParameter( aParameter ); + return aParameter; +} + +void ChartTypeTabPage::commitToModel( const ChartTypeParameter& rParameter ) +{ + if( !m_pCurrentMainType ) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + m_pCurrentMainType->commitToModel( rParameter, m_xChartModel ); +} + +void ChartTypeTabPage::stateChanged() +{ + if(m_nChangingCalls) + return; + m_nChangingCalls++; + + ChartTypeParameter aParameter( getCurrentParamter() ); + if( m_pCurrentMainType ) + { + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + m_pCurrentMainType->adjustSubTypeAndEnableControls( aParameter ); + } + commitToModel( aParameter ); + + //detect the new ThreeDLookScheme + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + // tdf#124295 - select always a 3D scheme + if (ThreeDLookScheme aThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + aThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Unknown) + aParameter.eThreeDLookScheme = aThreeDLookScheme; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //the controls have to be enabled/disabled accordingly + fillAllControls( aParameter ); + + m_nChangingCalls--; +} + +ChartTypeDialogController* ChartTypeTabPage::getSelectedMainType() +{ + ChartTypeDialogController* pTypeController = nullptr; + auto nM = static_cast< std::vector< ChartTypeDialogController* >::size_type >( + m_xMainTypeList->get_selected_index() ); + if( nMadjustParameterToSubType( aParameter ); + fillAllControls( aParameter, false ); + commitToModel( aParameter ); + } +} + +IMPL_LINK_NOARG(ChartTypeTabPage, SelectMainTypeHdl, weld::TreeView&, void) +{ + selectMainType(); +} + +void ChartTypeTabPage::selectMainType() +{ + ChartTypeParameter aParameter( getCurrentParamter() ); + + if( m_pCurrentMainType ) + { + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + m_pCurrentMainType->hideExtraControls(); + } + + m_pCurrentMainType = getSelectedMainType(); + if( !m_pCurrentMainType ) + return; + + showAllControls(*m_pCurrentMainType); + + m_pCurrentMainType->adjustParameterToMainType( aParameter ); + commitToModel( aParameter ); + //detect the new ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme( ChartModelHelper::findDiagram( m_xChartModel ) ); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls( aParameter ); + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast(getCurrentTemplate().get()), uno::UNO_QUERY ); + m_pCurrentMainType->fillExtraControls(m_xChartModel,xTemplateProps); +} + +void ChartTypeTabPage::showAllControls( ChartTypeDialogController& rTypeController ) +{ + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + + bool bShow = rTypeController.shouldShow_3DLookControl(); + m_pDim3DLookResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_StackingControl(); + m_pStackingResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_SplineControl(); + m_pSplineResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_GeometryControl(); + m_pGeometryResourceGroup->showControls( bShow ); + bShow = rTypeController.shouldShow_SortByXValuesResourceGroup(); + m_pSortByXValuesResourceGroup->showControls( bShow ); + rTypeController.showExtraControls(m_xBuilder.get()); +} + +void ChartTypeTabPage::fillAllControls( const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList ) +{ + m_nChangingCalls++; + if( m_pCurrentMainType && bAlsoResetSubTypeList ) + { + m_pCurrentMainType->fillSubTypeList(*m_xSubTypeList, rParameter); + } + m_xSubTypeList->SelectItem( static_cast( rParameter.nSubTypeIndex) ); + m_pDim3DLookResourceGroup->fillControls( rParameter ); + m_pStackingResourceGroup->fillControls( rParameter ); + m_pSplineResourceGroup->fillControls( rParameter ); + m_pGeometryResourceGroup->fillControls( rParameter ); + m_pSortByXValuesResourceGroup->fillControls( rParameter ); + m_nChangingCalls--; +} + +void ChartTypeTabPage::initializePage() +{ + if( !m_xChartModel.is() ) + return; + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + DiagramHelper::tTemplateWithServiceName aTemplate = + DiagramHelper::getTemplateForDiagram( xDiagram, xChartTypeManager ); + OUString aServiceName( aTemplate.sServiceName ); + + bool bFound = false; + + sal_uInt16 nM=0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if( elem->isSubType(aServiceName) ) + { + bFound = true; + + m_xMainTypeList->select(nM); + showAllControls(*elem); + uno::Reference< beans::XPropertySet > xTemplateProps( static_cast(aTemplate.xChartTypeTemplate.get()), uno::UNO_QUERY ); + ChartTypeParameter aParameter = elem->getChartTypeParameterForService( aServiceName, xTemplateProps ); + m_pCurrentMainType = getSelectedMainType(); + + //set ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme( xDiagram ); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls( aParameter ); + if( m_pCurrentMainType ) + m_pCurrentMainType->fillExtraControls(m_xChartModel,xTemplateProps); + break; + } + ++nM; + } + + if( !bFound ) + { + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + m_pDim3DLookResourceGroup->showControls( false ); + m_pStackingResourceGroup->showControls( false ); + m_pSplineResourceGroup->showControls( false ); + m_pGeometryResourceGroup->showControls( false ); + m_pSortByXValuesResourceGroup->showControls( false ); + } +} + +bool ChartTypeTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + return true; // return false if this page should not be left +} + +rtl::Reference< ChartTypeTemplate > ChartTypeTabPage::getCurrentTemplate() const +{ + if( m_pCurrentMainType && m_xChartModel.is() ) + { + ChartTypeParameter aParameter( getCurrentParamter() ); + m_pCurrentMainType->adjustParameterToSubType( aParameter ); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = m_xChartModel->getTypeManager(); + return m_pCurrentMainType->getCurrentTemplate( aParameter, xChartTypeManager ); + } + return nullptr; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ChartType.hxx b/chart2/source/controller/dialogs/tp_ChartType.hxx new file mode 100644 index 000000000..34ed8abf2 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartType.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include +#include + +#include + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace weld { class CustomWeld; } + +class ValueSet; + +namespace chart +{ + +class Dim3DLookResourceGroup; +class StackingResourceGroup; +class SplineResourceGroup; +class GeometryResourceGroup; +class SortByXValuesResourceGroup; + +class ChartTypeTabPage final : public ResourceChangeListener, public vcl::OWizardPage, public ChartTypeTemplateProvider +{ +public: + ChartTypeTabPage( weld::Container* pPage, weld::DialogController* pController + , const rtl::Reference<::chart::ChartModel>& xChartModel + , bool bShowDescription = true ); + virtual ~ChartTypeTabPage() override; + + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + virtual rtl::Reference< ::chart::ChartTypeTemplate > getCurrentTemplate() const override; + +private: + ChartTypeDialogController* getSelectedMainType(); + void showAllControls( ChartTypeDialogController& rTypeController ); + void fillAllControls( const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList=true ); + ChartTypeParameter getCurrentParamter() const; + + virtual void stateChanged() override; + + void commitToModel( const ChartTypeParameter& rParameter ); + void selectMainType(); + + DECL_LINK(SelectMainTypeHdl, weld::TreeView&, void); + DECL_LINK(SelectSubTypeHdl, ValueSet*, void ); + + std::unique_ptr m_pDim3DLookResourceGroup; + std::unique_ptr m_pStackingResourceGroup; + std::unique_ptr m_pSplineResourceGroup; + std::unique_ptr m_pGeometryResourceGroup; + std::unique_ptr m_pSortByXValuesResourceGroup; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + + std::vector< std::unique_ptr > m_aChartTypeDialogControllerList; + ChartTypeDialogController* m_pCurrentMainType; + + sal_Int32 m_nChangingCalls; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr m_xFT_ChooseType; + std::unique_ptr m_xMainTypeList; + std::unique_ptr m_xSubTypeList; + std::unique_ptr m_xSubTypeListWin; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataLabel.cxx b/chart2/source/controller/dialogs/tp_DataLabel.cxx new file mode 100644 index 000000000..3594e3e8f --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataLabel.cxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_DataLabel.hxx" + +namespace chart +{ + +DataLabelsTabPage::DataLabelsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_DataLabel.ui", "tp_DataLabel", &rInAttrs) + , m_aDataLabelResources(m_xBuilder.get(), pController->getDialog(), rInAttrs) +{ +} + +std::unique_ptr DataLabelsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool DataLabelsTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + m_aDataLabelResources.FillItemSet(rOutAttrs); + return true; +} + +void DataLabelsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_aDataLabelResources.Reset(*rInAttrs); +} + +void DataLabelsTabPage::SetNumberFormatter( SvNumberFormatter* pFormatter ) +{ + m_aDataLabelResources.SetNumberFormatter( pFormatter ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataLabel.hxx b/chart2/source/controller/dialogs/tp_DataLabel.hxx new file mode 100644 index 000000000..200063af9 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataLabel.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "res_DataLabel.hxx" +#include + +class SvNumberFormatter; + +namespace chart +{ +class DataLabelsTabPage : public SfxTabPage +{ +public: + DataLabelsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + + static std::unique_ptr + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + + void SetNumberFormatter(SvNumberFormatter* pFormatter); + + virtual void Reset(const SfxItemSet* rInAttrs) override; + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + +private: + DataLabelResources m_aDataLabelResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataPointOption.cxx b/chart2/source/controller/dialogs/tp_DataPointOption.cxx new file mode 100644 index 000000000..4c8242872 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataPointOption.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_DataPointOption.hxx" + +#include +#include + +namespace chart +{ +DataPointOptionTabPage::DataPointOptionTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_DataPointOption.ui", + "tp_DataPointOption", &rInAttrs) + , m_xCBHideLegendEntry(m_xBuilder->weld_check_button("CB_LEGEND_ENTRY_HIDDEN")) +{ +} + +DataPointOptionTabPage::~DataPointOptionTabPage() {} + +std::unique_ptr DataPointOptionTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool DataPointOptionTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + if (m_xCBHideLegendEntry->get_visible()) + rOutAttrs->Put( + SfxBoolItem(SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, m_xCBHideLegendEntry->get_active())); + + return true; +} + +void DataPointOptionTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SfxBoolItem* pEntryItem + = rInAttrs->GetItemIfSet(SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY)) + { + bool bVal = pEntryItem->GetValue(); + m_xCBHideLegendEntry->set_active(bVal); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataPointOption.hxx b/chart2/source/controller/dialogs/tp_DataPointOption.hxx new file mode 100644 index 000000000..b73a8a609 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataPointOption.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace weld +{ +class CheckButton; +} + +namespace chart +{ +class DataPointOptionTabPage : public SfxTabPage +{ +public: + DataPointOptionTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~DataPointOptionTabPage() override; + + static std::unique_ptr + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr m_xCBHideLegendEntry; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataSource.cxx b/chart2/source/controller/dialogs/tp_DataSource.cxx new file mode 100644 index 000000000..b142825b3 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataSource.cxx @@ -0,0 +1,926 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_DataSource.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DialogModel.hxx" +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +constexpr OUStringLiteral lcl_aLabelRole( u"label" ); + +void lcl_UpdateCurrentRange(weld::TreeView& rOutListBox, const OUString & rRole, + const OUString& rRange) +{ + int nEntry = rOutListBox.get_selected_index(); + if (nEntry != -1) + { + rOutListBox.set_text(nEntry, ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole), 0); + rOutListBox.set_text(nEntry, rRange, 1); + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry)); + pEntry->m_sRole = rRole; + } +} + +bool lcl_UpdateCurrentSeriesName(weld::TreeView& rOutListBox) +{ + int nEntry = rOutListBox.get_selected_index(); + if (nEntry == -1) + return false; + + bool bResult = false; + ::chart::SeriesEntry * pEntry = weld::fromId<::chart::SeriesEntry*>(rOutListBox.get_id(nEntry)); + if (pEntry->m_xDataSeries.is() && pEntry->m_xChartType.is()) + { + OUString aLabel(::chart::DataSeriesHelper::getDataSeriesLabel( + pEntry->m_xDataSeries, + pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel())); + if (!aLabel.isEmpty()) + { + rOutListBox.set_text(nEntry, aLabel); + bResult = true; + } + } + return bResult; +} + +OUString lcl_GetSelectedRole(const weld::TreeView& rRoleListBox, bool bUITranslated = false) +{ + int nEntry = rRoleListBox.get_selected_index(); + if (nEntry != -1) + { + if (bUITranslated) + return rRoleListBox.get_text(nEntry); + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(rRoleListBox.get_id(nEntry)); + return pEntry->m_sRole; + } + return OUString(); +} + +OUString lcl_GetSelectedRolesRange( const weld::TreeView& rRoleListBox ) +{ + OUString aResult; + int nEntry = rRoleListBox.get_selected_index(); + if (nEntry != -1) + aResult = rRoleListBox.get_text(nEntry, 1); + return aResult; +} + +OUString lcl_GetSequenceNameForLabel(const ::chart::SeriesEntry* pEntry) +{ + OUString aResult("values-y"); + if (pEntry && pEntry->m_xChartType.is()) + aResult = pEntry->m_xChartType->getRoleOfSequenceForSeriesLabel(); + return aResult; +} + +void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pDialog) +{ + if (!pDialog) + return; + weld::Dialog* pDlg = pDialog->getDialog(); + pDlg->set_modal(!bEnable); + pDlg->set_visible(!bEnable); +} + +void lcl_addLSequenceToDataSource( + const uno::Reference< chart2::data::XLabeledDataSequence > & xLSequence, + const Reference< ::chart::DataSeries > & xSource ) +{ + if( xSource.is()) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = xSource->getDataSequences2(); + aData.push_back( xLSequence ); + xSource->setData( aData ); + } +} + +uno::Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( + const rtl::Reference< ::chart::DataSeries > & xDataSource ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledDataSeq : xDataSource->getDataSequences2() ) + { + // no values are set but a label exists + if( ! labeledDataSeq->getValues().is() && + labeledDataSeq->getLabel().is()) + { + xResult = labeledDataSeq; + break; + } + } + + return xResult; +} + +} // anonymous namespace + +namespace chart +{ + +DataSourceTabPage::DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController, + DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription /* = false */) + : ::vcl::OWizardPage(pPage, pController, "modules/schart/ui/tp_DataSource.ui", "tp_DataSource") + , m_pTemplateProvider(pTemplateProvider) + , m_rDialogModel(rDialogModel) + , m_pCurrentRangeChoosingField( nullptr ) + , m_bIsDirty( false ) + , m_pTabPageNotifiable(dynamic_cast(pController)) + , m_xFT_CAPTION(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xFT_SERIES(m_xBuilder->weld_label("FT_SERIES")) + , m_xLB_SERIES(m_xBuilder->weld_tree_view("LB_SERIES")) + , m_xBTN_ADD(m_xBuilder->weld_button("BTN_ADD")) + , m_xBTN_REMOVE(m_xBuilder->weld_button("BTN_REMOVE")) + , m_xBTN_UP(m_xBuilder->weld_button("BTN_UP")) + , m_xBTN_DOWN(m_xBuilder->weld_button("BTN_DOWN")) + , m_xFT_ROLE(m_xBuilder->weld_label("FT_ROLE")) + , m_xLB_ROLE(m_xBuilder->weld_tree_view("LB_ROLE")) + , m_xFT_RANGE(m_xBuilder->weld_label("FT_RANGE")) + , m_xEDT_RANGE(m_xBuilder->weld_entry("EDT_RANGE")) + , m_xIMB_RANGE_MAIN(m_xBuilder->weld_button("IMB_RANGE_MAIN")) + , m_xFT_CATEGORIES(m_xBuilder->weld_label("FT_CATEGORIES")) + , m_xFT_DATALABELS(m_xBuilder->weld_label("FT_DATALABELS")) + , m_xEDT_CATEGORIES(m_xBuilder->weld_entry("EDT_CATEGORIES")) + , m_xIMB_RANGE_CAT(m_xBuilder->weld_button("IMB_RANGE_CAT")) +{ + m_xLB_SERIES->set_size_request(m_xLB_SERIES->get_approximate_digit_width() * 25, + m_xLB_SERIES->get_height_rows(10)); + m_xLB_ROLE->set_size_request(m_xLB_ROLE->get_approximate_digit_width() * 60, + m_xLB_ROLE->get_height_rows(5)); + m_xFT_CAPTION->set_visible(!bHideDescription); + + m_aFixedTextRange = m_xFT_RANGE->get_label(); + SetPageTitle(SchResId(STR_OBJECT_DATASERIES_PLURAL)); + + // set handlers + m_xLB_SERIES->connect_changed(LINK(this, DataSourceTabPage, SeriesSelectionChangedHdl)); + m_xLB_ROLE->connect_changed(LINK(this, DataSourceTabPage, RoleSelectionChangedHdl)); + + m_xIMB_RANGE_MAIN->connect_clicked(LINK(this, DataSourceTabPage, MainRangeButtonClickedHdl)); + m_xIMB_RANGE_CAT->connect_clicked(LINK(this, DataSourceTabPage, CategoriesRangeButtonClickedHdl)); + + m_xBTN_ADD->connect_clicked(LINK(this, DataSourceTabPage, AddButtonClickedHdl)); + m_xBTN_REMOVE->connect_clicked(LINK(this, DataSourceTabPage, RemoveButtonClickedHdl)); + + m_xBTN_UP->connect_clicked(LINK(this, DataSourceTabPage, UpButtonClickedHdl)); + m_xBTN_DOWN->connect_clicked(LINK(this, DataSourceTabPage, DownButtonClickedHdl)); + + m_xEDT_RANGE->connect_changed(LINK(this, DataSourceTabPage, RangeModifiedHdl)); + m_xEDT_CATEGORIES->connect_changed(LINK( this, DataSourceTabPage, RangeModifiedHdl)); + + // init controls + std::vector aWidths { o3tl::narrowing(m_xLB_ROLE->get_approximate_digit_width() * 20) }; + m_xLB_ROLE->set_column_fixed_widths(aWidths); + m_xLB_ROLE->show(); + + updateControlsFromDialogModel(); + + // select first series + if (m_xLB_SERIES->n_children()) + m_xLB_SERIES->select(0); +} + +void DataSourceTabPage::InsertRoleLBEntry(const OUString& rRole, const OUString& rRange) +{ + m_aEntries.emplace_back(new SeriesEntry); + SeriesEntry* pEntry = m_aEntries.back().get(); + pEntry->m_sRole = rRole; + m_xLB_ROLE->append(weld::toId(pEntry), + ::chart::DialogModel::ConvertRoleFromInternalToUI(rRole)); + m_xLB_ROLE->set_text(m_xLB_ROLE->n_children() - 1, rRange, 1); +} + +DataSourceTabPage::~DataSourceTabPage() +{ +} + +void DataSourceTabPage::Activate() +{ + OWizardPage::Activate(); + updateControlsFromDialogModel(); + m_xLB_SERIES->grab_focus(); +} + +void DataSourceTabPage::initializePage() +{ +} + +void DataSourceTabPage::Deactivate() +{ + commitPage(); + vcl::OWizardPage::Deactivate(); +} + +void DataSourceTabPage::commitPage() +{ + commitPage(::vcl::WizardTypes::eFinish); +} + +bool DataSourceTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + //ranges may have been edited in the meanwhile (dirty is true in that case here) + if( isValid() ) + { + updateModelFromControl(); + return true; //return false if this page should not be left + } + else + return false; +} + +bool DataSourceTabPage::isRangeFieldContentValid(weld::Entry& rEdit ) +{ + OUString aRange(rEdit.get_text()); + bool bIsValid = aRange.isEmpty() || + m_rDialogModel.getRangeSelectionHelper()->verifyCellRange(aRange); + rEdit.set_message_type(bIsValid ? weld::EntryMessageType::Normal : weld::EntryMessageType::Error); + return bIsValid; +} + +bool DataSourceTabPage::isValid() +{ + bool bRoleRangeValid = true; + bool bCategoriesRangeValid = true; + bool bHasSelectedEntry = (m_xLB_SERIES->get_selected_index() != -1); + + if (bHasSelectedEntry) + bRoleRangeValid = isRangeFieldContentValid(*m_xEDT_RANGE); + if (m_xEDT_CATEGORIES->get_sensitive()) + bCategoriesRangeValid = isRangeFieldContentValid( *m_xEDT_CATEGORIES ); + bool bValid = ( bRoleRangeValid && bCategoriesRangeValid ); + + if( m_pTabPageNotifiable ) + { + if( bValid ) + m_pTabPageNotifiable->setValidPage( this ); + else + m_pTabPageNotifiable->setInvalidPage( this ); + } + + return bValid; +} + +void DataSourceTabPage::setDirty() +{ + m_bIsDirty = true; +} + +void DataSourceTabPage::updateControlsFromDialogModel() +{ + // series + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + + // categories + m_xEDT_CATEGORIES->set_text(m_rDialogModel.getCategoriesRange()); + + updateControlState(); +} + +void DataSourceTabPage::fillSeriesListBox() +{ + rtl::Reference< DataSeries > xSelected; + SeriesEntry* pEntry = nullptr; + int nEntry = m_xLB_SERIES->get_selected_index(); + if (nEntry != -1) + { + pEntry = weld::fromId(m_xLB_SERIES->get_id(nEntry)); + xSelected = pEntry->m_xDataSeries; + } + + bool bHasSelectedEntry = (pEntry != nullptr); + int nSelectedEntry = -1; + + m_xLB_SERIES->freeze(); + m_xLB_SERIES->clear(); + + std::vector< DialogModel::tSeriesWithChartTypeByName > aSeries( + m_rDialogModel.getAllDataSeriesWithLabel() ); + + sal_Int32 nUnnamedSeriesIndex = 1; + nEntry = 0; + for (auto const& series : aSeries) + { + OUString aLabel(series.first); + if (aLabel.isEmpty()) + { + if( nUnnamedSeriesIndex > 1 ) + { + OUString aResString(::chart::SchResId( STR_DATA_UNNAMED_SERIES_WITH_INDEX )); + + // replace index of unnamed series + static const OUStringLiteral aReplacementStr( u"%NUMBER" ); + sal_Int32 nIndex = aResString.indexOf( aReplacementStr ); + if( nIndex != -1 ) + aLabel = aResString.replaceAt( + nIndex, aReplacementStr.getLength(), + OUString::number(nUnnamedSeriesIndex)); + } + if( aLabel.isEmpty() ) + aLabel = ::chart::SchResId( STR_DATA_UNNAMED_SERIES ); + + ++nUnnamedSeriesIndex; + } + + m_aEntries.emplace_back(new SeriesEntry); + pEntry = m_aEntries.back().get(); + pEntry->m_xDataSeries = series.second.first; + pEntry->m_xChartType = series.second.second; + m_xLB_SERIES->append(weld::toId(pEntry), aLabel); + if (bHasSelectedEntry && series.second.first == xSelected) + nSelectedEntry = nEntry; + ++nEntry; + } + + m_xLB_SERIES->thaw(); + + if (bHasSelectedEntry && nSelectedEntry != -1) + m_xLB_SERIES->select(nSelectedEntry); +} + +void DataSourceTabPage::fillRoleListBox() +{ + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pSeriesEntry = nullptr; + if (nSeriesEntry != -1) + pSeriesEntry = weld::fromId(m_xLB_SERIES->get_id(nSeriesEntry)); + bool bHasSelectedEntry = (pSeriesEntry != nullptr); + + int nRoleIndex = m_xLB_ROLE->get_selected_index(); + if (!bHasSelectedEntry) + return; + + DialogModel::tRolesWithRanges aRoles( + DialogModel::getRolesWithRanges( + pSeriesEntry->m_xDataSeries, + lcl_GetSequenceNameForLabel( pSeriesEntry ), + pSeriesEntry->m_xChartType )); + + // fill role list + m_xLB_ROLE->freeze(); + m_xLB_ROLE->clear(); + + for (auto const& elemRole : aRoles) + { + InsertRoleLBEntry(elemRole.first, elemRole.second); + } + + m_xLB_ROLE->thaw(); + + // series may contain no roles, check listbox size before selecting entries + if (m_xLB_ROLE->n_children() > 0) + { + if (nRoleIndex == -1 || nRoleIndex >= m_xLB_ROLE->n_children()) + nRoleIndex = 0; + m_xLB_ROLE->select(nRoleIndex); + } +} + +void DataSourceTabPage::updateControlState() +{ + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + bool bHasSelectedSeries = nSeriesEntry != -1; + bool bHasValidRole = false; + bool bHasRangeChooser = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection(); + + if( bHasSelectedSeries ) + { + int nRoleEntry = m_xLB_ROLE->get_selected_index(); + bHasValidRole = nRoleEntry != -1; + } + + m_xBTN_ADD->set_sensitive(true); + m_xBTN_REMOVE->set_sensitive(bHasSelectedSeries); + + m_xBTN_UP->set_sensitive(bHasSelectedSeries && (nSeriesEntry != 0)); + m_xBTN_DOWN->set_sensitive(bHasSelectedSeries && (nSeriesEntry != m_xLB_SERIES->n_children() - 1)); + + bool bHasCategories = m_rDialogModel.isCategoryDiagram(); + + m_xFT_DATALABELS->set_visible(!bHasCategories); + m_xFT_CATEGORIES->set_visible( bHasCategories); + bool bShowIB = bHasRangeChooser; + + m_xIMB_RANGE_CAT->set_visible(bShowIB); + + m_xFT_ROLE->set_sensitive(bHasSelectedSeries); + m_xLB_ROLE->set_sensitive(bHasSelectedSeries); + + m_xFT_RANGE->set_sensitive(bHasValidRole); + m_xEDT_RANGE->set_sensitive(bHasValidRole); + + m_xFT_SERIES->set_sensitive(true); + m_xLB_SERIES->set_sensitive(true); + + m_xIMB_RANGE_MAIN->set_visible(bShowIB); + + isValid(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, SeriesSelectionChangedHdl, weld::TreeView&, void) +{ + m_rDialogModel.startControllerLockTimer(); + if (m_xLB_SERIES->get_selected_index() != -1) + { + fillRoleListBox(); + RoleSelectionChangedHdl(*m_xLB_ROLE); + } + updateControlState(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, RoleSelectionChangedHdl, weld::TreeView&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_ROLE->get_selected_index(); + if (nEntry == -1) + return; + + OUString aSelectedRoleUI = lcl_GetSelectedRole( *m_xLB_ROLE, true ); + OUString aSelectedRange = lcl_GetSelectedRolesRange( *m_xLB_ROLE ); + + // replace role in fixed text label + static const OUStringLiteral aReplacementStr( u"%VALUETYPE" ); + sal_Int32 nIndex = m_aFixedTextRange.indexOf( aReplacementStr ); + if( nIndex != -1 ) + { + m_xFT_RANGE->set_label( + m_aFixedTextRange.replaceAt( + nIndex, aReplacementStr.getLength(), aSelectedRoleUI )); + } + + m_xEDT_RANGE->set_text(aSelectedRange); + isValid(); +} + +IMPL_LINK_NOARG(DataSourceTabPage, MainRangeButtonClickedHdl, weld::Button&, void) +{ + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + m_pCurrentRangeChoosingField = m_xEDT_RANGE.get(); + if (!m_xEDT_RANGE->get_text().isEmpty() && + !updateModelFromControl( m_pCurrentRangeChoosingField)) + return; + + int nEntry = m_xLB_SERIES->get_selected_index(); + bool bHasSelectedEntry = (nEntry != -1); + + OUString aSelectedRolesRange = lcl_GetSelectedRolesRange(*m_xLB_ROLE); + + if (bHasSelectedEntry && (m_xLB_ROLE->get_selected_index() != -1)) + { + OUString aUIStr(SchResId(STR_DATA_SELECT_RANGE_FOR_SERIES)); + + // replace role + OUString aReplacement( "%VALUETYPE" ); + sal_Int32 nIndex = aUIStr.indexOf( aReplacement ); + if( nIndex != -1 ) + { + aUIStr = aUIStr.replaceAt( nIndex, aReplacement.getLength(), + lcl_GetSelectedRole( *m_xLB_ROLE, true )); + } + // replace series name + aReplacement = "%SERIESNAME"; + nIndex = aUIStr.indexOf( aReplacement ); + if( nIndex != -1 ) + { + aUIStr = aUIStr.replaceAt(nIndex, aReplacement.getLength(), + m_xLB_SERIES->get_text(nEntry)); + } + + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( aSelectedRolesRange, aUIStr, *this ); + } + else + m_pCurrentRangeChoosingField = nullptr; +} + +IMPL_LINK_NOARG(DataSourceTabPage, CategoriesRangeButtonClickedHdl, weld::Button&, void) +{ + OSL_ASSERT( m_pCurrentRangeChoosingField == nullptr ); + m_pCurrentRangeChoosingField = m_xEDT_CATEGORIES.get(); + if( !m_xEDT_CATEGORIES->get_text().isEmpty() && + ! updateModelFromControl( m_pCurrentRangeChoosingField )) + return; + + OUString aStr(SchResId(m_xFT_CATEGORIES->get_visible() ? STR_DATA_SELECT_RANGE_FOR_CATEGORIES : STR_DATA_SELECT_RANGE_FOR_DATALABELS)); + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( + m_rDialogModel.getCategoriesRange(), aStr, *this ); +} + +IMPL_LINK_NOARG(DataSourceTabPage, AddButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_SERIES->get_selected_index(); + rtl::Reference< DataSeries > xSeriesToInsertAfter; + rtl::Reference< ChartType > xChartTypeForNewSeries; + if( m_pTemplateProvider ) + m_rDialogModel.setTemplate( m_pTemplateProvider->getCurrentTemplate()); + + if (nEntry != -1) + { + ::chart::SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + xSeriesToInsertAfter = pEntry->m_xDataSeries; + xChartTypeForNewSeries = pEntry->m_xChartType; + } + else + { + std::vector< rtl::Reference< ChartType > > aCntVec( + m_rDialogModel.getAllDataSeriesContainers()); + if( ! aCntVec.empty()) + xChartTypeForNewSeries = aCntVec.front(); + } + OSL_ENSURE( xChartTypeForNewSeries.is(), "Cannot insert new series" ); + + m_rDialogModel.insertSeriesAfter( xSeriesToInsertAfter, xChartTypeForNewSeries ); + setDirty(); + + fillSeriesListBox(); + // note the box was cleared and refilled, so nEntry is invalid now + + int nSelEntry = m_xLB_SERIES->get_selected_index(); + if (nSelEntry != -1) + { + ++nSelEntry; + if (nSelEntry < m_xLB_SERIES->n_children()) + m_xLB_SERIES->select(nSelEntry); + } + SeriesSelectionChangedHdl(*m_xLB_SERIES); +} + +IMPL_LINK_NOARG(DataSourceTabPage, RemoveButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + int nEntry = m_xLB_SERIES->get_selected_index(); + if (nEntry == -1) + return; + + SeriesEntry* pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry)); + rtl::Reference< DataSeries > xNewSelSeries; + SeriesEntry * pNewSelEntry = nullptr; + if (nEntry + 1 < m_xLB_SERIES->n_children()) + pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry + 1)); + else if (nEntry > 0) + pNewSelEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(nEntry - 1)); + if (pNewSelEntry) + xNewSelSeries = pNewSelEntry->m_xDataSeries; + + m_rDialogModel.deleteSeries( pEntry->m_xDataSeries, pEntry->m_xChartType ); + setDirty(); + + m_xLB_SERIES->remove(nEntry); + fillSeriesListBox(); + + // select previous or next series + if (xNewSelSeries.is()) + { + for (int i = 0; i < m_xLB_SERIES->n_children(); ++i) + { + pEntry = weld::fromId<::chart::SeriesEntry*>(m_xLB_SERIES->get_id(i)); + if (pEntry->m_xDataSeries == xNewSelSeries) + { + m_xLB_SERIES->select(i); + break; + } + } + } + SeriesSelectionChangedHdl(*m_xLB_SERIES); +} + +IMPL_LINK_NOARG(DataSourceTabPage, UpButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + + int nEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pEntry = nullptr; + if (nEntry != -1) + pEntry = weld::fromId(m_xLB_SERIES->get_id(nEntry)); + + bool bHasSelectedEntry = (pEntry != nullptr); + + if (bHasSelectedEntry) + { + m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Up ); + setDirty(); + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + } +} + +IMPL_LINK_NOARG(DataSourceTabPage, DownButtonClickedHdl, weld::Button&, void) +{ + m_rDialogModel.startControllerLockTimer(); + + int nEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pEntry = nullptr; + if (nEntry != -1) + pEntry = weld::fromId(m_xLB_SERIES->get_id(nEntry)); + + bool bHasSelectedEntry = (pEntry != nullptr); + + if (bHasSelectedEntry) + { + m_rDialogModel.moveSeries( pEntry->m_xDataSeries, DialogModel::MoveDirection::Down ); + setDirty(); + fillSeriesListBox(); + SeriesSelectionChangedHdl(*m_xLB_SERIES); + } +} + +IMPL_LINK(DataSourceTabPage, RangeModifiedHdl, weld::Entry&, rEdit, void) +{ + // note: isValid sets the color of the edit field + if( isRangeFieldContentValid( rEdit )) + { + setDirty(); + updateModelFromControl( &rEdit ); + if (&rEdit == m_xEDT_RANGE.get()) + { + if( ! lcl_UpdateCurrentSeriesName( *m_xLB_SERIES )) + fillSeriesListBox(); + } + } + + // enable/disable OK button + isValid(); +} + +void DataSourceTabPage::listeningFinished( + const OUString & rNewRange ) +{ + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + m_rDialogModel.startControllerLockTimer(); + + // stop listening + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening(); + + // change edit field + if( m_pCurrentRangeChoosingField ) + { + m_pCurrentRangeChoosingField->set_text(aRange); + m_pCurrentRangeChoosingField->grab_focus(); + } + + if (m_pCurrentRangeChoosingField == m_xEDT_RANGE.get()) + { + m_xEDT_RANGE->set_text(aRange); + setDirty(); + } + else if (m_pCurrentRangeChoosingField == m_xEDT_CATEGORIES.get()) + { + m_xEDT_CATEGORIES->set_text(aRange); + setDirty(); + } + + updateModelFromControl(m_pCurrentRangeChoosingField); + if (!lcl_UpdateCurrentSeriesName(*m_xLB_SERIES)) + fillSeriesListBox(); + + m_pCurrentRangeChoosingField = nullptr; + + updateControlState(); + lcl_enableRangeChoosing(false, m_pDialogController); +} + +void DataSourceTabPage::disposingRangeSelection() +{ + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false ); +} + +bool DataSourceTabPage::updateModelFromControl(const weld::Entry* pField) +{ + if (!m_bIsDirty) + return true; + + ControllerLockGuardUNO aLockedControllers( m_rDialogModel.getChartModel() ); + + // @todo: validity check of field content + bool bResult = true; + bool bAll = (pField == nullptr); + Reference< data::XDataProvider > xDataProvider( m_rDialogModel.getDataProvider()); + + if (bAll || (pField == m_xEDT_CATEGORIES.get())) + { + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( m_rDialogModel.getCategories() ); + if( xDataProvider.is()) + { + OUString aRange(m_xEDT_CATEGORIES->get_text()); + if (!aRange.isEmpty()) + { + // create or change categories + if( !xLabeledSeq.is()) + { + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + m_rDialogModel.setCategories( xLabeledSeq ); + } + try + { + xLabeledSeq->setValues( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else if( xLabeledSeq.is()) + { + // clear existing categories + xLabeledSeq.set(nullptr); + m_rDialogModel.setCategories( xLabeledSeq ); + } + } + } + + int nSeriesEntry = m_xLB_SERIES->get_selected_index(); + SeriesEntry* pSeriesEntry = nullptr; + if (nSeriesEntry != -1) + pSeriesEntry = weld::fromId(m_xLB_SERIES->get_id(nSeriesEntry)); + bool bHasSelectedEntry = (pSeriesEntry != nullptr); + + if( bHasSelectedEntry ) + { + if( bAll || (pField == m_xEDT_RANGE.get()) ) + { + try + { + OUString aSelectedRole = lcl_GetSelectedRole( *m_xLB_ROLE ); + OUString aRange(m_xEDT_RANGE->get_text()); + OUString aSequenceRole( aSelectedRole ); + bool bIsLabel = (aSequenceRole == lcl_aLabelRole ); + OUString aSequenceNameForLabel( lcl_GetSequenceNameForLabel( pSeriesEntry )); + + if( bIsLabel ) + aSequenceRole = aSequenceNameForLabel; + + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq = + DataSeriesHelper::getDataSequenceByRole( pSeriesEntry->m_xDataSeries, aSequenceRole ); + + if( xDataProvider.is()) + { + if( bIsLabel ) + { + if( ! xLabeledSeq.is()) + { + // check if there is already an "orphan" label sequence + xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries ); + if( ! xLabeledSeq.is()) + { + // no corresponding labeled data sequence for label found + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries ); + } + } + if( xLabeledSeq.is()) + { + if( !aRange.isEmpty()) + { + Reference< data::XDataSequence > xNewSeq; + try + { + xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + if( xNewSeq.is()) + { + // update range name by the full string provided + // by the data provider. E.g. "a1" might become + // "$Sheet1.$A$1" + aRange = xNewSeq->getSourceRangeRepresentation(); + Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( "Role" , uno::Any( OUString(lcl_aLabelRole) )); + + //Labels should always include hidden cells, regardless of the setting chosen + xProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true)); + xLabeledSeq->setLabel( xNewSeq ); + } + } + else + { + xLabeledSeq->setLabel( Reference< data::XDataSequence >()); + } + } + } + else + { + if( !aRange.isEmpty()) + { + Reference< data::XDataSequence > xNewSeq; + try + { + xNewSeq.set( xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + } + catch( const uno::Exception & ) + { + // should work as validation should have happened before + DBG_UNHANDLED_EXCEPTION("chart2"); + } + if( xNewSeq.is()) + { + // update range name by the full string provided + // by the data provider. E.g. "a1:e1" might become + // "$Sheet1.$A$1:$E$1" + aRange = xNewSeq->getSourceRangeRepresentation(); + + Reference< beans::XPropertySet > xProp( xNewSeq, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( "Role" , uno::Any( aSelectedRole )); + if( !xLabeledSeq.is()) + { + if( aSelectedRole == aSequenceNameForLabel ) + xLabeledSeq = lcl_findLSequenceWithOnlyLabel( pSeriesEntry->m_xDataSeries ); + if( ! xLabeledSeq.is()) + { + xLabeledSeq = DataSourceHelper::createLabeledDataSequence(); + lcl_addLSequenceToDataSource( xLabeledSeq, pSeriesEntry->m_xDataSeries ); + } + } + xLabeledSeq->setValues( xNewSeq ); + } + } + } + } + + lcl_UpdateCurrentRange( *m_xLB_ROLE, aSelectedRole, aRange ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + bResult = false; + } + } + } + + // update View + // @todo remove this when automatic view updates from calc, writer and own data sequences are available + if( bResult ) + { + try + { + if( m_rDialogModel.getChartModel() ) + m_rDialogModel.getChartModel()->setModified( true ); + const DialogModelTimeBasedInfo& rInfo = m_rDialogModel.getTimeBasedInfo(); + if(rInfo.bTimeBased) + { + m_rDialogModel.setTimeBasedRange(rInfo.bTimeBased, rInfo.nStart, rInfo.nEnd); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_DataSource.hxx b/chart2/source/controller/dialogs/tp_DataSource.hxx new file mode 100644 index 000000000..40219d917 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_DataSource.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +#include + +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart { class TabPageNotifiable; } + +namespace chart +{ +class ChartType; +class ChartTypeTemplateProvider; +class DataSeries; +class DialogModel; + +class SeriesEntry +{ +public: + OUString m_sRole; + + /// the corresponding data series + rtl::Reference< ::chart::DataSeries > m_xDataSeries; + + /// the chart type that contains the series (via XDataSeriesContainer) + rtl::Reference< ::chart::ChartType > m_xChartType; +}; + +class DataSourceTabPage final : + public ::vcl::OWizardPage, + public RangeSelectionListenerParent +{ +public: + explicit DataSourceTabPage(weld::Container* pPage, weld::DialogController* pController, + DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription = false); + virtual ~DataSourceTabPage() override; + + virtual void Activate() override; + + void commitPage(); + +private: + // OWizardPage + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + //TabPage + virtual void Deactivate() override; + + virtual void initializePage() override; + + DECL_LINK( SeriesSelectionChangedHdl, weld::TreeView&, void ); + DECL_LINK( RoleSelectionChangedHdl, weld::TreeView&, void ); + DECL_LINK( MainRangeButtonClickedHdl, weld::Button&, void ); + DECL_LINK( CategoriesRangeButtonClickedHdl, weld::Button&, void ); + DECL_LINK( AddButtonClickedHdl, weld::Button&, void ); + DECL_LINK( RemoveButtonClickedHdl, weld::Button&, void ); + DECL_LINK( RangeModifiedHdl, weld::Entry&, void ); + DECL_LINK( UpButtonClickedHdl, weld::Button&, void ); + DECL_LINK( DownButtonClickedHdl, weld::Button&, void ); + + // ____ RangeSelectionListenerParent ____ + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + + void InsertRoleLBEntry(const OUString& rRole, const OUString& rRange); + + void updateControlState(); + + /** updates the internal data according to the content of the given edit + field. If pField is 0, all relevant fields are used + + @return + if the text from the field is a valid format to the internal + data was valid + */ + bool updateModelFromControl(const weld::Entry* pField = nullptr); + + /** @return , if the edit field contains a valid range entry. If no + XCellRangesAccess can be obtained, is returned. + */ + bool isRangeFieldContentValid(weld::Entry& rEdit); + + /** @return , if the tab-page is in a consistent (committable) state + */ + bool isValid(); + void setDirty(); + + void updateControlsFromDialogModel(); + + void fillSeriesListBox(); + void fillRoleListBox(); + + std::vector> m_aEntries; + + OUString m_aFixedTextRange; + + ChartTypeTemplateProvider * m_pTemplateProvider; + DialogModel & m_rDialogModel; + weld::Entry* m_pCurrentRangeChoosingField; + bool m_bIsDirty; + + TabPageNotifiable * m_pTabPageNotifiable; + + std::unique_ptr m_xFT_CAPTION; + std::unique_ptr m_xFT_SERIES; + std::unique_ptr m_xLB_SERIES; + std::unique_ptr m_xBTN_ADD; + std::unique_ptr m_xBTN_REMOVE; + std::unique_ptr m_xBTN_UP; + std::unique_ptr m_xBTN_DOWN; + std::unique_ptr m_xFT_ROLE; + std::unique_ptr m_xLB_ROLE; + std::unique_ptr m_xFT_RANGE; + std::unique_ptr m_xEDT_RANGE; + std::unique_ptr m_xIMB_RANGE_MAIN; + std::unique_ptr m_xFT_CATEGORIES; + std::unique_ptr m_xFT_DATALABELS;//used for xy charts + std::unique_ptr m_xEDT_CATEGORIES; + std::unique_ptr m_xIMB_RANGE_CAT; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ErrorBars.cxx b/chart2/source/controller/dialogs/tp_ErrorBars.cxx new file mode 100644 index 000000000..927bf1130 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ErrorBars.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_ErrorBars.hxx" + +using namespace ::com::sun::star; + +namespace chart +{ + +ErrorBarsTabPage::ErrorBarsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_ErrorBars.ui", "tp_ErrorBars", &rInAttrs) + , m_aErrorBarResources(m_xBuilder.get(), pController, rInAttrs, /* bNoneAvailable = */ false) +{ +} + +std::unique_ptr ErrorBarsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool ErrorBarsTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + m_aErrorBarResources.FillItemSet( *rOutAttrs ); + return true; +} + +void ErrorBarsTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + m_aErrorBarResources.Reset( *rInAttrs ); +} + +void ErrorBarsTabPage::SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ) +{ + m_aErrorBarResources.SetAxisMinorStepWidthForErrorBarDecimals( fMinorStepWidth ); +} + +void ErrorBarsTabPage::SetErrorBarType( ErrorBarResources::tErrorBarType eNewType ) +{ + m_aErrorBarResources.SetErrorBarType( eNewType ); +} + +void ErrorBarsTabPage::SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ) +{ + m_aErrorBarResources.SetChartDocumentForRangeChoosing( xChartDocument ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ErrorBars.hxx b/chart2/source/controller/dialogs/tp_ErrorBars.hxx new file mode 100644 index 000000000..159de22b0 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ErrorBars.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include + +namespace chart +{ +class ChartModel; + +class ErrorBarsTabPage : public SfxTabPage +{ +public: + ErrorBarsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + void SetErrorBarType( ErrorBarResources::tErrorBarType eNewType ); + void SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + +private: + ErrorBarResources m_aErrorBarResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_LegendPosition.cxx b/chart2/source/controller/dialogs/tp_LegendPosition.cxx new file mode 100644 index 000000000..00a0d54b1 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_LegendPosition.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_LegendPosition.hxx" +#include +#include +#include +#include +#include + +namespace chart +{ + +SchLegendPosTabPage::SchLegendPosTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_LegendPosition.ui", "tp_LegendPosition", &rInAttrs) + , m_aLegendPositionResources(*m_xBuilder) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("LB_LEGEND_TEXTDIR"))) + , m_xCBLegendNoOverlay(m_xBuilder->weld_check_button("CB_NO_OVERLAY")) +{ +} + +SchLegendPosTabPage::~SchLegendPosTabPage() +{ + m_xLbTextDirection.reset(); +} + +std::unique_ptr SchLegendPosTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool SchLegendPosTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + m_aLegendPositionResources.writeToItemSet(*rOutAttrs); + + if (m_xLbTextDirection->get_active() != -1) + rOutAttrs->Put(SvxFrameDirectionItem(m_xLbTextDirection->get_active_id(), EE_PARA_WRITINGDIR)); + + if (m_xCBLegendNoOverlay->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_LEGEND_NO_OVERLAY, m_xCBLegendNoOverlay->get_active())); + + return true; +} + +void SchLegendPosTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_aLegendPositionResources.initFromItemSet(*rInAttrs); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet( EE_PARA_WRITINGDIR ) ) + m_xLbTextDirection->set_active_id( pDirectionItem->GetValue() ); + + if (const SfxBoolItem* pNoOverlayItem = rInAttrs->GetItemIfSet(SCHATTR_LEGEND_NO_OVERLAY)) + { + bool bVal = pNoOverlayItem->GetValue(); + m_xCBLegendNoOverlay->set_active(bVal); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_LegendPosition.hxx b/chart2/source/controller/dialogs/tp_LegendPosition.hxx new file mode 100644 index 000000000..9e5f32d28 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_LegendPosition.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace chart { class TextDirectionListBox; } + +namespace chart +{ + +class SchLegendPosTabPage : public SfxTabPage +{ +private: + + LegendPositionResources m_aLegendPositionResources; + std::unique_ptr m_xLbTextDirection; + std::unique_ptr m_xCBLegendNoOverlay; + +public: + SchLegendPosTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchLegendPosTabPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PointGeometry.cxx b/chart2/source/controller/dialogs/tp_PointGeometry.cxx new file mode 100644 index 000000000..7c2c4d942 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PointGeometry.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_PointGeometry.hxx" +#include + +#include + +#include +#include + +namespace chart +{ + +SchLayoutTabPage::SchLayoutTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_ChartType.ui", "tp_ChartType", &rInAttrs) +{ + m_pGeometryResources.reset(new BarGeometryResources(m_xBuilder.get())); +} + +SchLayoutTabPage::~SchLayoutTabPage() +{ + m_pGeometryResources.reset(); +} + +std::unique_ptr SchLayoutTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool SchLayoutTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + int nShape = m_pGeometryResources ? m_pGeometryResources->get_selected_index() : -1; + if (nShape != -1) + { + tools::Long nSegs=32; + + if (nShape==CHART_SHAPE3D_PYRAMID) + nSegs=4; + + rOutAttrs->Put(SfxInt32Item(SCHATTR_STYLE_SHAPE,nShape)); + rOutAttrs->Put(makeSvx3DHorizontalSegmentsItem(nSegs)); + } + return true; +} + +void SchLayoutTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SfxInt32Item* pShapeItem = rInAttrs->GetItemIfSet(SCHATTR_STYLE_SHAPE)) + { + tools::Long nVal = pShapeItem->GetValue(); + if(m_pGeometryResources) + { + m_pGeometryResources->select(static_cast(nVal)); + m_pGeometryResources->set_visible(true); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PointGeometry.hxx b/chart2/source/controller/dialogs/tp_PointGeometry.hxx new file mode 100644 index 000000000..326cc9025 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PointGeometry.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class BarGeometryResources; +class SchLayoutTabPage : public SfxTabPage +{ +public: + SchLayoutTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~SchLayoutTabPage() override; + + static std::unique_ptr + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr m_pGeometryResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PolarOptions.cxx b/chart2/source/controller/dialogs/tp_PolarOptions.cxx new file mode 100644 index 000000000..ad7b2b6f0 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PolarOptions.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_PolarOptions.hxx" +#include + +#include +#include +#include + +namespace chart +{ + +PolarOptionsTabPage::PolarOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_PolarOptions.ui", "tp_PolarOptions", &rInAttrs) + , m_xCB_Clockwise(m_xBuilder->weld_check_button("CB_CLOCKWISE")) + , m_xFL_StartingAngle(m_xBuilder->weld_frame("frameANGLE")) + , m_xNF_StartingAngle(m_xBuilder->weld_metric_spin_button("NF_STARTING_ANGLE", FieldUnit::DEGREE)) + , m_xFL_PlotOptions(m_xBuilder->weld_frame("framePLOT_OPTIONS")) + , m_xCB_IncludeHiddenCells(m_xBuilder->weld_check_button("CB_INCLUDE_HIDDEN_CELLS_POLAR")) + , m_xAngleDial(new svx::DialControl) + , m_xAngleDialWin(new weld::CustomWeld(*m_xBuilder, "CT_ANGLE_DIAL", *m_xAngleDial)) +{ + m_xAngleDial->SetLinkedField(m_xNF_StartingAngle.get()); +} + +PolarOptionsTabPage::~PolarOptionsTabPage() +{ + m_xAngleDialWin.reset(); + m_xAngleDial.reset(); +} + +std::unique_ptr PolarOptionsTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool PolarOptionsTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + if (m_xAngleDialWin->get_visible()) + { + rOutAttrs->Put(SdrAngleItem(SCHATTR_STARTING_ANGLE, m_xAngleDial->GetRotation())); + } + + if( m_xCB_Clockwise->get_visible() ) + rOutAttrs->Put(SfxBoolItem(SCHATTR_CLOCKWISE,m_xCB_Clockwise->get_active())); + + if (m_xCB_IncludeHiddenCells->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, m_xCB_IncludeHiddenCells->get_active())); + + return true; +} + +void PolarOptionsTabPage::Reset(const SfxItemSet* rInAttrs) +{ + if (const SdrAngleItem* pAngleItem = rInAttrs->GetItemIfSet(SCHATTR_STARTING_ANGLE)) + { + Degree100 nTmp = pAngleItem->GetValue(); + m_xAngleDial->SetRotation( nTmp ); + } + else + { + m_xFL_StartingAngle->hide(); + } + // tdf#108059 Hide clockwise orientation checkbox in OOXML-heavy environments it would be useless anyways + const SfxBoolItem* pClockWiseItem = nullptr; + if (!officecfg::Office::Compatibility::View::ClockwisePieChartDirection::get() && + (pClockWiseItem = rInAttrs->GetItemIfSet(SCHATTR_CLOCKWISE))) + { + bool bCheck = pClockWiseItem->GetValue(); + m_xCB_Clockwise->set_active(bCheck); + } + else + { + m_xCB_Clockwise->hide(); + } + if (const SfxBoolItem* pHiddenCellsItem = rInAttrs->GetItemIfSet(SCHATTR_INCLUDE_HIDDEN_CELLS)) + { + bool bVal = pHiddenCellsItem->GetValue(); + m_xCB_IncludeHiddenCells->set_active(bVal); + } + else + { + m_xFL_PlotOptions->hide(); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_PolarOptions.hxx b/chart2/source/controller/dialogs/tp_PolarOptions.hxx new file mode 100644 index 000000000..eba401805 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_PolarOptions.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace weld { + class CheckButton; + class CustomWeld; + class Frame; + class SpinButton; +} + +namespace chart +{ + +class PolarOptionsTabPage : public SfxTabPage +{ + +public: + PolarOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~PolarOptionsTabPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + +private: + std::unique_ptr m_xCB_Clockwise; + std::unique_ptr m_xFL_StartingAngle; + std::unique_ptr m_xNF_StartingAngle; + std::unique_ptr m_xFL_PlotOptions; + std::unique_ptr m_xCB_IncludeHiddenCells; + std::unique_ptr m_xAngleDial; + std::unique_ptr m_xAngleDialWin; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_RangeChooser.cxx b/chart2/source/controller/dialogs/tp_RangeChooser.cxx new file mode 100644 index 000000000..05f137f5a --- /dev/null +++ b/chart2/source/controller/dialogs/tp_RangeChooser.cxx @@ -0,0 +1,381 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_RangeChooser.hxx" +#include +#include +#include +#include "DialogModel.hxx" +#include +#include +#include +#include +#include +#include + +namespace +{ + void lcl_ShowChooserButton( + weld::Button& rChooserButton, + bool bShow) + { + if( rChooserButton.get_visible() != bShow ) + { + rChooserButton.set_visible( bShow ); + } + } + + void lcl_enableRangeChoosing(bool bEnable, weld::DialogController* pDialog) + { + if (!pDialog) + return; + weld::Dialog* pDlg = pDialog->getDialog(); + pDlg->set_modal(!bEnable); + pDlg->set_visible(!bEnable); + } + +} // anonymous namespace + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Sequence; + +RangeChooserTabPage::RangeChooserTabPage(weld::Container* pPage, weld::DialogController* pController, DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription /* = false */) + : OWizardPage(pPage, pController, "modules/schart/ui/tp_RangeChooser.ui", "tp_RangeChooser") + , m_nChangingControlCalls(0) + , m_bIsDirty(false) + , m_pTemplateProvider(pTemplateProvider) + , m_rDialogModel( rDialogModel ) + , m_pTabPageNotifiable(dynamic_cast(pController)) + , m_xFT_Caption(m_xBuilder->weld_label("FT_CAPTION_FOR_WIZARD")) + , m_xFT_Range(m_xBuilder->weld_label("FT_RANGE")) + , m_xED_Range(m_xBuilder->weld_entry("ED_RANGE")) + , m_xIB_Range(m_xBuilder->weld_button("IB_RANGE")) + , m_xRB_Rows(m_xBuilder->weld_radio_button("RB_DATAROWS")) + , m_xRB_Columns(m_xBuilder->weld_radio_button("RB_DATACOLS")) + , m_xCB_FirstRowAsLabel(m_xBuilder->weld_check_button("CB_FIRST_ROW_ASLABELS")) + , m_xCB_FirstColumnAsLabel(m_xBuilder->weld_check_button("CB_FIRST_COLUMN_ASLABELS")) + , m_xFTTitle(m_xBuilder->weld_label("STR_PAGE_DATA_RANGE")) + , m_xFL_TimeBased(m_xBuilder->weld_widget("separator1")) + , m_xCB_TimeBased(m_xBuilder->weld_check_button("CB_TIME_BASED")) + , m_xFT_TimeStart(m_xBuilder->weld_label("label1")) + , m_xEd_TimeStart(m_xBuilder->weld_entry("ED_TIME_BASED_START")) + , m_xFT_TimeEnd(m_xBuilder->weld_label("label2")) + , m_xEd_TimeEnd(m_xBuilder->weld_entry("ED_TIME_BASED_END")) +{ + m_xFT_Caption->set_visible(!bHideDescription); + + SetPageTitle(m_xFTTitle->get_label());// OH:remove later with dialog + + // set defaults as long as DetectArguments does not work + m_xRB_Columns->set_active(true); + m_xCB_FirstColumnAsLabel->set_active(true); + m_xCB_FirstRowAsLabel->set_active(true); + + // BM: Note, that the range selection is not available, if there is no view. + // This happens for charts having their own embedded spreadsheet. If you + // force to get the range selection here, this would mean when entering this + // page the calc view would be created in this case. So, I enable the + // button here, and in the worst case nothing happens when it is pressed. + // Not nice, but I see no better solution for the moment. + m_xIB_Range->connect_clicked( LINK( this, RangeChooserTabPage, ChooseRangeHdl )); + + m_xED_Range->connect_changed( LINK( this, RangeChooserTabPage, ControlEditedHdl )); + m_xRB_Rows->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedRadioHdl ) ); + m_xCB_FirstRowAsLabel->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xCB_FirstColumnAsLabel->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xCB_TimeBased->connect_toggled( LINK( this, RangeChooserTabPage, ControlChangedCheckBoxHdl ) ); + m_xEd_TimeStart->connect_changed( LINK( this, RangeChooserTabPage, ControlChangedHdl ) ); + m_xEd_TimeEnd->connect_changed( LINK( this, RangeChooserTabPage, ControlChangedHdl ) ); + + if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() ) + { + m_xFL_TimeBased->hide(); + m_xCB_TimeBased->hide(); + m_xFT_TimeStart->hide(); + m_xEd_TimeStart->hide(); + m_xFT_TimeEnd->hide(); + m_xEd_TimeEnd->hide(); + } +} + +RangeChooserTabPage::~RangeChooserTabPage() +{ +} + +void RangeChooserTabPage::Activate() +{ + OWizardPage::Activate(); + initControlsFromModel(); + m_xED_Range->grab_focus(); +} + +void RangeChooserTabPage::initControlsFromModel() +{ + m_nChangingControlCalls++; + + if(m_pTemplateProvider) + m_xCurrentChartTypeTemplate = m_pTemplateProvider->getCurrentTemplate(); + + bool bUseColumns = !m_xRB_Rows->get_active(); + bool bFirstCellAsLabel = bUseColumns ? m_xCB_FirstRowAsLabel->get_active() : m_xCB_FirstColumnAsLabel->get_active(); + bool bHasCategories = bUseColumns ? m_xCB_FirstColumnAsLabel->get_active() : m_xCB_FirstRowAsLabel->get_active(); + + bool bIsValid = m_rDialogModel.allArgumentsForRectRangeDetected(); + if( bIsValid ) + m_rDialogModel.detectArguments(m_aLastValidRangeString, bUseColumns, bFirstCellAsLabel, bHasCategories ); + else + m_aLastValidRangeString.clear(); + + m_xED_Range->set_text( m_aLastValidRangeString ); + + m_xRB_Rows->set_active( !bUseColumns ); + m_xRB_Columns->set_active( bUseColumns ); + + m_xCB_FirstRowAsLabel->set_active( m_xRB_Rows->get_active()?bHasCategories:bFirstCellAsLabel ); + m_xCB_FirstColumnAsLabel->set_active( m_xRB_Columns->get_active()?bHasCategories:bFirstCellAsLabel ); + + isValid(); + + m_nChangingControlCalls--; +} + +void RangeChooserTabPage::Deactivate() +{ + commitPage(); + vcl::OWizardPage::Deactivate(); +} + +void RangeChooserTabPage::commitPage() +{ + commitPage(::vcl::WizardTypes::eFinish); +} + +bool RangeChooserTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + //ranges may have been edited in the meanwhile (dirty is true in that case here) + if( isValid() ) + { + changeDialogModelAccordingToControls(); + return true; // return false if this page should not be left + } + else + return false; +} + +void RangeChooserTabPage::changeDialogModelAccordingToControls() +{ + if(m_nChangingControlCalls>0) + return; + + if( !m_xCurrentChartTypeTemplate.is() ) + { + if(m_pTemplateProvider) + m_xCurrentChartTypeTemplate = m_pTemplateProvider->getCurrentTemplate(); + if( !m_xCurrentChartTypeTemplate.is()) + { + OSL_FAIL( "Need a template to change data source" ); + return; + } + } + + if( !m_bIsDirty ) + return; + + bool bFirstCellAsLabel = ( m_xCB_FirstColumnAsLabel->get_active() && !m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && !m_xRB_Rows->get_active() ); + bool bHasCategories = ( m_xCB_FirstColumnAsLabel->get_active() && m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && m_xRB_Rows->get_active() ); + bool bTimeBased = m_xCB_TimeBased->get_active(); + + Sequence< beans::PropertyValue > aArguments( + DataSourceHelper::createArguments( + m_xRB_Columns->get_active(), bFirstCellAsLabel, bHasCategories ) ); + + if(bTimeBased) + { + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "TimeBased", -1, uno::Any(bTimeBased), + beans::PropertyState_DIRECT_VALUE ); + } + + // only if range is valid + if( m_aLastValidRangeString != m_xED_Range->get_text()) + return; + + m_rDialogModel.setTemplate( m_xCurrentChartTypeTemplate ); + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "CellRangeRepresentation" , -1, + uno::Any( m_aLastValidRangeString ), + beans::PropertyState_DIRECT_VALUE ); + m_rDialogModel.setData( aArguments ); + m_bIsDirty = false; + + if(bTimeBased) + { + sal_Int32 nStart = m_xEd_TimeStart->get_text().toInt32(); + sal_Int32 nEnd = m_xEd_TimeEnd->get_text().toInt32(); + m_rDialogModel.setTimeBasedRange(true, nStart, nEnd); + } + + //@todo warn user that the selected range is not valid + //@todo better: disable OK-Button if range is invalid +} + +bool RangeChooserTabPage::isValid() +{ + OUString aRange( m_xED_Range->get_text()); + bool bFirstCellAsLabel = ( m_xCB_FirstColumnAsLabel->get_active() && !m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && !m_xRB_Rows->get_active() ); + bool bHasCategories = ( m_xCB_FirstColumnAsLabel->get_active() && m_xRB_Columns->get_active() ) + || ( m_xCB_FirstRowAsLabel->get_active() && m_xRB_Rows->get_active() ); + bool bIsValid = ( aRange.isEmpty() ) || + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), bFirstCellAsLabel, bHasCategories )); + + if( bIsValid ) + { + m_xED_Range->set_message_type(weld::EntryMessageType::Normal); + if( m_pTabPageNotifiable ) + m_pTabPageNotifiable->setValidPage( this ); + m_aLastValidRangeString = aRange; + } + else + { + m_xED_Range->set_message_type(weld::EntryMessageType::Error); + if( m_pTabPageNotifiable ) + m_pTabPageNotifiable->setInvalidPage( this ); + } + + // enable/disable controls + // #i79531# if the range is valid but an action of one of these buttons + // would render it invalid, the button should be disabled + if( bIsValid ) + { + bool bDataInColumns = m_xRB_Columns->get_active(); + bool bIsSwappedRangeValid = m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), ! bDataInColumns, bHasCategories, bFirstCellAsLabel )); + m_xRB_Rows->set_sensitive( bIsSwappedRangeValid ); + m_xRB_Columns->set_sensitive( bIsSwappedRangeValid ); + + m_xCB_FirstRowAsLabel->set_sensitive( + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), + bDataInColumns ? ! bFirstCellAsLabel : bFirstCellAsLabel, + bDataInColumns ? bHasCategories : ! bHasCategories ))); + m_xCB_FirstColumnAsLabel->set_sensitive( + m_rDialogModel.getRangeSelectionHelper()->verifyArguments( + DataSourceHelper::createArguments( + aRange, Sequence< sal_Int32 >(), m_xRB_Columns->get_active(), + bDataInColumns ? bFirstCellAsLabel : ! bFirstCellAsLabel, + bDataInColumns ? ! bHasCategories : bHasCategories ))); + } + else + { + m_xRB_Rows->set_sensitive( bIsValid ); + m_xRB_Columns->set_sensitive( bIsValid ); + m_xCB_FirstRowAsLabel->set_sensitive( bIsValid ); + m_xCB_FirstColumnAsLabel->set_sensitive( bIsValid ); + } + + bool bShowIB = m_rDialogModel.getRangeSelectionHelper()->hasRangeSelection(); + lcl_ShowChooserButton( *m_xIB_Range, bShowIB ); + + return bIsValid; +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlEditedHdl, weld::Entry&, void) +{ + setDirty(); + isValid(); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedRadioHdl, weld::Toggleable&, void) +{ + ControlChangedHdl(*m_xED_Range); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedCheckBoxHdl, weld::Toggleable&, void) +{ + ControlChangedHdl(*m_xED_Range); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ControlChangedHdl, weld::Entry&, void) +{ + setDirty(); + if( isValid()) + changeDialogModelAccordingToControls(); +} + +IMPL_LINK_NOARG(RangeChooserTabPage, ChooseRangeHdl, weld::Button&, void) +{ + OUString aRange = m_xED_Range->get_text(); + OUString aTitle = m_xFTTitle->get_label(); + + lcl_enableRangeChoosing(true, m_pDialogController); + m_rDialogModel.getRangeSelectionHelper()->chooseRange( aRange, aTitle, *this ); +} + +void RangeChooserTabPage::listeningFinished( const OUString & rNewRange ) +{ + //user has selected a new range + + // rNewRange becomes invalid after removing the listener + OUString aRange( rNewRange ); + + m_rDialogModel.startControllerLockTimer(); + + // stop listening + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening(); + + //update dialog state + m_xED_Range->set_text(aRange); + m_xED_Range->grab_focus(); + + setDirty(); + if( isValid()) + changeDialogModelAccordingToControls(); + + lcl_enableRangeChoosing(false, m_pDialogController); +} + +void RangeChooserTabPage::disposingRangeSelection() +{ + m_rDialogModel.getRangeSelectionHelper()->stopRangeListening( false ); +} + +void RangeChooserTabPage::setDirty() +{ + if( m_nChangingControlCalls == 0 ) + m_bIsDirty = true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_RangeChooser.hxx b/chart2/source/controller/dialogs/tp_RangeChooser.hxx new file mode 100644 index 000000000..fff338324 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_RangeChooser.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +namespace chart { class TabPageNotifiable; } + +namespace chart +{ +class ChartTypeTemplate; +class ChartTypeTemplateProvider; +class DialogModel; + +class RangeChooserTabPage final : public vcl::OWizardPage, public RangeSelectionListenerParent +{ +public: + + RangeChooserTabPage(weld::Container* pPage, weld::DialogController* pController, DialogModel & rDialogModel, + ChartTypeTemplateProvider* pTemplateProvider, + bool bHideDescription = false); + virtual ~RangeChooserTabPage() override; + + //RangeSelectionListenerParent + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + + virtual void Activate() override; + + void commitPage(); + +private: + + //OWizardPage + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + + //TabPage + virtual void Deactivate() override; + + void initControlsFromModel(); + void changeDialogModelAccordingToControls(); + bool isValid(); + void setDirty(); + + DECL_LINK( ChooseRangeHdl, weld::Button&, void ); + DECL_LINK( ControlChangedHdl, weld::Entry&, void ); + DECL_LINK( ControlChangedCheckBoxHdl, weld::Toggleable&, void ); + DECL_LINK( ControlChangedRadioHdl, weld::Toggleable&, void ); + DECL_LINK( ControlEditedHdl, weld::Entry&, void ); + + sal_Int32 m_nChangingControlCalls; + bool m_bIsDirty; + + OUString m_aLastValidRangeString; + rtl::Reference< ::chart::ChartTypeTemplate > m_xCurrentChartTypeTemplate; + ChartTypeTemplateProvider* m_pTemplateProvider; + + DialogModel & m_rDialogModel; + TabPageNotifiable * m_pTabPageNotifiable; + + std::unique_ptr m_xFT_Caption; + std::unique_ptr m_xFT_Range; + std::unique_ptr m_xED_Range; + std::unique_ptr m_xIB_Range; + std::unique_ptr m_xRB_Rows; + std::unique_ptr m_xRB_Columns; + std::unique_ptr m_xCB_FirstRowAsLabel; + std::unique_ptr m_xCB_FirstColumnAsLabel; + std::unique_ptr m_xFTTitle; + std::unique_ptr m_xFL_TimeBased; + std::unique_ptr m_xCB_TimeBased; + std::unique_ptr m_xFT_TimeStart; + std::unique_ptr m_xEd_TimeStart; + std::unique_ptr m_xFT_TimeEnd; + std::unique_ptr m_xEd_TimeEnd; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Scale.cxx b/chart2/source/controller/dialogs/tp_Scale.cxx new file mode 100644 index 000000000..7147dfa84 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Scale.cxx @@ -0,0 +1,637 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_Scale.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +namespace +{ + +void lcl_setValue(weld::FormattedSpinButton& rFmtField, double fValue) +{ + rFmtField.GetFormatter().SetValue(fValue); +} + +} + +ScaleTabPage::ScaleTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_Scale.ui", "tp_Scale", &rInAttrs) + , fMin(0.0) + , fMax(0.0) + , fStepMain(0.0) + , nStepHelp(0) + , fOrigin(0.0) + , m_nTimeResolution(1) + , m_nMainTimeUnit(1) + , m_nHelpTimeUnit(1) + , m_nAxisType(chart2::AxisType::REALNUMBER) + , m_bAllowDateAxis(false) + , pNumFormatter(nullptr) + , m_bShowAxisOrigin(false) + , m_xCbxReverse(m_xBuilder->weld_check_button("CBX_REVERSE")) + , m_xCbxLogarithm(m_xBuilder->weld_check_button("CBX_LOGARITHM")) + , m_xBxType(m_xBuilder->weld_widget("boxTYPE")) + , m_xLB_AxisType(m_xBuilder->weld_combo_box("LB_AXIS_TYPE")) + , m_xBxMinMax(m_xBuilder->weld_widget("gridMINMAX")) + , m_xFmtFldMin(m_xBuilder->weld_formatted_spin_button("EDT_MIN")) + , m_xCbxAutoMin(m_xBuilder->weld_check_button("CBX_AUTO_MIN")) + , m_xFmtFldMax(m_xBuilder->weld_formatted_spin_button("EDT_MAX")) + , m_xCbxAutoMax(m_xBuilder->weld_check_button("CBX_AUTO_MAX")) + , m_xBxResolution(m_xBuilder->weld_widget("boxRESOLUTION")) + , m_xLB_TimeResolution(m_xBuilder->weld_combo_box("LB_TIME_RESOLUTION")) + , m_xCbx_AutoTimeResolution(m_xBuilder->weld_check_button("CBX_AUTO_TIME_RESOLUTION")) + , m_xTxtMain(m_xBuilder->weld_label("TXT_STEP_MAIN")) + , m_xFmtFldStepMain(m_xBuilder->weld_formatted_spin_button("EDT_STEP_MAIN")) + , m_xMt_MainDateStep(m_xBuilder->weld_spin_button("MT_MAIN_DATE_STEP")) + , m_xLB_MainTimeUnit(m_xBuilder->weld_combo_box("LB_MAIN_TIME_UNIT")) + , m_xCbxAutoStepMain(m_xBuilder->weld_check_button("CBX_AUTO_STEP_MAIN")) + , m_xTxtHelpCount(m_xBuilder->weld_label("TXT_STEP_HELP_COUNT")) + , m_xTxtHelp(m_xBuilder->weld_label("TXT_STEP_HELP")) + , m_xMtStepHelp(m_xBuilder->weld_spin_button("MT_STEPHELP")) + , m_xLB_HelpTimeUnit(m_xBuilder->weld_combo_box("LB_HELP_TIME_UNIT")) + , m_xCbxAutoStepHelp(m_xBuilder->weld_check_button("CBX_AUTO_STEP_HELP")) + , m_xFmtFldOrigin(m_xBuilder->weld_formatted_spin_button("EDT_ORIGIN")) + , m_xCbxAutoOrigin(m_xBuilder->weld_check_button("CBX_AUTO_ORIGIN")) + , m_xBxOrigin(m_xBuilder->weld_widget("boxORIGIN")) +{ + m_xCbxAutoMin->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoMax->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoStepMain->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoStepHelp->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbxAutoOrigin->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + m_xCbx_AutoTimeResolution->connect_toggled(LINK(this, ScaleTabPage, EnableValueHdl)); + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + rFmtFldMax.ClearMinValue(); + rFmtFldMax.ClearMaxValue(); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + rFmtFldMin.ClearMinValue(); + rFmtFldMin.ClearMaxValue(); + Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter(); + rFmtFldStepMain.ClearMinValue(); + rFmtFldStepMain.ClearMaxValue(); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + rFmtFldOrigin.ClearMinValue(); + rFmtFldOrigin.ClearMaxValue(); + + m_xLB_AxisType->connect_changed(LINK(this, ScaleTabPage, SelectAxisTypeHdl)); + + HideAllControls(); +} + +ScaleTabPage::~ScaleTabPage() +{ +} + +void ScaleTabPage::EnableControls() +{ + bool bValueAxis = m_nAxisType == chart2::AxisType::REALNUMBER + || m_nAxisType == chart2::AxisType::PERCENT + || m_nAxisType == chart2::AxisType::DATE; + bool bDateAxis = m_nAxisType == chart2::AxisType::DATE; + + m_xBxType->set_visible(m_bAllowDateAxis); + + m_xCbxLogarithm->set_visible( bValueAxis && !bDateAxis ); + + m_xBxMinMax->set_visible(bValueAxis); + + m_xTxtMain->set_visible( bValueAxis ); + m_xCbxAutoStepMain->set_visible( bValueAxis ); + + m_xTxtHelpCount->set_visible( bValueAxis && !bDateAxis ); + m_xTxtHelp->set_visible( bDateAxis ); + m_xMtStepHelp->set_visible( bValueAxis ); + m_xCbxAutoStepHelp->set_visible( bValueAxis ); + + m_xBxOrigin->set_visible( m_bShowAxisOrigin && bValueAxis ); + m_xBxResolution->set_visible( bDateAxis ); + + bool bWasDateAxis = m_xMt_MainDateStep->get_visible(); + if( bWasDateAxis != bDateAxis ) + { + //transport value from one to other control + if( bWasDateAxis ) + lcl_setValue( *m_xFmtFldStepMain, m_xMt_MainDateStep->get_value() ); + else + m_xMt_MainDateStep->set_value(m_xFmtFldStepMain->GetFormatter().GetValue()); + } + + m_xFmtFldStepMain->set_visible( bValueAxis && !bDateAxis ); + m_xMt_MainDateStep->set_visible( bDateAxis ); + + m_xLB_MainTimeUnit->set_visible( bDateAxis ); + m_xLB_HelpTimeUnit->set_visible( bDateAxis ); + + EnableValueHdl(*m_xCbxAutoMin); + EnableValueHdl(*m_xCbxAutoMax); + EnableValueHdl(*m_xCbxAutoStepMain); + EnableValueHdl(*m_xCbxAutoStepHelp); + EnableValueHdl(*m_xCbxAutoOrigin); + EnableValueHdl(*m_xCbx_AutoTimeResolution); +} + +IMPL_LINK( ScaleTabPage, EnableValueHdl, weld::Toggleable&, rCbx, void ) +{ + bool bEnable = !rCbx.get_active() && rCbx.get_sensitive(); + if (&rCbx == m_xCbxAutoMin.get()) + { + m_xFmtFldMin->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoMax.get()) + { + m_xFmtFldMax->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoStepMain.get()) + { + m_xFmtFldStepMain->set_sensitive( bEnable ); + m_xMt_MainDateStep->set_sensitive( bEnable ); + m_xLB_MainTimeUnit->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoStepHelp.get()) + { + m_xMtStepHelp->set_sensitive( bEnable ); + m_xLB_HelpTimeUnit->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbx_AutoTimeResolution.get()) + { + m_xLB_TimeResolution->set_sensitive( bEnable ); + } + else if (&rCbx == m_xCbxAutoOrigin.get()) + { + m_xFmtFldOrigin->set_sensitive( bEnable ); + } +} + +namespace { + +enum AxisTypeListBoxEntry +{ + TYPE_AUTO=0, + TYPE_TEXT=1, + TYPE_DATE=2 +}; + +} + +IMPL_LINK_NOARG(ScaleTabPage, SelectAxisTypeHdl, weld::ComboBox&, void) +{ + const sal_Int32 nPos = m_xLB_AxisType->get_active(); + if( nPos==TYPE_DATE ) + m_nAxisType = chart2::AxisType::DATE; + else + m_nAxisType = chart2::AxisType::CATEGORY; + if( m_nAxisType == chart2::AxisType::DATE ) + m_xCbxLogarithm->set_active(false); + EnableControls(); + SetNumFormat(); +} + +std::unique_ptr ScaleTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool ScaleTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + OSL_PRECOND( pNumFormatter, "No NumberFormatter available" ); + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXISTYPE, m_nAxisType)); + if(m_bAllowDateAxis) + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_DATEAXIS, m_xLB_AxisType->get_active()==TYPE_AUTO)); + + bool bAutoScale = false; + if( m_nAxisType==chart2::AxisType::CATEGORY ) + bAutoScale = true;//reset scaling for category charts + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MIN ,bAutoScale || m_xCbxAutoMin->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_MAX ,bAutoScale || m_xCbxAutoMax->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP,bAutoScale || m_xCbxAutoStepHelp->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN ,bAutoScale || m_xCbxAutoOrigin->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM ,m_xCbxLogarithm->get_active())); + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_REVERSE ,m_xCbxReverse->get_active())); + rOutAttrs->Put(SvxDoubleItem(fMax , SCHATTR_AXIS_MAX)); + rOutAttrs->Put(SvxDoubleItem(fMin , SCHATTR_AXIS_MIN)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_STEP_HELP, nStepHelp)); + rOutAttrs->Put(SvxDoubleItem(fOrigin , SCHATTR_AXIS_ORIGIN)); + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN,bAutoScale || m_xCbxAutoStepMain->get_active())); + rOutAttrs->Put(SvxDoubleItem(fStepMain,SCHATTR_AXIS_STEP_MAIN)); + + rOutAttrs->Put(SfxBoolItem(SCHATTR_AXIS_AUTO_TIME_RESOLUTION,bAutoScale || m_xCbx_AutoTimeResolution->get_active())); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_TIME_RESOLUTION,m_nTimeResolution)); + + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_MAIN_TIME_UNIT,m_nMainTimeUnit)); + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS_HELP_TIME_UNIT,m_nHelpTimeUnit)); + + return true; +} + +void ScaleTabPage::Reset(const SfxItemSet* rInAttrs) +{ + OSL_PRECOND( pNumFormatter, "No NumberFormatter available" ); + if(!pNumFormatter) + return; + + if (const SfxBoolItem* pDateAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_ALLOW_DATEAXIS)) + m_bAllowDateAxis = pDateAxisItem->GetValue(); + m_nAxisType=chart2::AxisType::REALNUMBER; + if (const SfxInt32Item* pAxisTypeItem = rInAttrs->GetItemIfSet(SCHATTR_AXISTYPE)) + m_nAxisType = static_cast(pAxisTypeItem->GetValue()); + if( m_nAxisType==chart2::AxisType::DATE && !m_bAllowDateAxis ) + m_nAxisType=chart2::AxisType::CATEGORY; + if( m_bAllowDateAxis ) + { + bool bAutoDateAxis = false; + if (const SfxBoolItem* pDateAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_DATEAXIS)) + bAutoDateAxis = pDateAxisItem->GetValue(); + + sal_uInt16 nPos = 0; + if( m_nAxisType==chart2::AxisType::DATE ) + nPos=TYPE_DATE; + else if( bAutoDateAxis ) + nPos=TYPE_AUTO; + else + nPos=TYPE_TEXT; + m_xLB_AxisType->set_active( nPos ); + } + + m_xCbxAutoMin->set_active(true); + m_xCbxAutoMax->set_active(true); + m_xCbxAutoStepMain->set_active(true); + m_xCbxAutoStepHelp->set_active(true); + m_xCbxAutoOrigin->set_active(true); + m_xCbx_AutoTimeResolution->set_active(true); + + if (const SfxBoolItem* pAutoMinItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_MIN)) + m_xCbxAutoMin->set_active(pAutoMinItem->GetValue()); + + if (const SvxDoubleItem* pAxisMinItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MIN)) + { + fMin = pAxisMinItem->GetValue(); + lcl_setValue( *m_xFmtFldMin, fMin ); + m_xFmtFldMin->save_value(); + } + + if (const SfxBoolItem* pAutoMaxItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_MAX)) + m_xCbxAutoMax->set_active(pAutoMaxItem->GetValue()); + + if (const SvxDoubleItem* pAxisMaxItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MAX)) + { + fMax = pAxisMaxItem->GetValue(); + lcl_setValue( *m_xFmtFldMax, fMax ); + m_xFmtFldMax->save_value(); + } + + if (const SfxBoolItem* pAutoStepMainItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_STEP_MAIN)) + m_xCbxAutoStepMain->set_active(pAutoStepMainItem->GetValue()); + + if (const SvxDoubleItem* pStepMainItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_STEP_MAIN)) + { + fStepMain = pStepMainItem->GetValue(); + lcl_setValue( *m_xFmtFldStepMain, fStepMain ); + m_xFmtFldStepMain->save_value(); + m_xMt_MainDateStep->set_value( static_cast(fStepMain) ); + m_xMt_MainDateStep->save_value(); + } + if (const SfxBoolItem* pAutoStepHelpItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_STEP_HELP)) + m_xCbxAutoStepHelp->set_active(pAutoStepHelpItem->GetValue()); + if (const SfxBoolItem* pLogItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_LOGARITHM)) + m_xCbxLogarithm->set_active(pLogItem->GetValue()); + if (const SfxBoolItem* pReverseItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_REVERSE)) + m_xCbxReverse->set_active(pReverseItem->GetValue()); + if (const SfxInt32Item* pStepHelpItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_STEP_HELP)) + { + nStepHelp = pStepHelpItem->GetValue(); + m_xMtStepHelp->set_value( nStepHelp ); + m_xMtStepHelp->save_value(); + } + if (const SfxBoolItem* pOriginItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_ORIGIN)) + m_xCbxAutoOrigin->set_active(pOriginItem->GetValue()); + if (const SvxDoubleItem* pOriginItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_ORIGIN)) + { + fOrigin = pOriginItem->GetValue(); + lcl_setValue( *m_xFmtFldOrigin, fOrigin ); + m_xFmtFldOrigin->save_value(); + } + + if (const SfxBoolItem* pAutoTimeResItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_AUTO_TIME_RESOLUTION)) + m_xCbx_AutoTimeResolution->set_active(pAutoTimeResItem->GetValue()); + if (const SfxInt32Item* pTimeResItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_TIME_RESOLUTION)) + { + m_nTimeResolution = pTimeResItem->GetValue(); + m_xLB_TimeResolution->set_active( m_nTimeResolution ); + } + + if (const SfxInt32Item* pMainTimeUnitItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_MAIN_TIME_UNIT)) + { + m_nMainTimeUnit = pMainTimeUnitItem->GetValue(); + m_xLB_MainTimeUnit->set_active( m_nMainTimeUnit ); + } + if (const SfxInt32Item* pHelpTimeUnitItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_HELP_TIME_UNIT)) + { + m_nHelpTimeUnit = pHelpTimeUnitItem->GetValue(); + m_xLB_HelpTimeUnit->set_active( m_nHelpTimeUnit ); + } + + EnableControls(); + SetNumFormat(); +} + +DeactivateRC ScaleTabPage::DeactivatePage(SfxItemSet* pItemSet) +{ + if( !pNumFormatter ) + { + OSL_FAIL( "No NumberFormatter available" ); + return DeactivateRC::LeavePage; + } + + bool bDateAxis = m_nAxisType == chart2::AxisType::DATE; + + sal_uInt32 nMinMaxOriginFmt = m_xFmtFldMax->GetFormatter().GetFormatKey(); + if (pNumFormatter->GetType(nMinMaxOriginFmt) == SvNumFormatType::TEXT) + nMinMaxOriginFmt = 0; + // numberformat_text cause numbers to fail being numbers... Shouldn't happen, but can. + sal_uInt32 nStepFmt = m_xFmtFldStepMain->GetFormatter().GetFormatKey(); + if (pNumFormatter->GetType(nStepFmt) == SvNumFormatType::TEXT) + nStepFmt = 0; + + weld::Widget* pControl = nullptr; + TranslateId pErrStrId; + double fDummy; + + fMax = m_xFmtFldMax->GetFormatter().GetValue(); + fMin = m_xFmtFldMin->GetFormatter().GetValue(); + fOrigin = m_xFmtFldOrigin->GetFormatter().GetValue(); + fStepMain = bDateAxis ? m_xMt_MainDateStep->get_value() : m_xFmtFldStepMain->GetFormatter().GetValue(); + nStepHelp = m_xMtStepHelp->get_value(); + m_nTimeResolution = m_xLB_TimeResolution->get_active(); + m_nMainTimeUnit = m_xLB_MainTimeUnit->get_active(); + m_nHelpTimeUnit = m_xLB_HelpTimeUnit->get_active(); + + if( m_nAxisType != chart2::AxisType::REALNUMBER ) + m_xCbxLogarithm->hide(); + + //check which entries need user action + + if ( m_xCbxLogarithm->get_active() && + ( ( !m_xCbxAutoMin->get_active() && fMin <= 0.0 ) + || ( !m_xCbxAutoMax->get_active() && fMax <= 0.0 ) ) ) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_BAD_LOGARITHM; + } + // check for entries that cannot be parsed for the current number format + else if ( m_xFmtFldMin->get_value_changed_from_saved() + && !m_xCbxAutoMin->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldMin->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if ( m_xFmtFldMax->get_value_changed_from_saved() + && !m_xCbxAutoMax->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldMax->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldMax.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if ( !bDateAxis && m_xFmtFldStepMain->get_value_changed_from_saved() + && !m_xCbxAutoStepMain->get_active() + && !pNumFormatter->IsNumberFormat( m_xFmtFldStepMain->get_text(), nStepFmt, fDummy)) + { + pControl = m_xFmtFldStepMain.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if (m_xFmtFldOrigin->get_value_changed_from_saved() && !m_xCbxAutoOrigin->get_active() && + !pNumFormatter->IsNumberFormat( m_xFmtFldOrigin->get_text(), nMinMaxOriginFmt, fDummy)) + { + pControl = m_xFmtFldOrigin.get(); + pErrStrId = STR_INVALID_NUMBER; + } + else if (!m_xCbxAutoStepMain->get_active() && fStepMain <= 0.0) + { + pControl = m_xFmtFldStepMain.get(); + pErrStrId = STR_STEP_GT_ZERO; + } + else if (!m_xCbxAutoMax->get_active() && !m_xCbxAutoMin->get_active() && + fMin >= fMax) + { + pControl = m_xFmtFldMin.get(); + pErrStrId = STR_MIN_GREATER_MAX; + } + else if( bDateAxis ) + { + if( !m_xCbxAutoStepMain->get_active() && !m_xCbxAutoStepHelp->get_active() ) + { + if( m_nHelpTimeUnit > m_nMainTimeUnit ) + { + pControl = m_xLB_MainTimeUnit.get(); + pErrStrId = STR_INVALID_INTERVALS; + } + else if( m_nHelpTimeUnit == m_nMainTimeUnit && nStepHelp > fStepMain ) + { + pControl = m_xLB_MainTimeUnit.get(); + pErrStrId = STR_INVALID_INTERVALS; + } + } + if( !pErrStrId && !m_xCbx_AutoTimeResolution->get_active() ) + { + if( (!m_xCbxAutoStepMain->get_active() && m_nTimeResolution > m_nMainTimeUnit ) + || + (!m_xCbxAutoStepHelp->get_active() && m_nTimeResolution > m_nHelpTimeUnit ) + ) + { + pControl = m_xLB_TimeResolution.get(); + pErrStrId = STR_INVALID_TIME_UNIT; + } + } + } + + if( ShowWarning( pErrStrId, pControl ) ) + return DeactivateRC::KeepPage; + + if( pItemSet ) + FillItemSet( pItemSet ); + + return DeactivateRC::LeavePage; +} + +void ScaleTabPage::SetNumFormatter( SvNumberFormatter* pFormatter ) +{ + pNumFormatter = pFormatter; + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + Formatter& rFmtFldStepMain = m_xFmtFldStepMain->GetFormatter(); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + + rFmtFldMax.SetFormatter( pNumFormatter ); + rFmtFldMin.SetFormatter( pNumFormatter ); + rFmtFldStepMain.SetFormatter( pNumFormatter ); + rFmtFldOrigin.SetFormatter( pNumFormatter ); + + // #i6278# allow more decimal places than the output format. As + // the numbers shown in the edit fields are used for input, it makes more + // sense to display the values in the input format rather than the output + // format. + rFmtFldMax.UseInputStringForFormatting(); + rFmtFldMin.UseInputStringForFormatting(); + rFmtFldStepMain.UseInputStringForFormatting(); + rFmtFldOrigin.UseInputStringForFormatting(); + + SetNumFormat(); +} + +void ScaleTabPage::SetNumFormat() +{ + const SfxUInt32Item *pNumFormatItem = GetItemSet().GetItemIfSet( SID_ATTR_NUMBERFORMAT_VALUE ); + + if( !pNumFormatItem ) + return; + + sal_uLong nFmt = pNumFormatItem->GetValue(); + + Formatter& rFmtFldMax = m_xFmtFldMax->GetFormatter(); + rFmtFldMax.SetFormatKey(nFmt); + Formatter& rFmtFldMin = m_xFmtFldMin->GetFormatter(); + rFmtFldMin.SetFormatKey(nFmt); + Formatter& rFmtFldOrigin = m_xFmtFldOrigin->GetFormatter(); + rFmtFldOrigin.SetFormatKey(nFmt); + + if( pNumFormatter ) + { + SvNumFormatType eType = pNumFormatter->GetType( nFmt ); + if( eType == SvNumFormatType::DATE ) + { + // for intervals use standard format for dates (so you can enter a number of days) + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardIndex( pFormat->GetLanguage()); + else + nFmt = pNumFormatter->GetStandardIndex(); + } + else if( eType == SvNumFormatType::DATETIME ) + { + // for intervals use time format for date times + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::TIME, pFormat->GetLanguage() ); + else + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::TIME ); + + // tdf#141625 give enough space to see full date+time + int nWidestTime(m_xFmtFldMin->get_pixel_size(getWidestDateTime(Application::GetSettings().GetLocaleDataWrapper(), true)).Width()); + int nWidthChars = std::ceil(nWidestTime / m_xFmtFldMin->get_approximate_digit_width()) + 1; + m_xFmtFldMin->set_width_chars(nWidthChars); + m_xFmtFldMax->set_width_chars(nWidthChars); + } + + if( m_nAxisType == chart2::AxisType::DATE && ( eType != SvNumFormatType::DATE && eType != SvNumFormatType::DATETIME) ) + { + const SvNumberformat* pFormat = pNumFormatter->GetEntry( nFmt ); + if( pFormat ) + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::DATE, pFormat->GetLanguage() ); + else + nFmt = pNumFormatter->GetStandardFormat( SvNumFormatType::DATE ); + + rFmtFldMax.SetFormatKey(nFmt); + rFmtFldMin.SetFormatKey(nFmt); + rFmtFldOrigin.SetFormatKey(nFmt); + } + } + + m_xFmtFldStepMain->GetFormatter().SetFormatKey(nFmt); +} + +void ScaleTabPage::ShowAxisOrigin( bool bShowOrigin ) +{ + m_bShowAxisOrigin = bShowOrigin; + if( !AxisHelper::isAxisPositioningEnabled() ) + m_bShowAxisOrigin = true; +} + +bool ScaleTabPage::ShowWarning(TranslateId pResIdMessage, weld::Widget* pControl /* = nullptr */) +{ + if (!pResIdMessage) + return false; + + std::unique_ptr xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SchResId(pResIdMessage))); + xWarn->run(); + if (pControl) + { + pControl->grab_focus(); + weld::Entry* pEdit = dynamic_cast(pControl); + if (pEdit) + pEdit->select_region(0, -1); + } + return true; +} + +void ScaleTabPage::HideAllControls() +{ + // We need to set these controls invisible when the class is instantiated + // since some code in EnableControls() depends on that logic. The real + // visibility of these controls depend on axis data type, and are + // set in EnableControls(). + + m_xBxType->hide(); + m_xCbxLogarithm->hide(); + m_xBxMinMax->hide(); + m_xTxtMain->hide(); + m_xFmtFldStepMain->hide(); + m_xMt_MainDateStep->hide(); + m_xLB_MainTimeUnit->hide(); + m_xCbxAutoStepMain->hide(); + m_xTxtHelpCount->hide(); + m_xTxtHelp->hide(); + m_xMtStepHelp->hide(); + m_xCbxAutoStepHelp->hide(); + m_xBxOrigin->hide(); + m_xBxResolution->hide(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Scale.hxx b/chart2/source/controller/dialogs/tp_Scale.hxx new file mode 100644 index 000000000..b90d3ef20 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Scale.hxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart +{ + +class ScaleTabPage : public SfxTabPage +{ +public: + ScaleTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~ScaleTabPage() override; + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + virtual DeactivateRC DeactivatePage( SfxItemSet* pItemSet ) override; + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNumFormat(); + + void ShowAxisOrigin( bool bShowOrigin ); + +private: + double fMin; + double fMax; + double fStepMain; + sal_Int32 nStepHelp; + double fOrigin; + sal_Int32 m_nTimeResolution; + sal_Int32 m_nMainTimeUnit; + sal_Int32 m_nHelpTimeUnit; + int m_nAxisType; + bool m_bAllowDateAxis; + SvNumberFormatter* pNumFormatter; + + bool m_bShowAxisOrigin; + + std::unique_ptr m_xCbxReverse; + std::unique_ptr m_xCbxLogarithm; + std::unique_ptr m_xBxType; + std::unique_ptr m_xLB_AxisType; + std::unique_ptr m_xBxMinMax; + std::unique_ptr m_xFmtFldMin; + std::unique_ptr m_xCbxAutoMin; + std::unique_ptr m_xFmtFldMax; + std::unique_ptr m_xCbxAutoMax; + std::unique_ptr m_xBxResolution; + std::unique_ptr m_xLB_TimeResolution; + std::unique_ptr m_xCbx_AutoTimeResolution; + std::unique_ptr m_xTxtMain; + std::unique_ptr m_xFmtFldStepMain; + std::unique_ptr m_xMt_MainDateStep; + std::unique_ptr m_xLB_MainTimeUnit; + std::unique_ptr m_xCbxAutoStepMain; + std::unique_ptr m_xTxtHelpCount; + std::unique_ptr m_xTxtHelp; + std::unique_ptr m_xMtStepHelp; + std::unique_ptr m_xLB_HelpTimeUnit; + std::unique_ptr m_xCbxAutoStepHelp; + std::unique_ptr m_xFmtFldOrigin; + std::unique_ptr m_xCbxAutoOrigin; + std::unique_ptr m_xBxOrigin; + + void EnableControls(); + + DECL_LINK(SelectAxisTypeHdl, weld::ComboBox&, void); + DECL_LINK(EnableValueHdl, weld::Toggleable&, void); + + /** shows a warning window due to an invalid input. + + @param pResIdMessage + The resource identifier that represents the localized warning text. + If this is nullptr, no warning is shown and false is returned. + + @param pControl + If non-NULL, contains a pointer to the control in which the + erroneous value was in. This method gives this control the focus + and selects its content. + + @return false, if nResIdMessage was 0, true otherwise + */ + bool ShowWarning(TranslateId pResIdMessage, weld::Widget* pControl); + + void HideAllControls(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx b/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx new file mode 100644 index 000000000..3ffbc3642 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_SeriesToAxis.cxx @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_SeriesToAxis.hxx" + +#include + +#include +#include +#include + +#include + +namespace chart +{ + +SchOptionTabPage::SchOptionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_SeriesToAxis.ui", "TP_OPTIONS", &rInAttrs) + , m_nAllSeriesAxisIndex(0) + , m_bProvidesSecondaryYAxis(true) + , m_bProvidesOverlapAndGapWidth(false) + , m_bProvidesBarConnectors(false) + , m_xGrpAxis(m_xBuilder->weld_widget("frameGrpAxis")) + , m_xRbtAxis1(m_xBuilder->weld_radio_button("RBT_OPT_AXIS_1")) + , m_xRbtAxis2(m_xBuilder->weld_radio_button("RBT_OPT_AXIS_2")) + , m_xGrpBar(m_xBuilder->weld_widget("frameSettings")) + , m_xMTGap(m_xBuilder->weld_metric_spin_button("MT_GAP", FieldUnit::PERCENT)) + , m_xMTOverlap(m_xBuilder->weld_metric_spin_button("MT_OVERLAP", FieldUnit::PERCENT)) + , m_xCBConnect(m_xBuilder->weld_check_button("CB_CONNECTOR")) + , m_xCBAxisSideBySide(m_xBuilder->weld_check_button("CB_BARS_SIDE_BY_SIDE")) + , m_xGrpPlotOptions(m_xBuilder->weld_widget("frameFL_PLOT_OPTIONS")) + , m_xGridPlotOptions(m_xBuilder->weld_widget("gridPLOT_OPTIONS")) + , m_xRB_DontPaint(m_xBuilder->weld_radio_button("RB_DONT_PAINT")) + , m_xRB_AssumeZero(m_xBuilder->weld_radio_button("RB_ASSUME_ZERO")) + , m_xRB_ContinueLine(m_xBuilder->weld_radio_button("RB_CONTINUE_LINE")) + , m_xCBIncludeHiddenCells(m_xBuilder->weld_check_button("CB_INCLUDE_HIDDEN_CELLS")) + , m_xCBHideLegendEntry(m_xBuilder->weld_check_button("CB_LEGEND_ENTRY_HIDDEN")) +{ + m_xRbtAxis1->connect_toggled(LINK(this, SchOptionTabPage, EnableHdl)); + m_xRbtAxis2->connect_toggled(LINK(this, SchOptionTabPage, EnableHdl)); +} + +SchOptionTabPage::~SchOptionTabPage() +{ +} + +IMPL_LINK_NOARG(SchOptionTabPage, EnableHdl, weld::Toggleable&, void) +{ + if( m_nAllSeriesAxisIndex == 0 ) + m_xCBAxisSideBySide->set_sensitive( m_xRbtAxis2->get_active()); + else if( m_nAllSeriesAxisIndex == 1 ) + m_xCBAxisSideBySide->set_sensitive( m_xRbtAxis1->get_active()); +} + +std::unique_ptr SchOptionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool SchOptionTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + if(m_xRbtAxis2->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS,CHART_AXIS_SECONDARY_Y)); + else + rOutAttrs->Put(SfxInt32Item(SCHATTR_AXIS,CHART_AXIS_PRIMARY_Y)); + + if(m_xMTGap->get_visible()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_BAR_GAPWIDTH,static_cast< sal_Int32 >( m_xMTGap->get_value(FieldUnit::PERCENT)))); + + if(m_xMTOverlap->get_visible()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_BAR_OVERLAP,static_cast< sal_Int32 >( m_xMTOverlap->get_value(FieldUnit::PERCENT)))); + + if(m_xCBConnect->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_BAR_CONNECT,m_xCBConnect->get_active())); + + // model property is "group bars per axis", UI feature is the other way + // round: "show bars side by side" + if(m_xCBAxisSideBySide->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_GROUP_BARS_PER_AXIS, ! m_xCBAxisSideBySide->get_active())); + + if(m_xRB_DontPaint->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::LEAVE_GAP)); + else if(m_xRB_AssumeZero->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::USE_ZERO)); + else if(m_xRB_ContinueLine->get_active()) + rOutAttrs->Put(SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT,css::chart::MissingValueTreatment::CONTINUE)); + + if (m_xCBIncludeHiddenCells->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, m_xCBIncludeHiddenCells->get_active())); + + if(m_xCBHideLegendEntry->get_visible()) + rOutAttrs->Put(SfxBoolItem(SCHATTR_HIDE_LEGEND_ENTRY, m_xCBHideLegendEntry->get_active())); + + return true; +} + +void SchOptionTabPage::Reset(const SfxItemSet* rInAttrs) +{ + m_xRbtAxis1->set_active(true); + m_xRbtAxis2->set_active(false); + if (const SfxInt32Item* pAxisItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS)) + { + tools::Long nVal = pAxisItem->GetValue(); + if(nVal==CHART_AXIS_SECONDARY_Y) + { + m_xRbtAxis2->set_active(true); + m_xRbtAxis1->set_active(false); + } + } + + tools::Long nTmp; + if (const SfxInt32Item* pGapWidthItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_GAPWIDTH)) + { + nTmp = static_cast(pGapWidthItem->GetValue()); + m_xMTGap->set_value(nTmp, FieldUnit::PERCENT); + } + + if (const SfxInt32Item* pOverlapItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_OVERLAP)) + { + nTmp = static_cast(pOverlapItem->GetValue()); + m_xMTOverlap->set_value(nTmp, FieldUnit::PERCENT); + } + + if (const SfxBoolItem* pConnectItem = rInAttrs->GetItemIfSet(SCHATTR_BAR_CONNECT)) + { + bool bCheck = pConnectItem->GetValue(); + m_xCBConnect->set_active(bCheck); + } + + if (const SfxInt32Item* pAllSeriesItem = rInAttrs->GetItemIfSet(SCHATTR_AXIS_FOR_ALL_SERIES)) + { + m_nAllSeriesAxisIndex = pAllSeriesItem->GetValue(); + m_xCBAxisSideBySide->set_sensitive(false); + } + if (const SfxBoolItem* pPerAxisItem = rInAttrs->GetItemIfSet(SCHATTR_GROUP_BARS_PER_AXIS)) + { + // model property is "group bars per axis", UI feature is the other way + // round: "show bars side by side" + bool bCheck = ! pPerAxisItem->GetValue(); + m_xCBAxisSideBySide->set_active( bCheck ); + } + else + { + m_xCBAxisSideBySide->hide(); + } + + //missing value treatment + { + std::vector< sal_Int32 > aMissingValueTreatments; + if (const SfxIntegerListItem* pValueTreatmentsItem = rInAttrs->GetItemIfSet(SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS)) + aMissingValueTreatments = pValueTreatmentsItem->GetList(); + + const SfxInt32Item* pMissingValueTreatmentItem; + if ( aMissingValueTreatments.size()>1 && + (pMissingValueTreatmentItem = rInAttrs->GetItemIfSet(SCHATTR_MISSING_VALUE_TREATMENT)) ) + { + m_xRB_DontPaint->set_sensitive(false); + m_xRB_AssumeZero->set_sensitive(false); + m_xRB_ContinueLine->set_sensitive(false); + + for(int nVal : aMissingValueTreatments) + { + if(nVal==css::chart::MissingValueTreatment::LEAVE_GAP) + m_xRB_DontPaint->set_sensitive(true); + else if(nVal==css::chart::MissingValueTreatment::USE_ZERO) + m_xRB_AssumeZero->set_sensitive(true); + else if(nVal==css::chart::MissingValueTreatment::CONTINUE) + m_xRB_ContinueLine->set_sensitive(true); + } + + tools::Long nVal=pMissingValueTreatmentItem->GetValue(); + if(nVal==css::chart::MissingValueTreatment::LEAVE_GAP) + m_xRB_DontPaint->set_active(true); + else if(nVal==css::chart::MissingValueTreatment::USE_ZERO) + m_xRB_AssumeZero->set_active(true); + else if(nVal==css::chart::MissingValueTreatment::CONTINUE) + m_xRB_ContinueLine->set_active(true); + } + else + { + m_xGridPlotOptions->hide(); + } + } + + // Include hidden cells + if (const SfxBoolItem* pHiddenCellsItem = rInAttrs->GetItemIfSet(SCHATTR_INCLUDE_HIDDEN_CELLS)) + { + bool bVal = pHiddenCellsItem->GetValue(); + m_xCBIncludeHiddenCells->set_active(bVal); + } + else + { + m_xCBIncludeHiddenCells->hide(); + // check if the radiobutton guys above + // are visible. If they aren't, we can + // as well hide the whole frame + if(!m_xGridPlotOptions->get_visible()) + m_xGrpPlotOptions->hide(); + } + + if (const SfxBoolItem* pEntryItem = rInAttrs->GetItemIfSet(SCHATTR_HIDE_LEGEND_ENTRY)) + { + bool bVal = pEntryItem->GetValue(); + m_xCBHideLegendEntry->set_active(bVal); + } + + AdaptControlPositionsAndVisibility(); +} + +void SchOptionTabPage::Init( bool bProvidesSecondaryYAxis, bool bProvidesOverlapAndGapWidth, bool bProvidesBarConnectors ) +{ + m_bProvidesSecondaryYAxis = bProvidesSecondaryYAxis; + m_bProvidesOverlapAndGapWidth = bProvidesOverlapAndGapWidth; + m_bProvidesBarConnectors = bProvidesBarConnectors; + + AdaptControlPositionsAndVisibility(); +} + +void SchOptionTabPage::AdaptControlPositionsAndVisibility() +{ + m_xGrpAxis->set_visible(m_bProvidesSecondaryYAxis); + m_xGrpBar->set_visible(m_bProvidesOverlapAndGapWidth); + m_xCBConnect->set_visible(m_bProvidesBarConnectors); + + if (!m_xMTGap->get_visible() && !m_xMTOverlap->get_visible()) + m_xGrpBar->hide(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx b/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx new file mode 100644 index 000000000..6b163f3c8 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_SeriesToAxis.hxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace weld { + class CheckButton; + class MetricSpinButton; + class RadioButton; + class ToggleButton; + class Widget; +} + +namespace chart +{ + +class SchOptionTabPage : public SfxTabPage +{ +public: + SchOptionTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + virtual ~SchOptionTabPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; + + void Init( bool bProvidesSecondaryYAxis, bool bProvidesOverlapAndGapWidth, bool bProvidesBarConnectors ); + +private: //methods + void AdaptControlPositionsAndVisibility(); + +private: //member + DECL_LINK(EnableHdl, weld::Toggleable&, void ); + + sal_Int32 m_nAllSeriesAxisIndex; + + bool m_bProvidesSecondaryYAxis; + bool m_bProvidesOverlapAndGapWidth; + bool m_bProvidesBarConnectors; + + std::unique_ptr m_xGrpAxis; + std::unique_ptr m_xRbtAxis1; + std::unique_ptr m_xRbtAxis2; + std::unique_ptr m_xGrpBar; + std::unique_ptr m_xMTGap; + std::unique_ptr m_xMTOverlap; + std::unique_ptr m_xCBConnect; + std::unique_ptr m_xCBAxisSideBySide; + std::unique_ptr m_xGrpPlotOptions; + std::unique_ptr m_xGridPlotOptions; + std::unique_ptr m_xRB_DontPaint; + std::unique_ptr m_xRB_AssumeZero; + std::unique_ptr m_xRB_ContinueLine; + std::unique_ptr m_xCBIncludeHiddenCells; + std::unique_ptr m_xCBHideLegendEntry; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_TitleRotation.cxx b/chart2/source/controller/dialogs/tp_TitleRotation.cxx new file mode 100644 index 000000000..2cc802f70 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_TitleRotation.cxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_TitleRotation.hxx" + +#include +#include + +#include +#include +#include + +namespace chart +{ + +SchAlignmentTabPage::SchAlignmentTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs, bool bWithRotation) + : SfxTabPage(pPage, pController, "modules/schart/ui/titlerotationtabpage.ui", "TitleRotationTabPage", &rInAttrs) + , m_xFtRotate(m_xBuilder->weld_label("degreeL")) + , m_xNfRotate(m_xBuilder->weld_metric_spin_button("OrientDegree", FieldUnit::DEGREE)) + , m_xCbStacked(m_xBuilder->weld_check_button("stackedCB")) + , m_xFtTextDirection(m_xBuilder->weld_label("textdirL")) + , m_xFtABCD(m_xBuilder->weld_label("labelABCD")) + , m_xLbTextDirection(new TextDirectionListBox(m_xBuilder->weld_combo_box("textdirLB"))) + , m_xCtrlDial(new svx::DialControl) + , m_xCtrlDialWin(new weld::CustomWeld(*m_xBuilder, "dialCtrl", *m_xCtrlDial)) +{ + m_xCtrlDial->SetLinkedField(m_xNfRotate.get()); + m_xCtrlDial->SetText(m_xFtABCD->get_label()); + m_xCbStacked->connect_toggled(LINK(this, SchAlignmentTabPage, StackedToggleHdl)); + + m_xCtrlDialWin->set_sensitive(true); + m_xNfRotate->set_sensitive(true); + m_xCbStacked->set_sensitive(true); + m_xFtRotate->set_sensitive(true); + + if( !bWithRotation ) + { + m_xCtrlDialWin->hide(); + m_xNfRotate->hide(); + m_xCbStacked->hide(); + m_xFtRotate->hide(); + } +} + +IMPL_LINK_NOARG(SchAlignmentTabPage, StackedToggleHdl, weld::Toggleable&, void) +{ + bool bActive = m_xCbStacked->get_active(); + m_xNfRotate->set_sensitive(!bActive); + m_xCtrlDialWin->set_sensitive(!bActive); + m_xCtrlDial->StyleUpdated(); + m_xFtRotate->set_sensitive(!bActive); +} + +SchAlignmentTabPage::~SchAlignmentTabPage() +{ + m_xCtrlDialWin.reset(); + m_xCtrlDial.reset(); + m_xLbTextDirection.reset(); +} + +std::unique_ptr SchAlignmentTabPage::Create(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rInAttrs) +{ + return std::make_unique(pPage, pController, *rInAttrs); +} + +std::unique_ptr SchAlignmentTabPage::CreateWithoutRotation(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rInAttrs) +{ + return std::make_unique(pPage, pController, *rInAttrs, false); +} + +bool SchAlignmentTabPage::FillItemSet(SfxItemSet* rOutAttrs) +{ + //Since 04/1998 text can be rotated by an arbitrary angle: SCHATTR_TEXT_DEGREES + bool bStacked = m_xCbStacked->get_active(); + rOutAttrs->Put( SfxBoolItem( SCHATTR_TEXT_STACKED, bStacked ) ); + + Degree100 nDegrees = bStacked ? 0_deg100 : m_xCtrlDial->GetRotation(); + rOutAttrs->Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, nDegrees ) ); + + SvxFrameDirection aDirection( m_xLbTextDirection->get_active_id() ); + rOutAttrs->Put( SvxFrameDirectionItem( aDirection, EE_PARA_WRITINGDIR ) ); + + return true; +} + +void SchAlignmentTabPage::Reset(const SfxItemSet* rInAttrs) +{ + const SfxPoolItem* pItem = GetItem( *rInAttrs, SCHATTR_TEXT_DEGREES ); + + Degree100 nDegrees = pItem ? static_cast(pItem)->GetValue() : 0_deg100; + m_xCtrlDial->SetRotation( nDegrees ); + + pItem = GetItem( *rInAttrs, SCHATTR_TEXT_STACKED ); + bool bStacked = pItem && static_cast(pItem)->GetValue(); + m_xCbStacked->set_active(bStacked); + StackedToggleHdl(*m_xCbStacked); + + if( const SvxFrameDirectionItem* pDirectionItem = rInAttrs->GetItemIfSet(EE_PARA_WRITINGDIR) ) + m_xLbTextDirection->set_active_id(pDirectionItem->GetValue()); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_TitleRotation.hxx b/chart2/source/controller/dialogs/tp_TitleRotation.hxx new file mode 100644 index 000000000..b303e4d35 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_TitleRotation.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart { class TextDirectionListBox; } +namespace weld { + class CheckButton; + class CustomWeld; + class Label; + class SpinButton; + class ToggleButton; +} + +namespace chart +{ + +class SchAlignmentTabPage : public SfxTabPage +{ +private: + std::unique_ptr m_xFtRotate; + std::unique_ptr m_xNfRotate; + std::unique_ptr m_xCbStacked; + std::unique_ptr m_xFtTextDirection; + std::unique_ptr m_xFtABCD; + std::unique_ptr m_xLbTextDirection; + std::unique_ptr m_xCtrlDial; + std::unique_ptr m_xCtrlDialWin; + + DECL_LINK(StackedToggleHdl, weld::Toggleable&, void); + +public: + SchAlignmentTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs, bool bWithRotation = true); + virtual ~SchAlignmentTabPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + static std::unique_ptr CreateWithoutRotation(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + virtual bool FillItemSet(SfxItemSet* rOutAttrs) override; + virtual void Reset(const SfxItemSet* rInAttrs) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Trendline.cxx b/chart2/source/controller/dialogs/tp_Trendline.cxx new file mode 100644 index 000000000..fe25959bd --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Trendline.cxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_Trendline.hxx" + +namespace chart +{ + +TrendlineTabPage::TrendlineTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_Trendline.ui", "TP_TRENDLINE", &rInAttrs) + , m_aTrendlineResources(*m_xBuilder, rInAttrs) +{ +} + +std::unique_ptr TrendlineTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rOutAttrs) +{ + return std::make_unique(pPage, pController, *rOutAttrs); +} + +bool TrendlineTabPage::FillItemSet( SfxItemSet* rOutAttrs ) +{ + m_aTrendlineResources.FillItemSet( rOutAttrs ); + return true; +} + +void TrendlineTabPage::Reset( const SfxItemSet* rInAttrs ) +{ + m_aTrendlineResources.Reset( *rInAttrs ); +} + +void TrendlineTabPage::SetNumFormatter( SvNumberFormatter* pNumFormatter ) +{ + m_aTrendlineResources.SetNumFormatter( pNumFormatter ); +} + +void TrendlineTabPage::SetNbPoints( sal_Int32 nNbPoints ) +{ + m_aTrendlineResources.SetNbPoints( nNbPoints ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Trendline.hxx b/chart2/source/controller/dialogs/tp_Trendline.hxx new file mode 100644 index 000000000..3a240af38 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Trendline.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "res_Trendline.hxx" + +#include + +namespace chart +{ + +class TrendlineTabPage : public SfxTabPage +{ +public: + TrendlineTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); + + static std::unique_ptr Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs ); + virtual bool FillItemSet( SfxItemSet* rOutAttrs ) override; + virtual void Reset( const SfxItemSet* rInAttrs ) override; + + void SetNumFormatter( SvNumberFormatter* pFormatter ); + void SetNbPoints( sal_Int32 nNbPoints ); + +private: + TrendlineResources m_aTrendlineResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx new file mode 100644 index 000000000..be6948b51 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.cxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tp_Wizard_TitlesAndObjects.hxx" +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +TitlesAndObjectsTabPage::TitlesAndObjectsTabPage(weld::Container* pPage, weld::DialogController* pController, + const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference< uno::XComponentContext >& xContext ) + : OWizardPage(pPage, pController, "modules/schart/ui/wizelementspage.ui", "WizElementsPage") + , m_xTitleResources(new TitleResources(*m_xBuilder, false)) + , m_xLegendPositionResources(new LegendPositionResources(*m_xBuilder, xContext)) + , m_xChartModel(xChartModel) + , m_xCC(xContext) + , m_bCommitToModel(true) + , m_aTimerTriggeredControllerLock( m_xChartModel ) + , m_xCB_Grid_X(m_xBuilder->weld_check_button("x")) + , m_xCB_Grid_Y(m_xBuilder->weld_check_button("y")) + , m_xCB_Grid_Z(m_xBuilder->weld_check_button("z")) +{ + m_xTitleResources->connect_changed( LINK( this, TitlesAndObjectsTabPage, ChangeEditHdl )); + m_xLegendPositionResources->SetChangeHdl( LINK( this, TitlesAndObjectsTabPage, ChangeHdl )); + + m_xCB_Grid_X->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); + m_xCB_Grid_Y->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); + m_xCB_Grid_Z->connect_toggled( LINK( this, TitlesAndObjectsTabPage, ChangeCheckBoxHdl )); +} + +TitlesAndObjectsTabPage::~TitlesAndObjectsTabPage() +{ +} + +void TitlesAndObjectsTabPage::initializePage() +{ + m_bCommitToModel = false; + + //init titles + { + TitleDialogData aTitleInput; + aTitleInput.readFromModel( m_xChartModel ); + m_xTitleResources->writeToResources( aTitleInput ); + } + + //init legend + { + m_xLegendPositionResources->writeToResources( m_xChartModel ); + } + + //init grid checkboxes + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartModel ); + uno::Sequence< sal_Bool > aPossibilityList; + uno::Sequence< sal_Bool > aExistenceList; + AxisHelper::getAxisOrGridPossibilities( aPossibilityList, xDiagram, false ); + AxisHelper::getAxisOrGridExistence( aExistenceList, xDiagram, false ); + m_xCB_Grid_X->set_sensitive( aPossibilityList[0] ); + m_xCB_Grid_Y->set_sensitive( aPossibilityList[1] ); + m_xCB_Grid_Z->set_sensitive( aPossibilityList[2] ); + m_xCB_Grid_X->set_active( aExistenceList[0] ); + m_xCB_Grid_Y->set_active( aExistenceList[1] ); + m_xCB_Grid_Z->set_active( aExistenceList[2] ); + } + + m_bCommitToModel = true; +} + +bool TitlesAndObjectsTabPage::commitPage( ::vcl::WizardTypes::CommitPageReason /*eReason*/ ) +{ + if( m_xTitleResources->get_value_changed_from_saved() ) //titles may have changed in the meanwhile + commitToModel(); + return true;//return false if this page should not be left +} + +void TitlesAndObjectsTabPage::commitToModel() +{ + m_aTimerTriggeredControllerLock.startTimer(); + rtl::Reference<::chart::ChartModel> xModel = m_xChartModel; + + ControllerLockGuardUNO aLockedControllers( xModel ); + + //commit title changes to model + { + TitleDialogData aTitleOutput; + m_xTitleResources->readFromResources( aTitleOutput ); + aTitleOutput.writeDifferenceToModel( xModel, m_xCC ); + m_xTitleResources->save_value(); + } + + //commit legend changes to model + { + m_xLegendPositionResources->writeToModel( xModel ); + } + + //commit grid changes to model + { + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + uno::Sequence< sal_Bool > aOldExistenceList; + AxisHelper::getAxisOrGridExistence( aOldExistenceList, xDiagram, false ); + uno::Sequence< sal_Bool > aNewExistenceList(aOldExistenceList); + sal_Bool* pNewExistenceList = aNewExistenceList.getArray(); + pNewExistenceList[0] = m_xCB_Grid_X->get_active(); + pNewExistenceList[1] = m_xCB_Grid_Y->get_active(); + pNewExistenceList[2] = m_xCB_Grid_Z->get_active(); + AxisHelper::changeVisibilityOfGrids( xDiagram + , aOldExistenceList, aNewExistenceList ); + } +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeCheckBoxHdl, weld::Toggleable&, void) +{ + ChangeHdl(nullptr); +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeEditHdl, weld::Entry&, void) +{ + ChangeHdl(nullptr); +} + +IMPL_LINK_NOARG(TitlesAndObjectsTabPage, ChangeHdl, LinkParamNone*, void) +{ + if( m_bCommitToModel ) + commitToModel(); +} + +bool TitlesAndObjectsTabPage::canAdvance() const +{ + return false; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx new file mode 100644 index 000000000..f06a3e7ec --- /dev/null +++ b/chart2/source/controller/dialogs/tp_Wizard_TitlesAndObjects.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include + +namespace chart { class LegendPositionResources; } +namespace chart { class TitleResources; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +class TitlesAndObjectsTabPage final : public vcl::OWizardPage +{ +public: + TitlesAndObjectsTabPage(weld::Container* pPage, weld::DialogController* pController, + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference< css::uno::XComponentContext >& xContext); + virtual ~TitlesAndObjectsTabPage() override; + + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason eReason ) override; + virtual bool canAdvance() const override; + +private: + void commitToModel(); + DECL_LINK( ChangeHdl, LinkParamNone*, void ); + DECL_LINK( ChangeEditHdl, weld::Entry&, void ); + DECL_LINK( ChangeCheckBoxHdl, weld::Toggleable&, void ); + + std::unique_ptr< TitleResources > m_xTitleResources; + std::unique_ptr< LegendPositionResources > m_xLegendPositionResources; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + bool m_bCommitToModel; + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr m_xCB_Grid_X; + std::unique_ptr m_xCB_Grid_Y; + std::unique_ptr m_xCB_Grid_Z; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx new file mode 100644 index 000000000..3918a296e --- /dev/null +++ b/chart2/source/controller/drawinglayer/DrawViewWrapper.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +namespace +{ + short lcl_getHitTolerance( OutputDevice const * pOutDev ) + { + const short HITPIX=2; //hit-tolerance in pixel + short nHitTolerance = 50; + if(pOutDev) + nHitTolerance = static_cast(pOutDev->PixelToLogic(Size(HITPIX,0)).Width()); + return nHitTolerance; + } + +// this code is copied from sfx2/source/doc/objembed.cxx. It is a workaround to +// get the reference device (e.g. printer) from the parent document +OutputDevice * lcl_GetParentRefDevice( const uno::Reference< frame::XModel > & xModel ) +{ + SfxObjectShell* pParent = SfxObjectShell::GetParentShell(xModel); + if ( pParent ) + return pParent->GetDocumentRefDev(); + return nullptr; +} + +} + +DrawViewWrapper::DrawViewWrapper( + SdrModel& rSdrModel, + OutputDevice* pOut) +: E3dView(rSdrModel, pOut) + ,m_pMarkHandleProvider(nullptr) + ,m_apOutliner(SdrMakeOutliner(OutlinerMode::TextObject, rSdrModel)) + ,m_bRestoreMapMode( false ) +{ + SetBufferedOutputAllowed(true); + SetBufferedOverlayAllowed(true); + SetPagePaintingAllowed(true); + + // #i12587# support for shapes in chart + SdrOutliner* pOutliner = getOutliner(); + SfxItemPool* pOutlinerPool = ( pOutliner ? pOutliner->GetEditTextObjectPool() : nullptr ); + if ( pOutlinerPool ) + { + SvtLinguConfig aLinguConfig; + SvtLinguOptions aLinguOptions; + aLinguConfig.GetOptions( aLinguOptions ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage, EE_CHAR_LANGUAGE ) ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage_CJK, EE_CHAR_LANGUAGE_CJK ) ); + pOutlinerPool->SetPoolDefaultItem( SvxLanguageItem( aLinguOptions.nDefaultLanguage_CTL, EE_CHAR_LANGUAGE_CTL ) ); + + // set font height without changing SdrEngineDefaults + pOutlinerPool->SetPoolDefaultItem( SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT ) ); // 12pt + } + + // #i121463# Use big handles by default + SetMarkHdlSizePixel(9); + + ReInit(); +} + +void DrawViewWrapper::ReInit() +{ + OutputDevice* pOutDev = GetFirstOutputDevice(); + Size aOutputSize(100,100); + if(pOutDev) + aOutputSize = pOutDev->GetOutputSize(); + + mbPageVisible = false; + mbPageBorderVisible = false; + mbBordVisible = false; + mbGridVisible = false; + mbHlplVisible = false; + + SetNoDragXorPolys(true);//for interactive 3D resize-dragging: paint only a single rectangle (not a simulated 3D object) + + //a correct work area is at least necessary for correct values in the position and size dialog + tools::Rectangle aRect(Point(0,0), aOutputSize); + SetWorkArea(aRect); + + ShowSdrPage(GetModel()->GetPage(0)); +} + +DrawViewWrapper::~DrawViewWrapper() +{ + maComeBackIdle.Stop();//@todo this should be done in destructor of base class + UnmarkAllObj();//necessary to avoid a paint call during the destructor hierarchy +} + +SdrPageView* DrawViewWrapper::GetPageView() const +{ + SdrPageView* pSdrPageView = GetSdrPageView(); + return pSdrPageView; +}; + +void DrawViewWrapper::SetMarkHandles(SfxViewShell* pOtherShell) +{ + if( m_pMarkHandleProvider && m_pMarkHandleProvider->getMarkHandles( maHdlList ) ) + return; + else + SdrView::SetMarkHandles(pOtherShell); +} + +SdrObject* DrawViewWrapper::getHitObject( const Point& rPnt ) const +{ + SdrPageView* pSdrPageView = GetPageView(); + SdrObject* pRet = SdrView::PickObj(rPnt, lcl_getHitTolerance( GetFirstOutputDevice() ), pSdrPageView, + SdrSearchOptions::DEEP | SdrSearchOptions::TESTMARKABLE); + + if( pRet ) + { + // ignore some special shapes + OUString aShapeName = pRet->GetName(); + + // return right away if it is a field button + if (aShapeName.startsWith("FieldButton")) + return pRet; + + if( aShapeName.match("PlotAreaIncludingAxes") || aShapeName.match("PlotAreaExcludingAxes") ) + { + pRet->SetMarkProtect( true ); + return getHitObject( rPnt ); + } + + //3d objects need a special treatment + //because the simple PickObj method is not accurate in this case for performance reasons + E3dObject* pE3d = dynamic_cast< E3dObject* >(pRet); + if( pE3d ) + { + E3dScene* pScene(pE3d->getRootE3dSceneFromE3dObject()); + + if(nullptr != pScene) + { + // prepare result vector and call helper + std::vector< const E3dCompoundObject* > aHitList; + const basegfx::B2DPoint aHitPoint(rPnt.X(), rPnt.Y()); + getAllHit3DObjectsSortedFrontToBack(aHitPoint, *pScene, aHitList); + + if(!aHitList.empty()) + { + // choose the frontmost hit 3D object of the scene + pRet = const_cast< E3dCompoundObject* >(aHitList[0]); + } + } + } + } + return pRet; +} + +void DrawViewWrapper::MarkObject( SdrObject* pObj ) +{ + bool bFrameDragSingles = true;//true == green == surrounding handles + if(pObj) + pObj->SetMarkProtect(false); + if( m_pMarkHandleProvider ) + bFrameDragSingles = m_pMarkHandleProvider->getFrameDragSingles(); + + SetFrameDragSingles(bFrameDragSingles);//decide whether each single object should get handles + SdrView::MarkObj( pObj, GetPageView() ); + showMarkHandles(); +} + +void DrawViewWrapper::setMarkHandleProvider( MarkHandleProvider* pMarkHandleProvider ) +{ + m_pMarkHandleProvider = pMarkHandleProvider; +} + +void DrawViewWrapper::CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* /* pRedirector */) +{ + svtools::ColorConfig aColorConfig; + Color aFillColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor ); + SetApplicationBackgroundColor(aFillColor); + E3dView::CompleteRedraw( pOut, rReg ); +} + +SdrObject* DrawViewWrapper::getSelectedObject() const +{ + SdrObject* pObj(nullptr); + const SdrMarkList& rMarkList = GetMarkedObjectList(); + if(rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + pObj = pMark->GetMarkedSdrObj(); + } + return pObj; +} + +SdrObject* DrawViewWrapper::getTextEditObject() const +{ + SdrObject* pObj = getSelectedObject(); + SdrObject* pTextObj = nullptr; + if( pObj && pObj->HasTextEdit()) + pTextObj = pObj; + return pTextObj; +} + +void DrawViewWrapper::attachParentReferenceDevice( const uno::Reference< frame::XModel > & xChartModel ) +{ + OutputDevice * pParentRefDev( lcl_GetParentRefDevice( xChartModel )); + SdrOutliner * pOutliner( getOutliner()); + if( pParentRefDev && pOutliner ) + { + pOutliner->SetRefDevice( pParentRefDev ); + } +} + +SdrOutliner* DrawViewWrapper::getOutliner() const +{ + return m_apOutliner.get(); +} + +SfxItemSet DrawViewWrapper::getPositionAndSizeItemSetFromMarkedObject() const +{ + SfxItemSet aFullSet( + GetModel()->GetItemPool(), + svl::Items< + SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS, + SID_ATTR_TRANSFORM_POS_X, SID_ATTR_TRANSFORM_ANGLE, + SID_ATTR_TRANSFORM_PROTECT_POS, SID_ATTR_TRANSFORM_AUTOHEIGHT, + SID_ATTR_METRIC, SID_ATTR_METRIC>); + SfxItemSet aGeoSet( E3dView::GetGeoAttrFromMarked() ); + aFullSet.Put( aGeoSet ); + aFullSet.Put( SfxUInt16Item(SID_ATTR_METRIC,static_cast< sal_uInt16 >( ConfigurationAccess::getFieldUnit()))); + return aFullSet; +} + +SdrObject* DrawViewWrapper::getNamedSdrObject( const OUString& rName ) const +{ + if(rName.isEmpty()) + return nullptr; + SdrPageView* pSdrPageView = GetPageView(); + if( pSdrPageView ) + { + return DrawModelWrapper::getNamedSdrObject( rName, pSdrPageView->GetObjList() ); + } + return nullptr; +} + +bool DrawViewWrapper::IsObjectHit( SdrObject const * pObj, const Point& rPnt ) +{ + if(pObj) + { + tools::Rectangle aRect(pObj->GetCurrentBoundRect()); + return aRect.Contains(rPnt); + } + return false; +} + +void DrawViewWrapper::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + //prevent wrong reselection of objects + SdrModel* pSdrModel( GetModel() ); + if( pSdrModel && pSdrModel->isLocked() ) + return; + + const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast(&rHint) : nullptr ); + + //#i76053# do nothing when only changes on the hidden draw page were made ( e.g. when the symbols for the dialogs are created ) + SdrPageView* pSdrPageView = GetPageView(); + if( pSdrHint && pSdrPageView ) + { + if( pSdrPageView->GetPage() != pSdrHint->GetPage() ) + return; + } + + E3dView::Notify(rBC, rHint); + + if( pSdrHint == nullptr ) + return; + + SdrHintKind eKind = pSdrHint->GetKind(); + if( eKind == SdrHintKind::BeginEdit ) + { + // #i79965# remember map mode + OSL_ASSERT( ! m_bRestoreMapMode ); + OutputDevice* pOutDev = GetFirstOutputDevice(); + if( pOutDev ) + { + m_aMapModeToRestore = pOutDev->GetMapMode(); + m_bRestoreMapMode = true; + } + } + else if( eKind == SdrHintKind::EndEdit ) + { + // #i79965# scroll back view when ending text edit + OSL_ASSERT( m_bRestoreMapMode ); + if( m_bRestoreMapMode ) + { + OutputDevice* pOutDev = GetFirstOutputDevice(); + if( pOutDev ) + { + pOutDev->SetMapMode( m_aMapModeToRestore ); + m_bRestoreMapMode = false; + } + } + } +} + +SdrObject* DrawViewWrapper::getSdrObject( const uno::Reference< + drawing::XShape >& xShape ) +{ + SdrObject* pRet = nullptr; + uno::Reference< lang::XTypeProvider > xTypeProvider( xShape, uno::UNO_QUERY ); + if(xTypeProvider.is()) + { + pRet = SdrObject::getSdrObjectFromXShape(xShape); + } + return pRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx b/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx new file mode 100644 index 000000000..ef7eba88e --- /dev/null +++ b/chart2/source/controller/drawinglayer/ViewElementListProvider.cxx @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +ViewElementListProvider::ViewElementListProvider( DrawModelWrapper* pDrawModelWrapper ) + : m_pDrawModelWrapper( pDrawModelWrapper ) +{ +} + +ViewElementListProvider::ViewElementListProvider(ViewElementListProvider&& rOther) noexcept +{ + m_pDrawModelWrapper = rOther.m_pDrawModelWrapper; + m_pFontList = std::move(rOther.m_pFontList); +} + +ViewElementListProvider::~ViewElementListProvider() +{ +} + +XColorListRef ViewElementListProvider::GetColorTable() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetColorList(); + return XColorListRef(); +} + +XDashListRef ViewElementListProvider::GetDashList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetDashList(); + return XDashListRef(); +} + +XLineEndListRef ViewElementListProvider::GetLineEndList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetLineEndList(); + return XLineEndListRef(); +} + +XGradientListRef ViewElementListProvider::GetGradientList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetGradientList(); + return XGradientListRef(); +} +XHatchListRef ViewElementListProvider::GetHatchList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetHatchList(); + return nullptr; +} + +XBitmapListRef ViewElementListProvider::GetBitmapList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetBitmapList(); + return XBitmapListRef(); +} + +XPatternListRef ViewElementListProvider::GetPatternList() const +{ + if(m_pDrawModelWrapper) + return m_pDrawModelWrapper->GetPatternList(); + return XPatternListRef(); +} + +//create chartspecific symbols for linecharts +SdrObjList* ViewElementListProvider::GetSymbolList() const +{ + SdrObjList* pSymbolList = nullptr; + try + { + //@todo use mutex + + //get hidden draw page (target): + rtl::Reference xTarget = m_pDrawModelWrapper->getHiddenDrawPage(); + + //create symbols via uno and convert to native sdr objects + drawing::Direction3D aSymbolSize(220, 220, 0); // should be 250, but 250 -> 280 ?? + rtl::Reference< SvxShapeGroup > xSymbols + = DataPointSymbolSupplier::create2DSymbolList(xTarget, aSymbolSize); + + SdrObject* pSdrObject = DrawViewWrapper::getSdrObject( + uno::Reference(static_cast(xSymbols.get()), uno::UNO_QUERY)); + if (pSdrObject) + pSymbolList = pSdrObject->GetSubList(); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return pSymbolList; +} + +Graphic ViewElementListProvider::GetSymbolGraphic( sal_Int32 nStandardSymbol, const SfxItemSet* pSymbolShapeProperties ) const +{ + SdrObjList* pSymbolList = GetSymbolList(); + if( !pSymbolList->GetObjCount() ) + return Graphic(); + if(nStandardSymbol<0) + nStandardSymbol*=-1; + if( o3tl::make_unsigned(nStandardSymbol) >= pSymbolList->GetObjCount() ) + nStandardSymbol %= pSymbolList->GetObjCount(); + SdrObject* pObj = pSymbolList->GetObj(nStandardSymbol); + + ScopedVclPtrInstance< VirtualDevice > pVDev; + pVDev->SetMapMode(MapMode(MapUnit::Map100thMM)); + + std::unique_ptr pModel( + new SdrModel()); + + pModel->GetItemPool().FreezeIdRanges(); + rtl::Reference pPage = new SdrPage( *pModel, false ); + pPage->SetSize(Size(1000,1000)); + pModel->InsertPage( pPage.get(), 0 ); + SdrView aView(*pModel, pVDev); + aView.hideMarkHandles(); + SdrPageView* pPageView = aView.ShowSdrPage(pPage.get()); + + // directly clone to target SdrModel + pObj = pObj->CloneSdrObject(*pModel); + + pPage->NbcInsertObject(pObj); + aView.MarkObj(pObj,pPageView); + if( pSymbolShapeProperties ) + pObj->SetMergedItemSet(*pSymbolShapeProperties); + + GDIMetaFile aMeta(aView.GetMarkedObjMetaFile()); + + Graphic aGraph(aMeta); + Size aSize = pObj->GetSnapRect().GetSize(); + aGraph.SetPrefSize(aSize); + aGraph.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + aView.UnmarkAll(); + pObj=pPage->RemoveObject(0); + SdrObject::Free( pObj ); + + return aGraph; +} + +FontList* ViewElementListProvider::getFontList() const +{ + //was old chart: + //SvxFontListItem* SfxObjectShell::.GetItem(SID_ATTR_CHAR_FONTLIST) + + if(!m_pFontList) + { + OutputDevice* pRefDev = m_pDrawModelWrapper ? m_pDrawModelWrapper->getReferenceDevice() : nullptr; + OutputDevice* pDefaultOut = Application::GetDefaultDevice(); + m_pFontList.reset( new FontList( pRefDev ? pRefDev : pDefaultOut + , pRefDev ? pDefaultOut : nullptr) ); + } + return m_pFontList.get(); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleBase.hxx b/chart2/source/controller/inc/AccessibleBase.hxx new file mode 100644 index 000000000..44f326f2a --- /dev/null +++ b/chart2/source/controller/inc/AccessibleBase.hxx @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::view { class XSelectionSupplier; } +namespace utl { class AccessibleStateSetHelper; } + + +class SdrView; + +namespace accessibility +{ +class IAccessibleViewForwarder; +} + +namespace chart +{ + +class AccessibleBase; +class ObjectHierarchy; + +typedef ObjectIdentifier AccessibleUniqueId; + +struct AccessibleElementInfo +{ + AccessibleUniqueId m_aOID; + + unotools::WeakReference< ::chart::ChartModel > m_xChartDocument; + css::uno::WeakReference< css::view::XSelectionSupplier > m_xSelectionSupplier; + css::uno::WeakReference< css::uno::XInterface > m_xView; + css::uno::WeakReference< css::awt::XWindow > m_xWindow; + + std::shared_ptr< ObjectHierarchy > m_spObjectHierarchy; + + AccessibleBase * m_pParent; + SdrView* m_pSdrView; + ::accessibility::IAccessibleViewForwarder* m_pViewForwarder; +}; + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::accessibility::XAccessible, + css::accessibility::XAccessibleContext, + css::accessibility::XAccessibleComponent, + css::accessibility::XAccessibleEventBroadcaster, + css::lang::XServiceInfo, + css::lang::XEventListener + > AccessibleBase_Base; +} + +/** Base class for all Chart Accessibility objects + */ +class AccessibleBase : + public cppu::BaseMutex, + public impl::AccessibleBase_Base +{ +public: + enum class EventType + { + GOT_SELECTION, + LOST_SELECTION + }; + + AccessibleBase( const AccessibleElementInfo & rAccInfo, + bool bMayHaveChildren, + bool bAlwaysTransparent ); + virtual ~AccessibleBase() override; + +protected: + // for all calls to protected methods it is assumed that the mutex is locked + // unless calls outside via UNO, e.g. event notification, are done + + /** @param bThrowException if true, a DisposedException is thrown if the + object is already disposed + @return true, if the component is already disposed and bThrowException is false, + false otherwise + @throws css::lang::DisposedException + */ + bool CheckDisposeState( bool bThrowException = true ) const; + + /** Events coming from the core have to be processed in this methods. The + default implementation returns false, which indicates that the object is + not interested in the event. To react on events you have to implement + this method in derived classes. + + The default implementation iterates over all children and forwards the + event until the first child returns true. + + @param nObjId contains the object id of chart objects. If the object is + no chart object, the event is not broadcast. + @return If an object is the addressee of the event it should return + true, false otherwise. + */ + bool NotifyEvent( EventType eType, const AccessibleUniqueId & rId ); + + /** Adds a state to the set. + + @throws css::uno::RuntimeException + */ + void AddState( sal_Int16 aState ); + + /** Removes a state from the set if the set contains the state, otherwise + nothing is done. + + @throws css::uno::RuntimeException + */ + void RemoveState( sal_Int16 aState ); + + /** has to be overridden by derived classes that support child elements. + With this method a rescan is initiated that should result in a correct + list of children. + + This method is called when access to any methods concerning children is + invoked for the first time. + */ + bool UpdateChildren(); + + /** Is called by UpdateChildren. This method is only called if an update is + really necessary. + */ + virtual bool ImplUpdateChildren(); + + /** adds a child to the end of the internal vector of children. As a + result, the child-count increases by one, but all existing children keep + their indices. + + Important: as the implementation is needed, this should remain the only + method for adding children (i.e. there mustn't be an AddChild( Reference< + XAccessible > ) or the like). + */ + void AddChild( AccessibleBase* pChild ); + + /** removes a child from the internal vector. All children with index + greater than the index of the removed element get an index one less than + before. + */ + void RemoveChildByOId( const ObjectIdentifier& rOId ); + + /** Retrieve the pixel coordinates of logical coordinates (0,0) of the + current logic coordinate system. This can be used for + getLocationOnScreen, if the coordinates of an object are not relative to + its direct parent, but a parent higher up in hierarchy. + + @return the (x,y) pixel coordinates of the upper left corner + */ + virtual css::awt::Point GetUpperLeftOnScreen() const; + + /** This method creates an AccessibleEventObject and sends it to all + listeners that are currently listening to this object + */ + void BroadcastAccEvent( sal_Int16 nId, + const css::uno::Any & rNew, + const css::uno::Any & rOld ) const; + + /** Removes all children from the internal lists and broadcasts child remove + events. + + This method cares about mutex locking, and thus should be called without + the mutex locked. + */ + void KillAllChildren(); + + /** Is called from getAccessibleChild(). Before this method is called, an + update of children is done if necessary. + + @throws css::lang::IndexOutOfBoundsException + @throws css::uno::RuntimeException + */ + virtual css::uno::Reference< css::accessibility::XAccessible > + ImplGetAccessibleChildById( sal_Int32 i ) const; + + /** Is called from getAccessibleChildCount(). Before this method is called, + an update of children is done if necessary. + + @throws css::uno::RuntimeException + */ + virtual sal_Int32 ImplGetAccessibleChildCount() const; + + const AccessibleElementInfo& GetInfo() const { return m_aAccInfo;} + void SetInfo( const AccessibleElementInfo & rNewInfo ); + const AccessibleUniqueId& GetId() const { return m_aAccInfo.m_aOID;} + + // ________ WeakComponentImplHelper (XComponent::dispose) ________ + virtual void SAL_CALL disposing() override; + + // ________ XAccessible ________ + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext() override; + + // ________ XAccessibleContext ________ + virtual sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleChild( sal_Int32 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleParent() override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + /// @return AccessibleRole.SHAPE + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + // has to be implemented by derived classes +// virtual OUString SAL_CALL getAccessibleName() +// throw (css::uno::RuntimeException); + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL + getAccessibleRelationSet() override; + virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL + getAccessibleStateSet() override; + virtual css::lang::Locale SAL_CALL getLocale() override; + // has to be implemented by derived classes +// virtual OUString SAL_CALL getAccessibleDescription() +// throw (css::uno::RuntimeException); + + // ________ XAccessibleComponent ________ + virtual sal_Bool SAL_CALL containsPoint( + const css::awt::Point& aPoint ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL + getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + // has to be defined in derived classes + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocation() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + virtual css::awt::Size SAL_CALL getSize() override; + virtual void SAL_CALL grabFocus() override; + virtual sal_Int32 SAL_CALL getForeground() override; + virtual sal_Int32 SAL_CALL getBackground() override; + + // ________ XServiceInfo ________ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( + const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ________ XEventListener ________ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ________ XAccessibleEventBroadcaster ________ + virtual void SAL_CALL addAccessibleEventListener( + const css::uno::Reference< css::accessibility::XAccessibleEventListener >& xListener ) override; + virtual void SAL_CALL removeAccessibleEventListener( + const css::uno::Reference< css::accessibility::XAccessibleEventListener >& xListener ) override; + +private: + enum eColorType + { + ACC_BASE_FOREGROUND, + ACC_BASE_BACKGROUND + }; + Color getColor( eColorType eColType ); + +private: + /** type of the vector containing the accessible children + */ + typedef std::vector< css::uno::Reference< css::accessibility::XAccessible > > ChildListVectorType; + /** type of the hash containing a vector index for every AccessibleUniqueId + of the object in the child list + */ + typedef std::map< ObjectIdentifier, css::uno::Reference< css::accessibility::XAccessible > > ChildOIDMap; + + bool m_bIsDisposed; + const bool m_bMayHaveChildren; + bool m_bChildrenInitialized; + ChildListVectorType m_aChildList; + + ChildOIDMap m_aChildOIDMap; + + ::comphelper::AccessibleEventNotifier::TClientId m_nEventNotifierId; + + /** Implementation helper for getAccessibleStateSet() + + Note: This member must come before m_aStateSet! + */ + rtl::Reference<::utl::AccessibleStateSetHelper> m_xStateSetHelper; + + AccessibleElementInfo m_aAccInfo; + const bool m_bAlwaysTransparent; + /** denotes if the state-set is initialized. On initialization the selected + state is checked. + + This variable is monitored by the solar mutex! + + Note: declared volatile to enable double-check-locking + */ + volatile bool m_bStateSetInitialized; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleChartView.hxx b/chart2/source/controller/inc/AccessibleChartView.hxx new file mode 100644 index 000000000..eb3367b20 --- /dev/null +++ b/chart2/source/controller/inc/AccessibleChartView.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "AccessibleBase.hxx" +#include +#include +#include +#include + +#include + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace accessibility +{ +class IAccessibleViewForwarder; +} + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + ::chart::AccessibleBase, + css::lang::XInitialization, + css::view::XSelectionChangeListener > + AccessibleChartView_Base; +} + +class AccessibleChartView final : + public impl::AccessibleChartView_Base +{ +public: + AccessibleChartView(SdrView* pView ); + virtual ~AccessibleChartView() override; + + AccessibleChartView() = delete; + + // ____ WeakComponentHelper (called from XComponent::dispose()) ____ + using AccessibleBase::disposing; + + // ____ lang::XInitialization ____ + // 0: view::XSelectionSupplier offers notifications for selection changes and access to the selection itself + // 1: frame::XModel representing the chart model - offers access to object data + // 2: lang::XInterface representing the normal chart view - offers access to some extra object data + // 3: accessibility::XAccessible representing the parent accessible + // 4: awt::XWindow representing the view's window (is a vcl Window) + // all arguments are only valid until next initialization - don't keep them longer + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // ____ view::XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( const css::lang::EventObject& aEvent ) override; + + // ________ XEventListener ________ + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // ________ XAccessibleContext ________ + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + virtual OUString SAL_CALL getAccessibleName() override; + virtual sal_Int16 SAL_CALL getAccessibleRole() override; + + // ________ XAccessibleComponent ________ + virtual css::awt::Rectangle SAL_CALL getBounds() override; + virtual css::awt::Point SAL_CALL getLocationOnScreen() override; + +protected: + // ________ AccessibleChartElement ________ + virtual css::awt::Point GetUpperLeftOnScreen() const override; + +private: // methods + /** @return the result that m_xWindow->getPosSize() _should_ return. It + returns (0,0) as upper left corner. When calling + getAccessibleParent, you get the parent's parent, which contains + a decoration. Thus you have an offset of (currently) (2,2) + which isn't taken into account. + */ + css::awt::Rectangle GetWindowPosSize() const; + +private: // members + css::uno::WeakReference< css::view::XSelectionSupplier > m_xSelectionSupplier; + unotools::WeakReference<::chart::ChartModel> m_xChartModel; + css::uno::WeakReference< css::uno::XInterface > m_xChartView; + css::uno::WeakReference< css::awt::XWindow > m_xWindow; + css::uno::WeakReference< css::accessibility::XAccessible > m_xParent; + + std::shared_ptr< ObjectHierarchy > m_spObjectHierarchy; + AccessibleUniqueId m_aCurrentSelectionOID; + SdrView* m_pSdrView; + std::unique_ptr<::accessibility::IAccessibleViewForwarder> m_pViewForwarder; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AccessibleTextHelper.hxx b/chart2/source/controller/inc/AccessibleTextHelper.hxx new file mode 100644 index 000000000..075fbf0f9 --- /dev/null +++ b/chart2/source/controller/inc/AccessibleTextHelper.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +// forward declaration of helper class from svx +namespace accessibility +{ +class AccessibleTextHelper; +} + +namespace chart +{ + +class DrawViewWrapper; + +namespace impl +{ +typedef comphelper::WeakComponentImplHelper< + css::lang::XInitialization, + css::accessibility::XAccessibleContext > + AccessibleTextHelper_Base; +} + +class AccessibleTextHelper final : + public impl::AccessibleTextHelper_Base +{ +public: + explicit AccessibleTextHelper( DrawViewWrapper * pDrawViewWrapper ); + virtual ~AccessibleTextHelper() override; + + // ____ XInitialization ____ + /** Must be called at least once for this helper class to work. + + mandatory parameter 0: type string. This is the CID that is used to find + the corresponding drawing object that contains the text that should + be handled by this helper class. +1 + mandatory parameter 1: type XAccessible. Is used as EventSource for the + ::accessibility::AccessibleTextHelper (svx) + + mandatory parameter 2: type awt::XWindow. The Window that shows the + text currently. + */ + virtual void SAL_CALL initialize( + const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // ____ XAccessibleContext ____ + virtual ::sal_Int32 SAL_CALL getAccessibleChildCount() override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( + ::sal_Int32 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override; + virtual ::sal_Int32 SAL_CALL getAccessibleIndexInParent() override; + virtual ::sal_Int16 SAL_CALL getAccessibleRole() override; + virtual OUString SAL_CALL getAccessibleDescription() override; + virtual OUString SAL_CALL getAccessibleName() override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override; + virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override; + virtual css::lang::Locale SAL_CALL getLocale() override; + +private: + std::unique_ptr<::accessibility::AccessibleTextHelper> m_pTextHelper; + DrawViewWrapper * m_pDrawViewWrapper; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/AxisItemConverter.hxx b/chart2/source/controller/inc/AxisItemConverter.hxx new file mode 100644 index 000000000..cbb75d2a1 --- /dev/null +++ b/chart2/source/controller/inc/AxisItemConverter.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include + +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace chart { struct ExplicitIncrementData; } +namespace chart { struct ExplicitScaleData; } +namespace chart { class ChartModel; } + +class SdrModel; + +namespace chart::wrapper { + +class AxisItemConverter final : public ItemConverter +{ +public: + AxisItemConverter( + const css::uno::Reference& rPropertySet, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + ExplicitScaleData const * pScale, + ExplicitIncrementData const * pIncrement, + const css::awt::Size* pRefSize ); + + virtual ~AxisItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr > m_aConverters; + css::uno::Reference< + css::chart2::XAxis > m_xAxis; + + rtl::Reference<::chart::ChartModel>m_xChartDoc; + + std::unique_ptr m_pExplicitScale; + std::unique_ptr m_pExplicitIncrement; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx b/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx new file mode 100644 index 000000000..96138e237 --- /dev/null +++ b/chart2/source/controller/inc/CharacterPropertyItemConverter.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include + +#include + +namespace chart::wrapper { + +class CharacterPropertyItemConverter final : public ItemConverter +{ +public: + CharacterPropertyItemConverter( + const css::uno::Reference& rPropertySet, + SfxItemPool& rItemPool ); + + CharacterPropertyItemConverter( + const css::uno::Reference& rPropertySet, + SfxItemPool& rItemPool, + const css::awt::Size* pRefSize, + const OUString & rRefSizePropertyName, + const css::uno::Reference& rRefSizePropSet = css::uno::Reference() ); + + virtual ~CharacterPropertyItemConverter() override; + +private: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + + const css::uno::Reference& GetRefSizePropertySet() const; + + OUString m_aRefSizePropertyName; + css::uno::Reference m_xRefSizePropSet; + std::optional m_pRefSize; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartController.hxx b/chart2/source/controller/inc/ChartController.hxx new file mode 100644 index 000000000..d50800fd6 --- /dev/null +++ b/chart2/source/controller/inc/ChartController.hxx @@ -0,0 +1,562 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "CommandDispatchContainer.hxx" +#include "SelectionHelper.hxx" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::accessibility { class XAccessible; } +namespace com::sun::star::accessibility { class XAccessibleContext; } +namespace com::sun::star::awt { class XFocusListener; } +namespace com::sun::star::awt { class XKeyListener; } +namespace com::sun::star::awt { class XMouseListener; } +namespace com::sun::star::awt { class XMouseMotionListener; } +namespace com::sun::star::awt { class XPaintListener; } +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::awt { class XWindowListener; } +namespace com::sun::star::awt { struct Point; } +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XDispatch; } +namespace com::sun::star::frame { class XLayoutManagerEventBroadcaster; } +namespace com::sun::star::graphic { class XGraphic; } +namespace com::sun::star::lang { class XInitialization; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XCloseable; } +namespace com::sun::star::view { class XSelectionSupplier; } + + +class SdrModel; + +namespace svt +{ + class AcceleratorExecute; +} + +namespace svx::sidebar { + class SelectionChangeHandler; +} + +namespace weld { + class Window; +} + +class DropTargetHelper; + +namespace chart +{ + +class UndoGuard; +class ChartWindow; +class DrawModelWrapper; +class DrawViewWrapper; +class ReferenceSizeProvider; +class ViewElementListProvider; +class Diagram; + +enum ChartDrawMode { CHARTDRAW_INSERT, CHARTDRAW_SELECT }; + + +class ChartController final : public ::cppu::WeakImplHelper < + css::frame::XController //comprehends XComponent (required interface) + ,css::frame::XDispatchProvider //(required interface) + ,css::view::XSelectionSupplier //(optional interface) + ,css::ui::XContextMenuInterception //(optional interface) + ,css::util::XCloseListener //(needed for communication with XModel) + ,css::lang::XServiceInfo + ,css::frame::XDispatch + ,css::awt::XWindow //this is the Window Controller part of this Controller, that will be given to a Frame via setComponent + ,css::lang::XMultiServiceFactory + ,css::util::XModifyListener + ,css::util::XModeChangeListener + ,css::frame::XLayoutManagerListener + > +{ +public: + ChartController() = delete; + explicit ChartController(css::uno::Reference< css::uno::XComponentContext > const & xContext); + virtual ~ChartController() override; + + OUString GetContextName(); + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // css::frame::XController (required interface) + virtual void SAL_CALL + attachFrame( const css::uno::Reference< css::frame::XFrame > & xFrame ) override; + + virtual sal_Bool SAL_CALL + attachModel( const css::uno::Reference< css::frame::XModel > & xModel ) override; + + virtual css::uno::Reference< css::frame::XFrame > SAL_CALL + getFrame() override; + + virtual css::uno::Reference< css::frame::XModel > SAL_CALL + getModel() override; + + virtual css::uno::Any SAL_CALL + getViewData() override; + + virtual void SAL_CALL + restoreViewData( const css::uno::Any& rValue ) override; + + virtual sal_Bool SAL_CALL + suspend( sal_Bool bSuspend ) override; + + // css::lang::XComponent (base of XController) + virtual void SAL_CALL + dispose() override; + + virtual void SAL_CALL + addEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override; + + virtual void SAL_CALL + removeEventListener( const css::uno::Reference< css::lang::XEventListener > & xListener ) override; + + // css::frame::XDispatchProvider (required interface) + virtual css::uno::Reference< css::frame::XDispatch> SAL_CALL + queryDispatch( const css::util::URL& rURL + , const OUString& rTargetFrameName + , sal_Int32 nSearchFlags) override; + + virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL + queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor > & xDescripts) override; + + // css::view::XSelectionSupplier (optional interface) + virtual sal_Bool SAL_CALL + select( const css::uno::Any& rSelection ) override; + + virtual css::uno::Any SAL_CALL + getSelection() override; + + virtual void SAL_CALL + addSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener > & xListener ) override; + + virtual void SAL_CALL + removeSelectionChangeListener( const css::uno::Reference< css::view::XSelectionChangeListener > & xListener ) override; + + // css::ui::XContextMenuInterception (optional interface) + virtual void SAL_CALL + registerContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor > & xInterceptor) override; + + virtual void SAL_CALL + releaseContextMenuInterceptor( const css::uno::Reference< css::ui::XContextMenuInterceptor > & xInterceptor) override; + + //additional interfaces + + // css::util::XCloseListener + virtual void SAL_CALL + queryClosing( const css::lang::EventObject& Source + , sal_Bool GetsOwnership ) override; + + virtual void SAL_CALL + notifyClosing( const css::lang::EventObject& Source ) override; + + // css::util::XEventListener (base of XCloseListener and XModifyListener) + virtual void SAL_CALL + disposing( const css::lang::EventObject& Source ) override; + + // css::frame::XDispatch + + virtual void SAL_CALL + dispatch( const css::util::URL& aURL + , const css::uno::Sequence< css::beans::PropertyValue >& aArgs ) override; + + virtual void SAL_CALL + addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl + , const css::util::URL& aURL ) override; + + virtual void SAL_CALL + removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& xControl + , const css::util::URL& aURL ) override; + + // css::awt::XWindow + virtual void SAL_CALL + setPosSize( sal_Int32 X, sal_Int32 Y + , sal_Int32 Width, sal_Int32 Height, sal_Int16 Flags ) override; + + virtual css::awt::Rectangle SAL_CALL + getPosSize() override; + + virtual void SAL_CALL + setVisible( sal_Bool Visible ) override; + + virtual void SAL_CALL + setEnable( sal_Bool Enable ) override; + + virtual void SAL_CALL + setFocus() override; + + virtual void SAL_CALL + addWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + + virtual void SAL_CALL + removeWindowListener( const css::uno::Reference< css::awt::XWindowListener >& xListener ) override; + + virtual void SAL_CALL + addFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + + virtual void SAL_CALL + removeFocusListener( const css::uno::Reference< css::awt::XFocusListener >& xListener ) override; + + virtual void SAL_CALL + addKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + + virtual void SAL_CALL + removeKeyListener( const css::uno::Reference< css::awt::XKeyListener >& xListener ) override; + + virtual void SAL_CALL + addMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + + virtual void SAL_CALL + removeMouseListener( const css::uno::Reference< css::awt::XMouseListener >& xListener ) override; + + virtual void SAL_CALL + addMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + + virtual void SAL_CALL + removeMouseMotionListener( const css::uno::Reference< css::awt::XMouseMotionListener >& xListener ) override; + + virtual void SAL_CALL + addPaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + + virtual void SAL_CALL + removePaintListener( const css::uno::Reference< css::awt::XPaintListener >& xListener ) override; + + // css::lang XMultiServiceFactory + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstance( const OUString& aServiceSpecifier ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( const OUString& ServiceSpecifier, + const css::uno::Sequence< + css::uno::Any >& Arguments ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getAvailableServiceNames() override; + + // css::util::XModifyListener + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // css::util::XModeChangeListener + virtual void SAL_CALL modeChanged( + const css::util::ModeChangeEvent& _rSource ) override; + + // css::frame::XLayoutManagerListener + virtual void SAL_CALL layoutEvent( + const css::lang::EventObject& aSource, + ::sal_Int16 eLayoutEvent, + const css::uno::Any& aInfo ) override; + + // WindowController stuff + void PrePaint(); + void execute_Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void execute_MouseButtonDown( const MouseEvent& rMEvt ); + void execute_MouseMove( const MouseEvent& rMEvt ); + void execute_MouseButtonUp( const MouseEvent& rMEvt ); + void execute_Resize(); + void execute_Command( const CommandEvent& rCEvt ); + bool execute_KeyInput( const KeyEvent& rKEvt ); + + /** get help text to be shown in a quick help + + @param aAtLogicPosition the position in logic coordinates (of the + window) of the mouse cursor to determine for + which object help is requested. + + @param bIsBalloonHelp determines whether to return the long text version + (balloon help) or the shorter one (quick help). + + @param rOutQuickHelpText is filled with the quick help text + + @param rOutEqualRect is filled with a rectangle that denotes the region + in which the quick help does not change. + + @return , if a quick help should be shown. + */ + bool requestQuickHelp( + ::Point aAtLogicPosition, bool bIsBalloonHelp, + OUString & rOutQuickHelpText, css::awt::Rectangle & rOutEqualRect ); + + css::uno::Reference< css::accessibility::XAccessible > CreateAccessible(); + + static bool isObjectDeleteable( const css::uno::Any& rSelection ); + + void setDrawMode( ChartDrawMode eMode ) { m_eDrawMode = eMode; } + + bool isShapeContext() const; + + ViewElementListProvider getViewElementListProvider(); + DrawModelWrapper* GetDrawModelWrapper(); + DrawViewWrapper* GetDrawViewWrapper(); + ChartWindow* GetChartWindow() const; + weld::Window* GetChartFrame(); + bool isAdditionalShapeSelected() const; + void SetAndApplySelection(const css::uno::Reference& rxShape); + void StartTextEdit( const Point* pMousePixel = nullptr ); + + void NotifyUndoActionHdl( std::unique_ptr ); + + css::uno::Reference const & getChartView() const; + + rtl::Reference<::chart::ChartModel> getChartModel(); + rtl::Reference<::chart::Diagram> getFirstDiagram(); + +private: + class TheModel : public salhelper::SimpleReferenceObject + { + public: + explicit TheModel( const rtl::Reference<::chart::ChartModel> & xModel ); + + virtual ~TheModel() override; + + void addListener( ChartController* pController ); + void removeListener( ChartController* pController ); + void tryTermination(); + const rtl::Reference<::chart::ChartModel>& + getModel() const { return m_xModel;} + + private: + rtl::Reference<::chart::ChartModel> m_xModel; + + //the ownership between model and controller is not clear at first + //each controller might consider himself as owner of the model first + bool m_bOwnership; + }; + class TheModelRef final + { + public: + TheModelRef( TheModel* pTheModel, ::osl::Mutex& rMutex ); + TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ); + TheModelRef& operator=(ChartController::TheModel* pTheModel); + TheModelRef& operator=(const TheModelRef& rTheModel); + ~TheModelRef(); + bool is() const; + TheModel* operator->() const { return m_xTheModel.get(); } + private: + rtl::Reference m_xTheModel; + ::osl::Mutex& m_rModelMutex; + }; + + mutable ::apphelper::LifeTimeManager m_aLifeTimeManager; + + bool m_bSuspended; + + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + //model + css::uno::Reference< css::frame::XFrame > m_xFrame; + mutable ::osl::Mutex m_aModelMutex; + TheModelRef m_aModel; + + //view + css::uno::Reference m_xViewWindow; + css::uno::Reference m_xChartView; + std::shared_ptr< DrawModelWrapper > m_pDrawModelWrapper; + std::unique_ptr m_pDrawViewWrapper; + + Selection m_aSelection; + SdrDragMode m_eDragMode; + + Timer m_aDoubleClickTimer; + bool m_bWaitingForDoubleClick; + bool m_bWaitingForMouseUp; + bool m_bFieldButtonDown; + + bool m_bConnectingToView; + bool m_bDisposed; + + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; + std::unique_ptr< UndoGuard > m_pTextActionUndoGuard; + + std::unique_ptr< ::svt::AcceleratorExecute > m_apAccelExecute; + + CommandDispatchContainer m_aDispatchContainer; + + std::unique_ptr< DropTargetHelper > m_apDropTargetHelper; + css::uno::Reference< + css::frame::XLayoutManagerEventBroadcaster > m_xLayoutManagerEventBroadcaster; + + ChartDrawMode m_eDrawMode; + + rtl::Reference mpSelectionChangeHandler; + + bool impl_isDisposedOrSuspended() const; + std::unique_ptr impl_createReferenceSizeProvider(); + void impl_adaptDataSeriesAutoResize(); + + void impl_createDrawViewController(); + void impl_deleteDrawViewController(); + + //executeDispatch methods + void executeDispatch_ObjectProperties(); + void executeDispatch_FormatObject( std::u16string_view rDispatchCommand ); + void executeDlg_ObjectProperties( const OUString& rObjectCID ); + bool executeDlg_ObjectProperties_withoutUndoGuard( const OUString& rObjectCID, bool bSuccessOnUnchanged ); + + void executeDispatch_ChartType(); + + void executeDispatch_InsertTitles(); + void executeDispatch_InsertLegend(); + void executeDispatch_DeleteLegend(); + void executeDispatch_OpenLegendDialog(); + void executeDispatch_InsertAxes(); + void executeDispatch_InsertGrid(); + + void executeDispatch_InsertMenu_DataLabels(); + void executeDispatch_InsertMenu_Trendlines(); + void executeDispatch_InsertMenu_MeanValues(); + + void executeDispatch_InsertMeanValue(); + void executeDispatch_InsertTrendline(); + void executeDispatch_InsertTrendlineEquation( bool bInsertR2=false ); + void executeDispatch_InsertErrorBars( bool bYError ); + + void executeDispatch_InsertR2Value(); + void executeDispatch_DeleteR2Value(); + + void executeDispatch_DeleteMeanValue(); + void executeDispatch_DeleteTrendline(); + void executeDispatch_DeleteTrendlineEquation(); + void executeDispatch_DeleteErrorBars( bool bYError ); + + void executeDispatch_InsertDataLabels(); + void executeDispatch_InsertDataLabel(); + void executeDispatch_DeleteDataLabels(); + void executeDispatch_DeleteDataLabel(); + + void executeDispatch_ResetAllDataPoints(); + void executeDispatch_ResetDataPoint(); + + void executeDispatch_InsertAxis(); + void executeDispatch_InsertAxisTitle(); + void executeDispatch_InsertMajorGrid(); + void executeDispatch_InsertMinorGrid(); + void executeDispatch_DeleteAxis(); + void executeDispatch_DeleteMajorGrid(); + void executeDispatch_DeleteMinorGrid(); + + void executeDispatch_InsertSpecialCharacter(); + void executeDispatch_EditText( const Point* pMousePixel = nullptr ); + void executeDispatch_SourceData(); + void executeDispatch_MoveSeries( bool bForward ); + + bool EndTextEdit(); + + void executeDispatch_View3D(); + void executeDispatch_PositionAndSize( const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs = nullptr ); + + void executeDispatch_EditData(); + + void executeDispatch_NewArrangement(); + void executeDispatch_ScaleText(); + + void executeDispatch_Paste(); + void executeDispatch_Copy(); + void executeDispatch_Cut(); + bool executeDispatch_Delete(); + void executeDispatch_ToggleLegend(); + void executeDispatch_ToggleGridHorizontal(); + void executeDispatch_ToggleGridVertical(); + + void executeDispatch_LOKSetTextSelection(int nType, int nX, int nY); + void executeDispatch_LOKPieSegmentDragging(int nOffset); + void executeDispatch_FillColor(sal_uInt32 nColor); + void executeDispatch_FillGradient(OUString sJSONGradient); + void executeDispatch_LineColor(sal_uInt32 nColor); + void executeDispatch_LineWidth(sal_uInt32 nWidth); + + void sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle); + + void impl_ShapeControllerDispatch( const css::util::URL& rURL, + const css::uno::Sequence< css::beans::PropertyValue >& rArgs ); + + DECL_LINK( DoubleClickWaitingHdl, Timer*, void ); + void execute_DoubleClick( const Point* pMousePixel ); + void startDoubleClickWaiting(); + void stopDoubleClickWaiting(); + + void impl_selectObjectAndNotiy(); + void impl_notifySelectionChangeListeners(); + void impl_invalidateAccessible(); + void impl_initializeAccessible(); + void impl_initializeAccessible( const css::uno::Reference< css::lang::XInitialization >& xInit ); + + //sets the model member to null if it equals the parameter + //returns true if successful + bool impl_releaseThisModel( const css::uno::Reference< css::uno::XInterface > & xModel ); + + enum eMoveOrResizeType + { + MOVE_OBJECT, + CENTERED_RESIZE_OBJECT + }; + /// @return , if resize/move was successful + bool impl_moveOrResizeObject( + const OUString & rCID, eMoveOrResizeType eType, double fAmountLogicX, double fAmountLogicY ); + bool impl_DragDataPoint( const OUString & rCID, double fOffset ); + + static const o3tl::sorted_vector< OUString >& impl_getAvailableCommands(); + + /** Creates a helper accessibility class that must be initialized via XInitialization. For + parameters see + + The returned object should not be used directly. Instead a proxy object + should use this helper to retrieve its children and add them to its own + children. + */ + css::uno::Reference< css::accessibility::XAccessibleContext > + impl_createAccessibleTextContext(); + + void impl_PasteGraphic( css::uno::Reference< css::graphic::XGraphic > const & xGraphic, + const ::Point & aPosition ); + void impl_PasteShapes( SdrModel* pModel ); + void impl_PasteStringAsTextShape( const OUString& rString, const css::awt::Point& rPosition ); + void impl_SetMousePointer( const MouseEvent & rEvent ); + + void impl_ClearSelection(); + + void impl_switchDiagramPositioningToExcludingPositioning(); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartDocumentWrapper.hxx b/chart2/source/controller/inc/ChartDocumentWrapper.hxx new file mode 100644 index 000000000..04f76d705 --- /dev/null +++ b/chart2/source/controller/inc/ChartDocumentWrapper.hxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XRefreshable; } +namespace chart { class ChartView; } + +namespace chart::wrapper +{ + +class Chart2ModelContact; + +class ChartDocumentWrapper_Base : public ::cppu::ImplInheritanceHelper + < WrappedPropertySet + , css::chart::XChartDocument + , css::drawing::XDrawPageSupplier + , css::lang::XMultiServiceFactory + , css::lang::XServiceInfo + , css::uno::XAggregation + > +{ +}; + +class ChartDocumentWrapper final : public ChartDocumentWrapper_Base + , public ::utl::OEventListenerAdapter +{ +public: + explicit ChartDocumentWrapper( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + virtual ~ChartDocumentWrapper() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + void setAddIn( const css::uno::Reference< css::util::XRefreshable >& xAddIn ); + const css::uno::Reference< css::util::XRefreshable >& getAddIn() const { return m_xAddIn;} + + void setUpdateAddIn( bool bUpdateAddIn ); + bool getUpdateAddIn() const { return m_bUpdateAddIn;} + + void setBaseDiagram( const OUString& rBaseDiagram ); + const OUString& getBaseDiagram() const { return m_aBaseDiagram;} + + css::uno::Reference< css::drawing::XShapes > getAdditionalShapes() const; + + /// @throws css::uno::RuntimeException + rtl::Reference impl_getDrawPage() const; + +protected: + + // ____ chart::XChartDocument ____ + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getTitle() override; + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getSubTitle() override; + virtual css::uno::Reference< css::drawing::XShape > SAL_CALL getLegend() override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getArea() override; + virtual css::uno::Reference< css::chart::XDiagram > SAL_CALL getDiagram() override; + virtual void SAL_CALL setDiagram( const css::uno::Reference< + css::chart::XDiagram >& xDiagram ) override; + virtual css::uno::Reference< css::chart::XChartData > SAL_CALL getData() override; + virtual void SAL_CALL attachData( const css::uno::Reference< + css::chart::XChartData >& xData ) override; + + // ____ XModel ____ + virtual sal_Bool SAL_CALL attachResource( const OUString& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + virtual OUString SAL_CALL getURL() override; + virtual css::uno::Sequence< + css::beans::PropertyValue > SAL_CALL getArgs() override; + virtual void SAL_CALL connectController( const css::uno::Reference< + css::frame::XController >& Controller ) override; + virtual void SAL_CALL disconnectController( const css::uno::Reference< + css::frame::XController >& Controller ) override; + virtual void SAL_CALL lockControllers() override; + virtual void SAL_CALL unlockControllers() override; + virtual sal_Bool SAL_CALL hasControllersLocked() override; + virtual css::uno::Reference< + css::frame::XController > SAL_CALL getCurrentController() override; + virtual void SAL_CALL setCurrentController( const css::uno::Reference< css::frame::XController >& Controller ) override; + virtual css::uno::Reference SAL_CALL getCurrentSelection() override; + + // ____ XComponent ____ + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override; + + // ____ XInterface (for new interfaces) ____ + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + + // ____ ::utl::OEventListenerAdapter ____ + virtual void _disposing( const css::lang::EventObject& rSource ) override; + + // ____ XDrawPageSupplier ____ + virtual css::uno::Reference< css::drawing::XDrawPage > SAL_CALL getDrawPage() override; + + // ____ XMultiServiceFactory ____ + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( + const OUString& ServiceSpecifier, + const css::uno::Sequence< css::uno::Any >& Arguments ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + // ____ XAggregation ____ + virtual void SAL_CALL setDelegator( + const css::uno::Reference< css::uno::XInterface >& rDelegator ) override; + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override; + + // ____ WrappedPropertySet ____ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence() override; + virtual std::vector< std::unique_ptr > createWrappedProperties() override; + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() override; + +private: //methods + void impl_resetAddIn(); + +private: //member + std::shared_ptr< Chart2ModelContact > m_spChart2ModelContact; + + css::uno::Reference< css::uno::XInterface > m_xDelegator; + + css::uno::Reference< css::drawing::XShape > m_xTitle; + css::uno::Reference< css::drawing::XShape > m_xSubTitle; + css::uno::Reference< css::drawing::XShape > m_xLegend; + css::uno::Reference< css::chart::XChartData > m_xChartData; + css::uno::Reference< css::chart::XDiagram > m_xDiagram; + css::uno::Reference< css::beans::XPropertySet > m_xArea; + + css::uno::Reference< css::util::XRefreshable > m_xAddIn; + OUString m_aBaseDiagram; + bool m_bUpdateAddIn; + + rtl::Reference< ChartView > m_xChartView; + css::uno::Reference< css::lang::XMultiServiceFactory> + m_xShapeFactory; + + bool m_bIsDisposed; +}; + +} // namespace chart::wrapper + +// CHART_CHARTDOCUMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartToolbarController.hxx b/chart2/source/controller/inc/ChartToolbarController.hxx new file mode 100644 index 000000000..ce493bba6 --- /dev/null +++ b/chart2/source/controller/inc/ChartToolbarController.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XFramesSupplier; } + +namespace chart { + +typedef comphelper::WeakComponentImplHelper< + css::frame::XToolbarController, css::frame::XStatusListener, + css::util::XUpdatable, css::lang::XInitialization, + css::lang::XServiceInfo> ChartToolbarControllerBase; + +class ChartToolbarController final : public ChartToolbarControllerBase +{ +public: + ChartToolbarController(const css::uno::Sequence& rProperties); + virtual ~ChartToolbarController() override; + + ChartToolbarController(const ChartToolbarController&) = delete; + const ChartToolbarController& operator=(const ChartToolbarController&) = delete; + + // XToolbarController + virtual void SAL_CALL execute(sal_Int16 nKeyModifier) override; + + virtual void SAL_CALL click() override; + + virtual void SAL_CALL doubleClick() override; + + virtual css::uno::Reference SAL_CALL createPopupWindow() override; + + virtual css::uno::Reference SAL_CALL + createItemWindow(const css::uno::Reference& rParent) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XStatusListener + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& rSource) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rAny) override; + + // XUpdatable + virtual void SAL_CALL update() override; + + using comphelper::WeakComponentImplHelperBase::disposing; + +private: + + css::uno::Reference mxFramesSupplier; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ChartWindow.hxx b/chart2/source/controller/inc/ChartWindow.hxx new file mode 100644 index 000000000..4ab65ddd9 --- /dev/null +++ b/chart2/source/controller/inc/ChartWindow.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class ChartController; + +/** The ChartWindow collects events from the window and forwards them the to the controller +thus the controller can perform appropriate actions +*/ + +class ChartWindow final : public vcl::Window +{ +public: + ChartWindow( ChartController* pController, vcl::Window* pParent, WinBits nStyle ); + virtual ~ChartWindow() override; + virtual void dispose() override; + + //from base class Window: + virtual void PrePaint(vcl::RenderContext& rRenderContext) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void Resize() override; + virtual void Activate() override; + virtual void Deactivate() override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual void Command( const CommandEvent& rCEvt ) override; + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + + /// For LibreOfficeKit, we need to route these to the mouse events. + virtual void LogicMouseButtonDown(const MouseEvent&) override; + virtual void LogicMouseButtonUp(const MouseEvent&) override; + virtual void LogicMouseMove(const MouseEvent&) override; + + void ForceInvalidate(); + virtual void Invalidate( InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + virtual void Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + virtual void Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags = InvalidateFlags::NONE ) override; + /// Notify the LOK client about an invalidated area. + virtual void LogicInvalidate( const tools::Rectangle* pRectangle ) override; + + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + virtual FactoryFunction GetUITestFactory() const override; + + ChartController* GetController(); + + virtual bool IsChart() const override { return true; } + vcl::Window* GetParentEditWin(); + +private: + // returns the chart bounding box in twips + tools::Rectangle GetBoundingBox(); + +private: + ChartController* m_pWindowController; + bool m_bInPaint; + VclPtr m_pViewShellWindow; + + void adjustHighContrastMode(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/CommandDispatchContainer.hxx b/chart2/source/controller/inc/CommandDispatchContainer.hxx new file mode 100644 index 000000000..ae95313c0 --- /dev/null +++ b/chart2/source/controller/inc/CommandDispatchContainer.hxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include + +namespace com::sun::star::frame { class XController; } +namespace com::sun::star::frame { class XDispatch; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::frame { struct DispatchDescriptor; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { struct URL; } + +namespace chart +{ +class ChartModel; +class DrawCommandDispatch; +class ShapeController; + +/** @HTML + + Helper class for implementing the XDispatchProvider interface + of the ChartController. This class handles all commands to queryDispatch and + queryDispatches in the following way: + +
    +
  • Check if there is a cached XDispatch for a given command. + If so, use it.
  • +
  • Check if the command is handled by this class, e.g. Undo. If so, + return a corresponding XDispatch implementation, and cache + this implementation for later use
  • +
  • Otherwise send the command to the chart dispatch provider, if it + can handle this dispatch (determined by the list of commands given in + setChartDispatch()).
  • +
+ +

The XDispatchProvider is designed to return different + XDispatch implementations for each command. This class here + decides which implementation to use for which command.

+ +

As most commands need much information of the controller and are + implemented there, the controller handles most of the commands itself (it + also implements XDispatch). Therefore it is set here as + chart dispatch.

+ */ +class CommandDispatchContainer +{ +public: + // note: the chart dispatcher should be removed when all commands are + // handled by other dispatchers. (Chart is currently the controller + // itself) + explicit CommandDispatchContainer( + const css::uno::Reference< css::uno::XComponentContext > & xContext ); + + void setModel( + const rtl::Reference<::chart::ChartModel> & xModel ); + + /** Set a chart dispatcher that is used for all commands contained in + rChartCommands + */ + void setChartDispatch( + const css::uno::Reference< css::frame::XDispatch >& rChartDispatch, + o3tl::sorted_vector< OUString > && rChartCommands ); + + /** Returns the dispatch that is able to do the command given in rURL, if + implemented here. If the URL is not implemented here, it should be + checked whether the command is one of the commands given via + the setChartDispatch() method. If so, call the chart dispatch. + +

If all this fails, return an empty dispatch.

+ */ + css::uno::Reference< css::frame::XDispatch > getDispatchForURL( + const css::util::URL & rURL ); + + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > getDispatchesForURLs( + const css::uno::Sequence< css::frame::DispatchDescriptor > & aDescriptors ); + + void DisposeAndClear(); + + static css::uno::Reference< css::frame::XDispatch > + getContainerDispatchForURL( + const css::uno::Reference< css::frame::XController > & xChartController, + const css::util::URL & rURL ); + + const css::uno::Reference< css::frame::XDispatch > & getChartDispatcher() const { return m_xChartDispatcher; } + + void setDrawCommandDispatch( DrawCommandDispatch* pDispatch ); + DrawCommandDispatch* getDrawCommandDispatch() { return m_pDrawCommandDispatch; } + void setShapeController( ShapeController* pController ); + ShapeController* getShapeController() { return m_pShapeController; } + +private: + typedef + std::map< OUString, + css::uno::Reference< css::frame::XDispatch > > + tDispatchMap; + + typedef + std::vector< css::uno::Reference< css::frame::XDispatch > > tDisposeVector; + + mutable tDispatchMap m_aCachedDispatches; + mutable tDisposeVector m_aToBeDisposedDispatches; + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + unotools::WeakReference< ::chart::ChartModel > m_xModel; + + css::uno::Reference< css::frame::XDispatch > m_xChartDispatcher; + o3tl::sorted_vector< OUString > m_aChartCommands; + + DrawCommandDispatch* m_pDrawCommandDispatch; + ShapeController* m_pShapeController; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ConfigurationAccess.hxx b/chart2/source/controller/inc/ConfigurationAccess.hxx new file mode 100644 index 000000000..2fb4636d2 --- /dev/null +++ b/chart2/source/controller/inc/ConfigurationAccess.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace chart::ConfigurationAccess +{ +/** @descr Retrieve the FieldUnit to be used for the UI. This unit is retrieved + from the registry settings of the Calc application. + + If this setting can not be found there is a fallback to cm which is the most + common setting worldwide (or not?) + + @return the FieldUnit enum. See for definition + */ +FieldUnit getFieldUnit(); + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/DataPointItemConverter.hxx b/chart2/source/controller/inc/DataPointItemConverter.hxx new file mode 100644 index 000000000..3c6e276ff --- /dev/null +++ b/chart2/source/controller/inc/DataPointItemConverter.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include "GraphicPropertyItemConverter.hxx" +#include + +#include +#include + +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace chart { class ChartModel; } +namespace chart { class DataSeries; } +class SdrModel; + +namespace chart::wrapper { + +class DataPointItemConverter final : public ItemConverter +{ +public: + DataPointItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& xContext, + const css::uno::Reference& rPropertySet, + const rtl::Reference<::chart::DataSeries>& xSeries, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference& xNamedPropertyContainerFactory, + GraphicObjectType eMapTo, + const css::awt::Size* pRefSize = nullptr, + bool bDataSeries = false, + bool bUseSpecialFillColor = false, + sal_Int32 nSpecialFillColor = 0, + bool bOverwriteLabelsForAttributedDataPointsAlso = false, + sal_Int32 nNumberFormat = 0, + sal_Int32 nPercentNumberFormat = 0, + sal_Int32 nPointIndex = -1 ); + + virtual ~DataPointItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr > m_aConverters; + bool m_bDataSeries; + bool m_bOverwriteLabelsForAttributedDataPointsAlso; + bool m_bUseSpecialFillColor; + Color m_nSpecialFillColor; + sal_Int32 m_nNumberFormat; + sal_Int32 m_nPercentNumberFormat; + css::uno::Sequence m_aAvailableLabelPlacements; + bool m_bForbidPercentValue; + bool m_bHideLegendEntry; + sal_Int32 m_nPointIndex; + rtl::Reference<::chart::DataSeries> m_xSeries; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/DrawViewWrapper.hxx b/chart2/source/controller/inc/DrawViewWrapper.hxx new file mode 100644 index 000000000..28c2a927e --- /dev/null +++ b/chart2/source/controller/inc/DrawViewWrapper.hxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::frame { class XModel; } + +class SdrModel; + +namespace chart +{ + +/** The DrawViewWrapper should help us to reduce effort if the underlying DrawingLayer changes. +Another task is to hide functionality we do not need, for example more than one page. +*/ + +class MarkHandleProvider +{ +public: + virtual bool getMarkHandles( SdrHdlList& rHdlList ) =0; + virtual bool getFrameDragSingles() =0; + +protected: + ~MarkHandleProvider() {} +}; + +class DrawViewWrapper final : public E3dView +{ +public: + DrawViewWrapper( + SdrModel& rSdrModel, + OutputDevice* pOut); + + virtual ~DrawViewWrapper() override; + + //triggers the use of an updated first page + void ReInit(); + + /// tries to get an OutputDevice from the XParent of the model to use as reference device + void attachParentReferenceDevice( + const css::uno::Reference< css::frame::XModel > & xChartModel ); + + //fill list of selection handles 'aHdl' + virtual void SetMarkHandles(SfxViewShell* pOtherShell) override; + + SdrPageView* GetPageView() const; + + SdrObject* getHitObject( const Point& rPnt ) const; + + void MarkObject( SdrObject* pObj ); + + //pMarkHandleProvider can be NULL; ownership is not taken + void setMarkHandleProvider( MarkHandleProvider* pMarkHandleProvider ); + void CompleteRedraw(OutputDevice* pOut, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector = nullptr) override; + + SdrObject* getSelectedObject() const; + SdrObject* getTextEditObject() const; + SdrOutliner* getOutliner() const; + + SfxItemSet getPositionAndSizeItemSetFromMarkedObject() const; + + SdrObject* getNamedSdrObject( const OUString& rName ) const; + static bool IsObjectHit( SdrObject const * pObj, const Point& rPnt ); + + virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override; + + static SdrObject* getSdrObject( const css::uno::Reference< css::drawing::XShape >& xShape ); + +private: + mutable MarkHandleProvider* m_pMarkHandleProvider; + + std::unique_ptr< SdrOutliner > m_apOutliner; + + // #i79965# scroll back view when ending text edit + bool m_bRestoreMapMode; + MapMode m_aMapModeToRestore; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ErrorBarItemConverter.hxx b/chart2/source/controller/inc/ErrorBarItemConverter.hxx new file mode 100644 index 000000000..997bda7d2 --- /dev/null +++ b/chart2/source/controller/inc/ErrorBarItemConverter.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "ItemConverter.hxx" + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +class ErrorBarItemConverter final : public ItemConverter +{ +public: + ErrorBarItemConverter( + const css::uno::Reference< css::frame::XModel > & xChartModel, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ); + virtual ~ErrorBarItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::shared_ptr< ItemConverter > m_spGraphicConverter; + css::uno::Reference< css::frame::XModel > m_xModel; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx b/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx new file mode 100644 index 000000000..234e50751 --- /dev/null +++ b/chart2/source/controller/inc/GraphicPropertyItemConverter.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +enum class GraphicObjectType +{ + FilledDataPoint, + LineDataPoint, + LineProperties, + LineAndFillProperties +}; + +class GraphicPropertyItemConverter final : public ItemConverter +{ +public: + GraphicPropertyItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + GraphicObjectType eObjectType ); + virtual ~GraphicPropertyItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + GraphicObjectType m_GraphicObjectType; + SdrModel & m_rDrawModel; + css::uno::Reference< css::lang::XMultiServiceFactory > m_xNamedPropertyTableFactory; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ItemConverter.hxx b/chart2/source/controller/inc/ItemConverter.hxx new file mode 100644 index 000000000..865268a3a --- /dev/null +++ b/chart2/source/controller/inc/ItemConverter.hxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::beans { class XPropertySetInfo; } + +namespace chart::wrapper { + + +/** This class serves for conversion between properties of an XPropertySet and + SfxItems in SfxItemSets. + + With this helper classes, you can feed dialogs with XPropertySets and let + those modify by the dialogs. + + You must implement GetWhichPairs() such that an SfxItemSet created with + CreateEmptyItemSet() is able to hold all items that may be mapped. + + You also have to implement GetItemProperty(), in order to return the + property name for a given which-id together with the corresponding member-id + that has to be used for conversion in QueryValue/PutValue. + + FillSpecialItem and ApplySpecialItem may be used for special handling of + individual item, e.g. if you need member-ids in QueryValue/PutValue + + A typical use could be the following: + + ::comphelper::ChartTypeItemConverter aItemConverter( xPropertySet, GetItemPool() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + bool bChanged = false; + + MyDialog aDlg( aItemSet ); + if( aDlg.Execute() == RET_OK ) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if( pOutItemSet ) + bChanged = aItemConverter.ApplyItemSet( *pOutItemSet ); + } + + if( bChanged ) + { + [ apply model changes to view ] + } + */ +class ItemConverter : + public ::utl::OEventListenerAdapter +{ +public: + /** Construct an item converter that uses the given property set for + reading/writing converted items + */ + ItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet , + SfxItemPool& rItemPool ); + virtual ~ItemConverter() override; + + typedef sal_uInt16 tWhichIdType; + typedef OUString tPropertyNameType; + typedef sal_uInt8 tMemberIdType; + + typedef std::pair< tPropertyNameType, tMemberIdType > tPropertyNameWithMemberId; + + /** applies all properties that can be mapped to items into the given item + set. + + Call this method before opening a dialog. + + @param rOutItemSet + the SfxItemSet is filled with all items that are a result of a + conversion from a property of the internal XPropertySet. + */ + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const; + + /** applies all properties that are results of a conversion from all items + in rItemSet to the internal XPropertySet. + + Call this method after a dialog was closed with OK + + @return true, if any properties have been changed, false otherwise. + */ + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ); + + /** creates an empty item set using the given pool or a common pool if empty + (see GetItemPool) and allowing all items given in the ranges returned by + GetWhichPairs. + */ + SfxItemSet CreateEmptyItemSet() const; + + /** Invalidates all items in rDestSet, that are set (state SfxItemState::SET) in + both item sets (rDestSet and rSourceSet) and have differing content. + */ + static void InvalidateUnequalItems( SfxItemSet &rDestSet, const SfxItemSet &rSourceSet ); + +protected: + + /** implement this method to provide an array of which-ranges + */ + virtual const WhichRangesContainer& GetWhichPairs() const = 0; + + /** implement this method to return a Property object for a given which id. + + @param rOutProperty + If true is returned, this contains the property name and the + corresponding Member-Id. + + @return true, if the item can be mapped to a property. + */ + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const = 0; + + /** for items that can not be mapped directly to a property. + + This method is called from FillItemSet(), if GetItemProperty() returns + false. + + The default implementation does nothing except showing an assertion + + @throws css::uno::Exception + */ + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const; + + /** for items that can not be mapped directly to a property. + + This method is called from ApplyItemSet(), if GetItemProperty() returns + false. + + The default implementation returns just false and shows an assertion + + @return true if the item changed a property, false otherwise. + + @throws css::uno::Exception + */ + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ); + + /// Returns the pool + SfxItemPool & GetItemPool() const { return m_rItemPool;} + + /** Returns the XPropertySet that was given in the CTOR and is used to apply + items in ApplyItemSet(). + */ + const css::uno::Reference< css::beans::XPropertySet >& GetPropertySet() const { return m_xPropertySet;} + + // ____ ::utl::OEventListenerAdapter ____ + virtual void _disposing( const css::lang::EventObject& rSource ) override; + +protected: + /** sets a new property set, that you get with GetPropertySet(). It should + not be necessary to use this method. It is introduced to allow changing + the regression type of a regression curve which changes the object + identity. + */ + void resetPropertySet( const css::uno::Reference< css::beans::XPropertySet > & xPropSet ); + +private: + css::uno::Reference< css::beans::XPropertySet > m_xPropertySet; + css::uno::Reference< css::beans::XPropertySetInfo > m_xPropertySetInfo; + + SfxItemPool& m_rItemPool; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ItemPropertyMap.hxx b/chart2/source/controller/inc/ItemPropertyMap.hxx new file mode 100644 index 000000000..7bee6ae81 --- /dev/null +++ b/chart2/source/controller/inc/ItemPropertyMap.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include "ItemConverter.hxx" + +#include + +namespace chart::wrapper +{ +typedef std::map> + ItemPropertyMapType; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/LegendItemConverter.hxx b/chart2/source/controller/inc/LegendItemConverter.hxx new file mode 100644 index 000000000..3e9315acc --- /dev/null +++ b/chart2/source/controller/inc/LegendItemConverter.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" + +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper +{ + +class LegendItemConverter final : public ItemConverter +{ +public: + LegendItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~LegendItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr > m_aConverters; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/MultipleChartConverters.hxx b/chart2/source/controller/inc/MultipleChartConverters.hxx new file mode 100644 index 000000000..4fe1bb1de --- /dev/null +++ b/chart2/source/controller/inc/MultipleChartConverters.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "MultipleItemConverter.hxx" +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace chart { class ChartModel; } +class SdrModel; + +namespace chart::wrapper { + +class AllAxisItemConverter final : public MultipleItemConverter +{ +public: + AllAxisItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::awt::Size* pRefSize ); + + virtual ~AllAxisItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllGridItemConverter final : public MultipleItemConverter +{ +public: + AllGridItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference & xNamedPropertyContainerFactory ); + virtual ~AllGridItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllDataLabelItemConverter final : public MultipleItemConverter +{ +public: + AllDataLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference& xNamedPropertyContainerFactory ); + + virtual ~AllDataLabelItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllTitleItemConverter final : public MultipleItemConverter +{ +public: + AllTitleItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const css::uno::Reference& xNamedPropertyContainerFactory ); + + virtual ~AllTitleItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +class AllSeriesStatisticsConverter final : public MultipleItemConverter +{ +public: + AllSeriesStatisticsConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, SfxItemPool& rItemPool ); + virtual ~AllSeriesStatisticsConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/MultipleItemConverter.hxx b/chart2/source/controller/inc/MultipleItemConverter.hxx new file mode 100644 index 000000000..e2e8f0775 --- /dev/null +++ b/chart2/source/controller/inc/MultipleItemConverter.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "ItemConverter.hxx" + +#include + +namespace chart::wrapper { + +/** Note: virtual const sal_uInt16 * GetWhichPairs() const; is still pure virtual + */ +class MultipleItemConverter : public ItemConverter +{ +public: + virtual ~MultipleItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + + /// implemented empty (returns always false) + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + +protected: + MultipleItemConverter( SfxItemPool& rItemPool ); + + std::vector< std::unique_ptr > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ObjectHierarchy.hxx b/chart2/source/controller/inc/ObjectHierarchy.hxx new file mode 100644 index 000000000..55c073bf2 --- /dev/null +++ b/chart2/source/controller/inc/ObjectHierarchy.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::awt { struct KeyEvent; } +namespace com::sun::star::chart2 { class XChartDocument; } + +namespace chart +{ + +class ExplicitValueProvider; + +class ObjectHierarchy +{ +public: + typedef std::vector< ObjectIdentifier > tChildContainer; + + /** @param bFlattenDiagram + If , the content of the diagram (data series, wall, floor, + etc.) is treated as being at the same level as the diagram. (This is + used for keyboard navigation). + */ + explicit ObjectHierarchy( + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider, + bool bFlattenDiagram = false, + bool bOrderingForElementSelector = false ); + ~ObjectHierarchy(); + + static ObjectIdentifier getRootNodeOID(); + static bool isRootNode( const ObjectIdentifier& rOID ); + + /// equal to getChildren( getRootNodeOID()) + const tChildContainer & getTopLevelChildren() const; + bool hasChildren( const ObjectIdentifier& rParent ) const; + const tChildContainer & getChildren( const ObjectIdentifier& rParent ) const; + + const tChildContainer & getSiblings( const ObjectIdentifier& rNode ) const; + + /// The result is empty, if the node cannot be found in the tree + ObjectIdentifier getParent( const ObjectIdentifier& rNode ) const; + /// @returns -1, if no parent can be determined + sal_Int32 getIndexInParent( const ObjectIdentifier& rNode ) const; + +private: + void createTree( const rtl::Reference<::chart::ChartModel> & xChartDocument ); + void createAxesTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createDiagramTree( + ObjectHierarchy::tChildContainer& rContainer, + const rtl::Reference<::chart::ChartModel>& xChartDoc, + const rtl::Reference< ::chart::Diagram >& xDiagram ); + void createDataSeriesTree( + ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + static void createWallAndFloor( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createLegendTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + void createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ); + ObjectIdentifier getParentImpl( + const ObjectIdentifier& rParentOID, + const ObjectIdentifier& rOID ) const; + + typedef std::map< ObjectIdentifier, ObjectHierarchy::tChildContainer > + tChildMap; + tChildMap m_aChildMap; + ExplicitValueProvider* m_pExplicitValueProvider; + bool m_bFlattenDiagram; + bool m_bOrderingForElementSelector; +}; + +class ObjectKeyNavigation +{ +public: + explicit ObjectKeyNavigation( const ObjectIdentifier & rCurrentOID, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider ); + + bool handleKeyEvent( const css::awt::KeyEvent & rEvent ); + const ObjectIdentifier& getCurrentSelection() const { return m_aCurrentOID;} + +private: + void setCurrentSelection( const ObjectIdentifier& rOID ); + bool first(); + bool last(); + bool next(); + bool previous(); + bool up(); + bool down(); + bool veryFirst(); + bool veryLast(); + + ObjectIdentifier m_aCurrentOID; + rtl::Reference<::chart::ChartModel> m_xChartDocument; + ExplicitValueProvider * m_pExplicitValueProvider; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ObjectNameProvider.hxx b/chart2/source/controller/inc/ObjectNameProvider.hxx new file mode 100644 index 000000000..276e58977 --- /dev/null +++ b/chart2/source/controller/inc/ObjectNameProvider.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ + +/** Provides localized ui strings for the userinterface. +*/ + +class ObjectNameProvider +{ +public: + static OUString getName( ObjectType eObjectType, bool bPlural=false ); + static OUString getAxisName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getGridName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getTitleName( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString getTitleNameByType( TitleHelper::eTitleType eType ); + + static OUString getNameForCID( + const OUString& rObjectCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ); + + static OUString getName_ObjectForSeries( + ObjectType eObjectType, + const OUString& rSeriesCID, + const rtl::Reference<::chart::ChartModel>& xChartDocument ); + static OUString getName_ObjectForAllSeries( ObjectType eObjectType ); + + /** Provides help texts for the various chart elements. + The parameter rObjectCID has to be a ClassifiedIdentifier - see class ObjectIdentifier. + */ + static OUString getHelpText( const OUString& rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, bool bVerbose=false ); + + /** This is used for showing the currently selected object in the status bar + (command "Context") + */ + static OUString getSelectedObjectText( const OUString & rObjectCID, const rtl::Reference<::chart::ChartModel>& xChartDocument ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/PositionAndSizeHelper.hxx b/chart2/source/controller/inc/PositionAndSizeHelper.hxx new file mode 100644 index 000000000..f70ccf302 --- /dev/null +++ b/chart2/source/controller/inc/PositionAndSizeHelper.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::awt { struct Rectangle; } + +namespace chart +{ + +class PositionAndSizeHelper +{ +public: + static bool moveObject( ObjectType eObjectType + , const css::uno::Reference< css::beans::XPropertySet >& xObjectProp + , const css::awt::Rectangle& rNewPositionAndSize + , const css::awt::Rectangle& rOldPositionAndSize + , const css::awt::Rectangle& rPageRectangle ); + + static bool moveObject( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::awt::Rectangle& rNewPositionAndSize + , const css::awt::Rectangle& rOldPositionAndSize + , const css::awt::Rectangle& rPageRectangle ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RangeSelectionHelper.hxx b/chart2/source/controller/inc/RangeSelectionHelper.hxx new file mode 100644 index 000000000..02db335a1 --- /dev/null +++ b/chart2/source/controller/inc/RangeSelectionHelper.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartDocument; } + +namespace com::sun::star { + namespace sheet{ + class XRangeSelection; + class XRangeSelectionListener; + } +} + +namespace chart +{ +class ChartModel; +class RangeSelectionListenerParent; + +class RangeSelectionHelper +{ +public: + explicit RangeSelectionHelper( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + ~RangeSelectionHelper(); + + bool hasRangeSelection(); + css::uno::Reference< css::sheet::XRangeSelection > const & getRangeSelection(); + void raiseRangeSelectionDocument(); + bool chooseRange( + const OUString & aCurrentRange, + const OUString & aUIString, + RangeSelectionListenerParent & rListenerParent ); + void stopRangeListening( bool bRemoveListener = true ); + bool verifyCellRange( const OUString & rRangeStr ); + bool verifyArguments( const css::uno::Sequence< css::beans::PropertyValue >& rArguments ); + +private: + css::uno::Reference< css::sheet::XRangeSelection > + m_xRangeSelection; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + + css::uno::Reference< css::sheet::XRangeSelectionListener > + m_xRangeSelectionListener; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RangeSelectionListener.hxx b/chart2/source/controller/inc/RangeSelectionListener.hxx new file mode 100644 index 000000000..29bea261c --- /dev/null +++ b/chart2/source/controller/inc/RangeSelectionListener.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ChartModel; + +class RangeSelectionListenerParent +{ +public: + virtual void listeningFinished(const OUString& rNewRange) = 0; + virtual void disposingRangeSelection() = 0; + +protected: + ~RangeSelectionListenerParent() {} +}; + +class RangeSelectionListener final + : public ::cppu::WeakImplHelper +{ +public: + explicit RangeSelectionListener( + RangeSelectionListenerParent& rParent, const OUString& rInitialRange, + const rtl::Reference<::chart::ChartModel>& xModelToLockController); + virtual ~RangeSelectionListener() override; + +protected: + // ____ XRangeSelectionListener ____ + virtual void SAL_CALL done(const css::sheet::RangeSelectionEvent& aEvent) override; + virtual void SAL_CALL aborted(const css::sheet::RangeSelectionEvent& aEvent) override; + + // ____ XEventListener ____ + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + +private: + RangeSelectionListenerParent& m_rParent; + OUString m_aRange; + ControllerLockGuardUNO m_aControllerLockGuard; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RegressionCurveItemConverter.hxx b/chart2/source/controller/inc/RegressionCurveItemConverter.hxx new file mode 100644 index 000000000..30c74c4c2 --- /dev/null +++ b/chart2/source/controller/inc/RegressionCurveItemConverter.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include + +namespace com::sun::star::chart2 { class XRegressionCurveContainer; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace chart { class DataSeries; } +class SdrModel; + +namespace chart::wrapper +{ + +class RegressionCurveItemConverter final : public ItemConverter +{ +public: + RegressionCurveItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + const rtl::Reference< ::chart::DataSeries > & xRegCurveCnt, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ); + virtual ~RegressionCurveItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::shared_ptr< ItemConverter > m_spGraphicConverter; + rtl::Reference< ::chart::DataSeries > m_xCurveContainer; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/RegressionEquationItemConverter.hxx b/chart2/source/controller/inc/RegressionEquationItemConverter.hxx new file mode 100644 index 000000000..0b32e4b9e --- /dev/null +++ b/chart2/source/controller/inc/RegressionEquationItemConverter.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" + +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper { + +class RegressionEquationItemConverter final : public ItemConverter +{ +public: + RegressionEquationItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~RegressionEquationItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/SelectionHelper.hxx b/chart2/source/controller/inc/SelectionHelper.hxx new file mode 100644 index 000000000..ff0e95eee --- /dev/null +++ b/chart2/source/controller/inc/SelectionHelper.hxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "DrawViewWrapper.hxx" +#include + +class SdrObject; + +namespace com::sun::star::drawing { class XShape; } + +namespace chart +{ + +class Selection +{ +public: //methods + bool hasSelection() const; + + OUString const & getSelectedCID() const; + css::uno::Reference< css::drawing::XShape > const & getSelectedAdditionalShape() const; + const ObjectIdentifier& getSelectedOID() const { return m_aSelectedOID;} + + bool isResizeableObjectSelected() const; + bool isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; + bool isDragableObjectSelected() const; + + bool isAdditionalShapeSelected() const; + + //returns true if selection has changed + bool setSelection( const OUString& rCID ); + bool setSelection( const css::uno::Reference< css::drawing::XShape >& xShape ); + + void clearSelection(); + + //returns true if the selection has changed + bool maybeSwitchSelectionAfterSingleClickWasEnsured(); + void resetPossibleSelectionAfterSingleClickWasEnsured(); + + void remindSelectionBeforeMouseDown(); + bool isSelectionDifferentFromBeforeMouseDown() const; + + void adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper + , bool bIsRightMouse, bool bWaitingForDoubleClick ); + + void applySelection( DrawViewWrapper* pDrawViewWrapper ); + +private: //member + //the selection could be given by a CID or by a shape + //if m_aSelectedObjectCID is not empty this indicates the selection + //the content of m_xSelectedShape is ignored in that case + //the strings are used for autogenerated chart specific objects + //the shape reference is used for additional shapes + ObjectIdentifier m_aSelectedOID; //only single object selection so far + ObjectIdentifier m_aSelectedOID_beforeMouseDown; + ObjectIdentifier m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing; +}; + +class SelectionHelper final : public MarkHandleProvider +{ +public: + static bool findNamedParent( SdrObject*& pInOutObject + , OUString& rOutName + , bool bGivenObjectMayBeResult ); + static bool findNamedParent( SdrObject*& pInOutObject + , ObjectIdentifier& rOutObject + , bool bGivenObjectMayBeResult ); + static SdrObject* getMarkHandlesObject( SdrObject* pObj ); + static E3dScene* getSceneToRotate( SdrObject* pObj ); + static bool isDragableObjectHitTwice( const Point& rMPos + , const OUString& rNameOfSelectedObject + , const DrawViewWrapper& rDrawViewWrapper ); + + static OUString getHitObjectCID( + const Point& rMPos, + DrawViewWrapper const & rDrawViewWrapper, + bool bGetDiagramInsteadOf_Wall=false ); + + static bool isRotateableObject( std::u16string_view rCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + explicit SelectionHelper( SdrObject* pSelectedObj ); + virtual ~SelectionHelper(); + + //MarkHandleProvider: + virtual bool getMarkHandles( SdrHdlList& rHdlList ) override; + virtual bool getFrameDragSingles() override; + + SdrObject* getObjectToMark();//sets also internally the mark object + //-> getMarkHandles will behave different if this method has found a Mark Object different from m_pSelectedObj + +private: + SdrObject* m_pSelectedObj;//hit and logically selected object + SdrObject* m_pMarkObj;//object that is marked instead to have more pretty handles +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx b/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx new file mode 100644 index 000000000..f9bc42dcc --- /dev/null +++ b/chart2/source/controller/inc/SeriesOptionsItemConverter.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include +#include + +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace chart { class ChartModel; } +namespace chart { class BaseCoordinateSystem; } + +namespace chart::wrapper +{ + +class SeriesOptionsItemConverter final : public ItemConverter +{ +public: + SeriesOptionsItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ); + virtual ~SeriesOptionsItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + + bool m_bAttachToMainAxis; + bool m_bSupportingOverlapAndGapWidthProperties; + bool m_bSupportingBarConnectors; + + sal_Int32 m_nBarOverlap; + sal_Int32 m_nGapWidth; + bool m_bConnectBars; + + bool m_bSupportingAxisSideBySide; + bool m_bGroupBarsPerAxis; + + bool m_bSupportingStartingAngle; + sal_Int32 m_nStartingAngle; + + bool m_bClockwise; + rtl::Reference< ::chart::BaseCoordinateSystem > m_xCooSys; + + css::uno::Sequence< sal_Int32 > m_aSupportedMissingValueTreatments; + sal_Int32 m_nMissingValueTreatment; + + bool m_bSupportingPlottingOfHiddenCells; + bool m_bIncludeHiddenCells; + + bool m_bHideLegendEntry; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ShapeController.h b/chart2/source/controller/inc/ShapeController.h new file mode 100644 index 000000000..392c28d2f --- /dev/null +++ b/chart2/source/controller/inc/ShapeController.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef CHART_SHAPECONTROLLER_H +#define CHART_SHAPECONTROLLER_H + +//Command Ids: +#define COMMAND_ID_FORMAT_LINE 1 +#define COMMAND_ID_FORMAT_AREA 2 +#define COMMAND_ID_TEXT_ATTRIBUTES 3 +#define COMMAND_ID_TRANSFORM_DIALOG 4 +#define COMMAND_ID_OBJECT_TITLE_DESCRIPTION 5 +#define COMMAND_ID_RENAME_OBJECT 6 +#define COMMAND_ID_BRING_TO_FRONT 8 +#define COMMAND_ID_FORWARD 9 +#define COMMAND_ID_BACKWARD 10 +#define COMMAND_ID_SEND_TO_BACK 11 +#define COMMAND_ID_FONT_DIALOG 15 +#define COMMAND_ID_PARAGRAPH_DIALOG 16 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/StatisticsItemConverter.hxx b/chart2/source/controller/inc/StatisticsItemConverter.hxx new file mode 100644 index 000000000..b82c1c230 --- /dev/null +++ b/chart2/source/controller/inc/StatisticsItemConverter.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" +#include + +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } + +namespace chart::wrapper +{ + +class StatisticsItemConverter final : public ItemConverter +{ +public: + StatisticsItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ); + virtual ~StatisticsItemConverter() override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xModel; +}; + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TabPageNotifiable.hxx b/chart2/source/controller/inc/TabPageNotifiable.hxx new file mode 100644 index 000000000..440cda2de --- /dev/null +++ b/chart2/source/controller/inc/TabPageNotifiable.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +// color to use as foreground for an invalid range +#define RANGE_SELECTION_INVALID_RANGE_FOREGROUND_COLOR COL_WHITE +// color to use as background for an invalid range +#define RANGE_SELECTION_INVALID_RANGE_BACKGROUND_COLOR Color(0xff6563) + +class BuilderPage; + +namespace chart +{ +class TabPageNotifiable +{ +public: + virtual void setInvalidPage(BuilderPage* pTabPage) = 0; + virtual void setValidPage(BuilderPage* pTabPage) = 0; + +protected: + ~TabPageNotifiable() {} +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TextDirectionListBox.hxx b/chart2/source/controller/inc/TextDirectionListBox.hxx new file mode 100644 index 000000000..d346a23cb --- /dev/null +++ b/chart2/source/controller/inc/TextDirectionListBox.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace chart +{ +class TextDirectionListBox final : public svx::FrameDirectionListBox +{ +public: + explicit TextDirectionListBox(std::unique_ptr pControl); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TextLabelItemConverter.hxx b/chart2/source/controller/inc/TextLabelItemConverter.hxx new file mode 100644 index 000000000..9df2a65e1 --- /dev/null +++ b/chart2/source/controller/inc/TextLabelItemConverter.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" + +#include +#include +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } +namespace chart { class DataSeries; } + +namespace chart::wrapper { + +class TextLabelItemConverter final : public ItemConverter +{ +public: + TextLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& rPropertySet, + const rtl::Reference<::chart::DataSeries>& xSeries, + SfxItemPool& rItemPool, + const css::awt::Size* pRefSize, + bool bDataSeries, + sal_Int32 nNumberFormat, + sal_Int32 nPercentNumberFormat ); + + virtual ~TextLabelItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector> maConverters; + sal_Int32 mnNumberFormat; + sal_Int32 mnPercentNumberFormat; + css::uno::Sequence maAvailableLabelPlacements; + + bool mbDataSeries:1; + bool mbForbidPercentValue:1; + + rtl::Reference<::chart::DataSeries> m_xSeries; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx b/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx new file mode 100644 index 000000000..34a4880c0 --- /dev/null +++ b/chart2/source/controller/inc/TimerTriggeredControllerLock.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include + +namespace com::sun::star::frame +{ +class XModel; +} +namespace chart +{ +class ControllerLockGuardUNO; +} + +namespace chart +{ +class ChartModel; + +class TimerTriggeredControllerLock final +{ +public: + TimerTriggeredControllerLock(const rtl::Reference<::chart::ChartModel>& xModel); + ~TimerTriggeredControllerLock(); + + void startTimer(); + +private: + rtl::Reference<::chart::ChartModel> m_xModel; + std::unique_ptr m_apControllerLockGuard; + AutoTimer m_aTimer; + + DECL_LINK(TimerTimeout, Timer*, void); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TitleDialogData.hxx b/chart2/source/controller/inc/TitleDialogData.hxx new file mode 100644 index 000000000..70b03c8a6 --- /dev/null +++ b/chart2/source/controller/inc/TitleDialogData.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +struct TitleDialogData +{ + css::uno::Sequence< sal_Bool > aPossibilityList; + css::uno::Sequence< sal_Bool > aExistenceList; + css::uno::Sequence< OUString > aTextList; + std::unique_ptr< ReferenceSizeProvider > apReferenceSizeProvider; + + TitleDialogData(std::unique_ptr pReferenzeSizeProvider = nullptr); + + void readFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ); + /* return true if anything has changed; + when pOldState is NULL then all data are written to the model + */ + bool writeDifferenceToModel( const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::uno::Reference< css::uno::XComponentContext >& xContext + , const TitleDialogData* pOldState=nullptr ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/TitleItemConverter.hxx b/chart2/source/controller/inc/TitleItemConverter.hxx new file mode 100644 index 000000000..5a2686d62 --- /dev/null +++ b/chart2/source/controller/inc/TitleItemConverter.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ItemConverter.hxx" + +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +class SdrModel; + +namespace chart::wrapper { + +class TitleItemConverter final : public ItemConverter +{ +public: + TitleItemConverter( + const css::uno::Reference& rPropertySet, + SfxItemPool& rItemPool, SdrModel& rDrawModel, + const css::uno::Reference& xNamedPropertyContainerFactory, + const css::awt::Size* pRefSize ); + + virtual ~TitleItemConverter() override; + + virtual void FillItemSet( SfxItemSet & rOutItemSet ) const override; + virtual bool ApplyItemSet( const SfxItemSet & rItemSet ) override; + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; + virtual bool GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const override; + + virtual void FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const override; + virtual bool ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) override; + +private: + std::vector< std::unique_ptr > m_aConverters; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/ViewElementListProvider.hxx b/chart2/source/controller/inc/ViewElementListProvider.hxx new file mode 100644 index 000000000..d8b8ffc42 --- /dev/null +++ b/chart2/source/controller/inc/ViewElementListProvider.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +class FontList; +class SdrObjList; +class SfxItemSet; + +namespace chart +{ + +class DrawModelWrapper; + +class ViewElementListProvider final +{ +public: + ViewElementListProvider( DrawModelWrapper* pDrawModelWrapper ); + ViewElementListProvider(ViewElementListProvider&&) noexcept; + ~ViewElementListProvider(); + + XColorListRef GetColorTable() const; + XDashListRef GetDashList() const; + XLineEndListRef GetLineEndList() const; + XGradientListRef GetGradientList() const; + XHatchListRef GetHatchList() const; + XBitmapListRef GetBitmapList() const; + XPatternListRef GetPatternList() const; + + //create chartspecific symbols for linecharts + SdrObjList* GetSymbolList() const; + Graphic GetSymbolGraphic( sal_Int32 nStandardSymbol, const SfxItemSet* pSymbolShapeProperties ) const; + + FontList* getFontList() const; + //SfxPrinter* getPrinter(); + +private: + DrawModelWrapper* m_pDrawModelWrapper; + mutable std::unique_ptr m_pFontList; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ChartType.hxx b/chart2/source/controller/inc/dlg_ChartType.hxx new file mode 100644 index 000000000..7520869e8 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ChartType.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ChartModel; +class ChartTypeTabPage; + +class ChartTypeDialog final : public weld::GenericDialogController +{ +public: + ChartTypeDialog(weld::Window* pWindow, const rtl::Reference<::chart::ChartModel>& xChartModel); + virtual ~ChartTypeDialog() override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + std::unique_ptr m_xContentArea; + std::unique_ptr m_xChartTypeTabPage; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ChartType_UNO.hxx b/chart2/source/controller/inc/dlg_ChartType_UNO.hxx new file mode 100644 index 000000000..4566ec751 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ChartType_UNO.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::beans { class XPropertySetInfo; } + +namespace chart +{ +class ChartModel; + +typedef ::svt::OGenericUnoDialog ChartTypeUnoDlg_BASE; +class ChartTypeUnoDlg final : public ChartTypeUnoDlg_BASE + ,public ::comphelper::OPropertyArrayUsageHelper< ChartTypeUnoDlg > +{ +public: + ChartTypeUnoDlg( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + +private: + virtual ~ChartTypeUnoDlg() override; + + // OGenericUnoDialog overridables + virtual void implInitialize(const css::uno::Any& _rValue) override; + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + ChartTypeUnoDlg(const ChartTypeUnoDlg&) = delete; + void operator =(const ChartTypeUnoDlg&) = delete; + + rtl::Reference<::chart::ChartModel> m_xChartModel; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_CreationWizard.hxx b/chart2/source/controller/inc/dlg_CreationWizard.hxx new file mode 100644 index 000000000..a0fcc9dae --- /dev/null +++ b/chart2/source/controller/inc/dlg_CreationWizard.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "TimerTriggeredControllerLock.hxx" +#include "TabPageNotifiable.hxx" + +#include +#include + +#include + +namespace com::sun::star::chart2 +{ +class XChartDocument; +} +namespace com::sun::star::uno +{ +class XComponentContext; +} + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace chart +{ +class ChartModel; +class ChartTypeTemplateProvider; +class DialogModel; + +class CreationWizard final : public vcl::RoadmapWizardMachine, public TabPageNotifiable +{ +public: + CreationWizard(weld::Window* pParent, const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& xContext); + + CreationWizard() = delete; + virtual ~CreationWizard() override; + + // TabPageNotifiable + virtual void setInvalidPage(BuilderPage* pTabPage) override; + virtual void setValidPage(BuilderPage* pTabPage) override; + +protected: + virtual bool leaveState(WizardState _nState) override; + virtual WizardState determineNextState(WizardState nCurrentState) const override; + virtual void enterState(WizardState nState) override; + + virtual OUString getStateDisplayName(WizardState nState) const override; + +private: + virtual std::unique_ptr createPage(WizardState nState) override; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference m_xComponentContext; + ChartTypeTemplateProvider* m_pTemplateProvider; + std::unique_ptr m_pDialogModel; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + bool m_bCanTravel; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx b/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx new file mode 100644 index 000000000..7e1792f08 --- /dev/null +++ b/chart2/source/controller/inc/dlg_CreationWizard_UNO.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dlg_CreationWizard.hxx" +#include + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +class VclWindowEvent; + +namespace chart +{ +class ChartModel; + +class CreationWizardUnoDlg final : public cppu::BaseMutex + , public ::cppu::OComponentHelper + , public css::ui::dialogs::XAsynchronousExecutableDialog + , public css::lang::XServiceInfo + , public css::lang::XInitialization + , public css::frame::XTerminateListener + , public css::beans::XPropertySet +{ +public: + CreationWizardUnoDlg() = delete; + + CreationWizardUnoDlg( const css::uno::Reference< css::uno::XComponentContext >& xContext ); + virtual ~CreationWizardUnoDlg() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual css::uno::Any SAL_CALL queryAggregation( css::uno::Type const & rType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XAsynchronousExecutableDialog + virtual void SAL_CALL setDialogTitle( const OUString& aTitle ) override; + virtual void SAL_CALL startExecuteModal( const css::uno::Reference& xListener ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + +protected: + // ____ OComponentHelper ____ + /// Called in dispose method after the listeners were notified. + virtual void SAL_CALL disposing() override; + +private: + void createDialogOnDemand(); + DECL_STATIC_LINK(CreationWizardUnoDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*); + +private: + rtl::Reference< ::chart::ChartModel > m_xChartModel; + css::uno::Reference< css::uno::XComponentContext> m_xCC; + css::uno::Reference< css::awt::XWindow > m_xParentWindow; + + std::shared_ptr m_xDialog; + bool m_bUnlockControllersOnExecute; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_DataEditor.hxx b/chart2/source/controller/inc/dlg_DataEditor.hxx new file mode 100644 index 000000000..5156e0831 --- /dev/null +++ b/chart2/source/controller/inc/dlg_DataEditor.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } +namespace comphelper { template class mem_fun1_t; } + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + } +} + +namespace chart +{ +class ChartModel; +class DataBrowser; + +class DataEditor final : public weld::GenericDialogController +{ +public: + DataEditor(weld::Window* pParent, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const css::uno::Reference & xContext); + virtual ~DataEditor() override; + + DECL_LINK(CloseHdl, weld::Button&, void); + + void SetReadOnly( bool bReadOnly ); + +private: + bool m_bReadOnly; + + rtl::Reference<::chart::ChartModel> m_xChartDoc; + css::uno::Reference m_xContext; + + std::unique_ptr m_xTbxData; + std::unique_ptr m_xCloseBtn; + std::unique_ptr m_xTable; + std::unique_ptr m_xColumns; + std::unique_ptr m_xColors; + css::uno::Reference m_xTableCtrlParent; + VclPtr m_xBrwData; + + /// handles actions of the toolbox + DECL_LINK( ToolboxHdl, const OString&, void ); + /// is called, if the cursor of the table has moved + DECL_LINK( BrowserCursorMovedHdl, DataBrowser*, void); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_DataSource.hxx b/chart2/source/controller/inc/dlg_DataSource.hxx new file mode 100644 index 000000000..2dce4169d --- /dev/null +++ b/chart2/source/controller/inc/dlg_DataSource.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "TabPageNotifiable.hxx" +#include +#include + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::uno { class XComponentContext; } +class BuilderPage; + +namespace chart +{ +class ChartModel; +class ChartTypeTemplateProvider; +class DataSourceTabPage; +class DialogModel; +class RangeChooserTabPage; + +class DataSourceDialog final : + public weld::GenericDialogController, + public TabPageNotifiable +{ +public: + explicit DataSourceDialog( + weld::Window * pParent, + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + virtual ~DataSourceDialog() override; + + // from GenericDialogController base + virtual short run() override; + + // TabPageNotifiable + virtual void setInvalidPage( BuilderPage * pTabPage ) override; + virtual void setValidPage( BuilderPage * pTabPage ) override; + +private: + DECL_LINK(ActivatePageHdl, const OString&, void); + DECL_LINK(DeactivatePageHdl, const OString&, bool); + + std::unique_ptr< ChartTypeTemplateProvider > m_apDocTemplateProvider; + std::unique_ptr< DialogModel > m_apDialogModel; + + std::unique_ptr m_xRangeChooserTabPage; + std::unique_ptr m_xDataSourceTabPage; + bool m_bRangeChooserTabIsValid; + bool m_bDataSourceTabIsValid; + bool m_bTogglingEnabled; + + std::unique_ptr m_xTabControl; + std::unique_ptr m_xBtnOK; + + static sal_uInt16 m_nLastPageId; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx b/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx new file mode 100644 index 000000000..b69ab70f6 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertAxis_Grid.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart +{ +struct InsertAxisOrGridDialogData +{ + css::uno::Sequence aPossibilityList; + css::uno::Sequence aExistenceList; + + InsertAxisOrGridDialogData(); +}; + +/************************************************************************* +|* +|* insert Axis dialog (also base for grid dialog) +|* +\************************************************************************/ +class SchAxisDlg : public weld::GenericDialogController +{ +protected: + std::unique_ptr m_xCbPrimaryX; + std::unique_ptr m_xCbPrimaryY; + std::unique_ptr m_xCbPrimaryZ; + std::unique_ptr m_xCbSecondaryX; + std::unique_ptr m_xCbSecondaryY; + std::unique_ptr m_xCbSecondaryZ; + +public: + SchAxisDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput, + bool bAxisDlg = true); + void getResult(InsertAxisOrGridDialogData& rOutput); +}; + +/************************************************************************* +|* +|* Grid dialog +|* +\************************************************************************/ +class SchGridDlg final : public SchAxisDlg +{ +public: + SchGridDlg(weld::Window* pParent, const InsertAxisOrGridDialogData& rInput); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertDataLabel.hxx b/chart2/source/controller/inc/dlg_InsertDataLabel.hxx new file mode 100644 index 000000000..7777db3c9 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertDataLabel.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +class SvNumberFormatter; + +namespace chart +{ +class DataLabelResources; + +class DataLabelsDialog final : public weld::GenericDialogController +{ +private: + std::unique_ptr m_apDataLabelResources; + +public: + DataLabelsDialog(weld::Window* pParent, const SfxItemSet& rInAttrs, + SvNumberFormatter* pFormatter); + virtual ~DataLabelsDialog() override; + + void FillItemSet(SfxItemSet& rOutAttrs); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertErrorBars.hxx b/chart2/source/controller/inc/dlg_InsertErrorBars.hxx new file mode 100644 index 000000000..e68036153 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertErrorBars.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include "res_ErrorBar.hxx" + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class InsertErrorBarsDialog final : public weld::GenericDialogController +{ +public: + InsertErrorBarsDialog(weld::Window* pParent, const SfxItemSet& rMyAttrs, + const rtl::Reference<::chart::ChartModel>& xChartDocument, + ErrorBarResources::tErrorBarType eType); + + void SetAxisMinorStepWidthForErrorBarDecimals(double fMinorStepWidth); + + static double getAxisMinorStepWidthForErrorBarDecimals( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& xChartView, + const OUString& rSelectedObjectCID); + + void FillItemSet(SfxItemSet& rOutAttrs); + +private: + std::unique_ptr m_apErrorBarResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertLegend.hxx b/chart2/source/controller/inc/dlg_InsertLegend.hxx new file mode 100644 index 000000000..0e2cccc38 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertLegend.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +#include "res_LegendPosition.hxx" + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class ChartModel; + +class SchLegendDlg final : public weld::GenericDialogController +{ +private: + std::unique_ptr m_xLegendPositionResources; + +public: + SchLegendDlg(weld::Window* pParent, const css::uno::Reference< css::uno::XComponentContext>& xCC); + + void init( const rtl::Reference<::chart::ChartModel>& xChartModel ); + void writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_InsertTitle.hxx b/chart2/source/controller/inc/dlg_InsertTitle.hxx new file mode 100644 index 000000000..096628529 --- /dev/null +++ b/chart2/source/controller/inc/dlg_InsertTitle.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "res_Titles.hxx" +#include +#include + +namespace chart +{ +class SchTitleDlg final : public weld::GenericDialogController +{ +private: + std::unique_ptr m_xTitleResources; + +public: + SchTitleDlg(weld::Window* pParent, const TitleDialogData& rInput); + + void getResult(TitleDialogData& rOutput); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ObjectProperties.hxx b/chart2/source/controller/inc/dlg_ObjectProperties.hxx new file mode 100644 index 000000000..238ccc83b --- /dev/null +++ b/chart2/source/controller/inc/dlg_ObjectProperties.hxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star::util { class XNumberFormatsSupplier; } +class Graphic; + +namespace chart +{ + +class ObjectPropertiesDialogParameter final +{ +public: + ObjectPropertiesDialogParameter( const OUString& rObjectCID ); + ~ObjectPropertiesDialogParameter(); + + void init( const rtl::Reference<::chart::ChartModel>& xModel ); + ObjectType getObjectType() const { return m_eObjectType;} + const OUString& getLocalizedName() const { return m_aLocalizedName;} + + bool HasGeometryProperties() const { return m_bHasGeometryProperties;} + bool HasStatisticProperties() const { return m_bHasStatisticProperties;} + bool ProvidesSecondaryYAxis() const { return m_bProvidesSecondaryYAxis;} + bool ProvidesOverlapAndGapWidth() const { return m_bProvidesOverlapAndGapWidth;} + bool ProvidesBarConnectors() const { return m_bProvidesBarConnectors;} + bool HasAreaProperties() const { return m_bHasAreaProperties;} + bool HasSymbolProperties() const { return m_bHasSymbolProperties;} + bool HasNumberProperties() const { return m_bHasNumberProperties;} + bool ProvidesStartingAngle() const { return m_bProvidesStartingAngle;} + bool ProvidesMissingValueTreatments() const { return m_bProvidesMissingValueTreatments;} + bool IsPieChartDataPoint() const { return m_bIsPieChartDataPoint;} + + bool HasScaleProperties() const { return m_bHasScaleProperties;} + bool CanAxisLabelsBeStaggered() const { return m_bCanAxisLabelsBeStaggered;} + bool IsSupportingAxisPositioning() const { return m_bSupportingAxisPositioning;} + bool ShowAxisOrigin() const { return m_bShowAxisOrigin;} + bool IsCrossingAxisIsCategoryAxis() const { return m_bIsCrossingAxisIsCategoryAxis;} + bool IsSupportingCategoryPositioning() const { return m_bSupportingCategoryPositioning;} + const css::uno::Sequence< OUString >& GetCategories() const { return m_aCategories;} + + const rtl::Reference<::chart::ChartModel>& + getDocument() const { return m_xChartDocument;} + + bool IsComplexCategoriesAxis() const { return m_bComplexCategoriesAxis;} + + sal_Int32 getNbPoints() const { return m_nNbPoints;} + +private: + OUString m_aObjectCID; + ObjectType m_eObjectType; + bool m_bAffectsMultipleObjects;//is true if more than one object of the given type will be changed (e.g. all axes or all titles) + + OUString m_aLocalizedName; + + bool m_bHasGeometryProperties; + bool m_bHasStatisticProperties; + bool m_bProvidesSecondaryYAxis; + bool m_bProvidesOverlapAndGapWidth; + bool m_bProvidesBarConnectors; + bool m_bHasAreaProperties; + bool m_bHasSymbolProperties; + bool m_bHasNumberProperties; + bool m_bProvidesStartingAngle; + bool m_bProvidesMissingValueTreatments; + bool m_bIsPieChartDataPoint; + + bool m_bHasScaleProperties; + bool m_bCanAxisLabelsBeStaggered; + + bool m_bSupportingAxisPositioning; + bool m_bShowAxisOrigin; + bool m_bIsCrossingAxisIsCategoryAxis; + bool m_bSupportingCategoryPositioning; + css::uno::Sequence< OUString > m_aCategories; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; + + bool m_bComplexCategoriesAxis; + + sal_Int32 m_nNbPoints; +}; + +/************************************************************************* +|* +|* dialog for properties of different chart object +|* +\************************************************************************/ + +class ViewElementListProvider; + +class SchAttribTabDlg final : public SfxTabDialogController +{ +private: + const ObjectPropertiesDialogParameter * const m_pParameter; + const ViewElementListProvider* const m_pViewElementListProvider; + SvNumberFormatter* m_pNumberFormatter; + + std::optional m_oSymbolShapeProperties; + std::unique_ptr m_pAutoSymbolGraphic; + + double m_fAxisMinorStepWidthForErrorBarDecimals; + bool m_bOKPressed; + + DECL_LINK(OKPressed, weld::Button&, void); + + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; + +public: + SchAttribTabDlg(weld::Window* pParent, const SfxItemSet* pAttr, + const ObjectPropertiesDialogParameter* pDialogParameter, + const ViewElementListProvider* pViewElementListProvider, + const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + virtual ~SchAttribTabDlg() override; + + //pSymbolShapeProperties: Properties to be set on the symbollist shapes + //pAutoSymbolGraphic: Graphic to be shown if AutoSymbol gets selected + void setSymbolInformation( SfxItemSet&& rSymbolShapeProperties, std::unique_ptr pAutoSymbolGraphic ); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + + bool DialogWasClosedWithOK() const { return m_bOKPressed;} +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ShapeFont.hxx b/chart2/source/controller/inc/dlg_ShapeFont.hxx new file mode 100644 index 000000000..6998ba470 --- /dev/null +++ b/chart2/source/controller/inc/dlg_ShapeFont.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class ViewElementListProvider; + +/** dialog for font properties of shapes + */ +class ShapeFontDialog final : public SfxTabDialogController +{ +public: + ShapeFontDialog(weld::Window* pParent, const SfxItemSet* pAttr, + const ViewElementListProvider* pViewElementListProvider); + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; + + const ViewElementListProvider* m_pViewElementListProvider; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_ShapeParagraph.hxx b/chart2/source/controller/inc/dlg_ShapeParagraph.hxx new file mode 100644 index 000000000..9d4d7496d --- /dev/null +++ b/chart2/source/controller/inc/dlg_ShapeParagraph.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +/** dialog for paragraph properties of shapes + */ +class ShapeParagraphDialog final : public SfxTabDialogController +{ +public: + ShapeParagraphDialog(weld::Window* pParent, const SfxItemSet* pAttr); + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/dlg_View3D.hxx b/chart2/source/controller/inc/dlg_View3D.hxx new file mode 100644 index 000000000..c165e8285 --- /dev/null +++ b/chart2/source/controller/inc/dlg_View3D.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class ThreeD_SceneGeometry_TabPage; +class ThreeD_SceneAppearance_TabPage; +class ThreeD_SceneIllumination_TabPage; + +class View3DDialog final : public weld::GenericDialogController +{ +public: + View3DDialog(weld::Window* pWindow, const rtl::Reference<::chart::ChartModel>& xChartModel); + virtual ~View3DDialog() override; + + virtual short run() override; + +private: + DECL_LINK(ActivatePageHdl, const OString&, void); + + ControllerLockHelper m_aControllerLocker; + + static sal_uInt16 m_nLastPageId; + + std::unique_ptr m_xTabControl; + std::unique_ptr m_xGeometry; + std::unique_ptr m_xAppearance; + std::unique_ptr m_xIllumination; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/helpids.h b/chart2/source/controller/inc/helpids.h new file mode 100644 index 000000000..69a23771c --- /dev/null +++ b/chart2/source/controller/inc/helpids.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +inline constexpr OStringLiteral HID_SCH_WIN_DOCUMENT = "CHART2_HID_SCH_WIN_DOCUMENT"; +inline constexpr OStringLiteral HID_SCH_ERROR_BARS_FROM_DATA = "CHART2_SCH_ERROR_BARS_FROM_DATA"; + + + +inline constexpr OStringLiteral HID_SCH_WIZARD_ROADMAP = "CHART2_HID_SCH_WIZARD_ROADMAP"; +inline constexpr OStringLiteral HID_SCH_DATA_SERIES_LABEL = "CHART2_HID_SCH_DATA_SERIES_LABEL"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_ErrorBar.hxx b/chart2/source/controller/inc/res_ErrorBar.hxx new file mode 100644 index 000000000..c3521d5ba --- /dev/null +++ b/chart2/source/controller/inc/res_ErrorBar.hxx @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include "RangeSelectionListener.hxx" +#include + +namespace com::sun::star::chart2 { class XChartDocument; } +namespace weld { class Builder; } +namespace weld { class Button; } +namespace weld { class CheckButton; } +namespace weld { class ComboBox; } +namespace weld { class DialogController; } +namespace weld { class Entry; } +namespace weld { class Frame; } +namespace weld { class Image; } +namespace weld { class Label; } +namespace weld { class MetricSpinButton; } +namespace weld { class RadioButton; } +namespace weld { class Toggleable; } +namespace weld { class Widget; } + +namespace chart +{ +class ChartModel; +class RangeSelectionHelper; + +class ErrorBarResources final : public RangeSelectionListenerParent +{ +public: + enum tErrorBarType + { + ERROR_BAR_X, + ERROR_BAR_Y + }; + + ErrorBarResources( + weld::Builder* pParent, weld::DialogController* pControllerDialog, const SfxItemSet& rInAttrs, bool bNoneAvailable, chart::ErrorBarResources::tErrorBarType eType = ERROR_BAR_Y); + virtual ~ErrorBarResources(); + + void SetAxisMinorStepWidthForErrorBarDecimals( double fMinorStepWidth ); + void SetErrorBarType( tErrorBarType eNewType ); + void SetChartDocumentForRangeChoosing( + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + void Reset(const SfxItemSet& rInAttrs); + void FillItemSet(SfxItemSet& rOutAttrs) const; + + void FillValueSets(); + + // ____ RangeSelectionListenerParent ____ + virtual void listeningFinished( const OUString & rNewRange ) override; + virtual void disposingRangeSelection() override; + +private: + SvxChartKindError m_eErrorKind; + SvxChartIndicate m_eIndicate; + + bool m_bErrorKindUnique; + bool m_bIndicatorUnique; + bool m_bRangePosUnique; + bool m_bRangeNegUnique; + + tErrorBarType m_eErrorBarType; + sal_uInt16 m_nConstDecimalDigits; + sal_Int64 m_nConstSpinSize; + double m_fPlusValue; + double m_fMinusValue; + + weld::DialogController* m_pController; + std::unique_ptr< RangeSelectionHelper > m_apRangeSelectionHelper; + weld::Entry* m_pCurrentRangeChoosingField; + bool m_bHasInternalDataProvider; + bool m_bEnableDataTableDialog; + + + // category + std::unique_ptr m_xRbNone; + std::unique_ptr m_xRbConst; + std::unique_ptr m_xRbPercent; + std::unique_ptr m_xRbFunction; + std::unique_ptr m_xRbRange; + std::unique_ptr m_xLbFunction; + + // parameters + std::unique_ptr m_xFlParameters; + std::unique_ptr m_xBxPositive; + std::unique_ptr m_xMfPositive; + std::unique_ptr m_xEdRangePositive; + std::unique_ptr m_xIbRangePositive; + std::unique_ptr m_xBxNegative; + std::unique_ptr m_xMfNegative; + std::unique_ptr m_xEdRangeNegative; + std::unique_ptr m_xIbRangeNegative; + std::unique_ptr m_xCbSyncPosNeg; + + // indicator + std::unique_ptr m_xRbBoth; + std::unique_ptr m_xRbPositive; + std::unique_ptr m_xRbNegative; + std::unique_ptr m_xFiBoth; + std::unique_ptr m_xFiPositive; + std::unique_ptr m_xFiNegative; + + std::unique_ptr m_xUIStringPos; + std::unique_ptr m_xUIStringNeg; + std::unique_ptr m_xUIStringRbRange; + + DECL_LINK( CategoryChosen, weld::Toggleable&, void ); + DECL_LINK( CategoryChosen2, weld::ComboBox&, void ); + DECL_LINK( SynchronizePosAndNeg, weld::Toggleable&, void ); + DECL_LINK( PosValueChanged, weld::MetricSpinButton&, void ); + DECL_LINK( IndicatorChanged, weld::Toggleable&, void ); + DECL_LINK( ChooseRange, weld::Button&, void ); + DECL_LINK( RangeChanged, weld::Entry&, void ); + + void UpdateControlStates(); + void isRangeFieldContentValid(weld::Entry& rEdit); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_LegendPosition.hxx b/chart2/source/controller/inc/res_LegendPosition.hxx new file mode 100644 index 000000000..ca0870dd4 --- /dev/null +++ b/chart2/source/controller/inc/res_LegendPosition.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } +namespace weld { class Builder; } +namespace weld { class CheckButton; } +namespace weld { class RadioButton; } +namespace weld { class Toggleable; } + +namespace chart +{ +class ChartModel; + +class LegendPositionResources final +{ + +public: + //constructor without Display checkbox + LegendPositionResources(weld::Builder& rBuilder); + //constructor inclusive Display checkbox + LegendPositionResources(weld::Builder& rBuilder, const css::uno::Reference< + css::uno::XComponentContext>& xCC ); + ~LegendPositionResources(); + + void writeToResources( const rtl::Reference<::chart::ChartModel>& xChartModel ); + void writeToModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) const; + + void initFromItemSet( const SfxItemSet& rInAttrs ); + void writeToItemSet( SfxItemSet& rOutAttrs ) const; + + void SetChangeHdl( const Link& rLink ); + + DECL_LINK( PositionEnableHdl, weld::Toggleable&, void ); + DECL_LINK( PositionChangeHdl, weld::Toggleable&, void ); + +private: + void impl_setRadioButtonToggleHdl(); + void PositionEnable(); + +private: + css::uno::Reference< css::uno::XComponentContext> m_xCC; + Link m_aChangeLink; + + std::unique_ptr m_xCbxShow; + std::unique_ptr m_xRbtLeft; + std::unique_ptr m_xRbtRight; + std::unique_ptr m_xRbtTop; + std::unique_ptr m_xRbtBottom; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/res_Titles.hxx b/chart2/source/controller/inc/res_Titles.hxx new file mode 100644 index 000000000..a7a2eba57 --- /dev/null +++ b/chart2/source/controller/inc/res_Titles.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "TitleDialogData.hxx" + +template class Link; +namespace weld +{ +class Builder; +} +namespace weld +{ +class Entry; +} +namespace weld +{ +class Label; +} + +namespace chart +{ +class TitleResources final +{ +public: + TitleResources(weld::Builder& rParent, bool bShowSecondaryAxesTitle); + ~TitleResources(); + + void writeToResources(const TitleDialogData& rInput); + void readFromResources(TitleDialogData& rOutput); + + void connect_changed(const Link& rLink); + bool get_value_changed_from_saved() const; + void save_value(); + +private: + std::unique_ptr m_xFT_Main; + std::unique_ptr m_xFT_Sub; + std::unique_ptr m_xEd_Main; + std::unique_ptr m_xEd_Sub; + + std::unique_ptr m_xFT_XAxis; + std::unique_ptr m_xFT_YAxis; + std::unique_ptr m_xFT_ZAxis; + std::unique_ptr m_xEd_XAxis; + std::unique_ptr m_xEd_YAxis; + std::unique_ptr m_xEd_ZAxis; + + std::unique_ptr m_xFT_SecondaryXAxis; + std::unique_ptr m_xFT_SecondaryYAxis; + std::unique_ptr m_xEd_SecondaryXAxis; + std::unique_ptr m_xEd_SecondaryYAxis; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/inc/uiobject.hxx b/chart2/source/controller/inc/uiobject.hxx new file mode 100644 index 000000000..b40fffb44 --- /dev/null +++ b/chart2/source/controller/inc/uiobject.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +#include "ChartWindow.hxx" + +class ChartUIObject final : public UIObject +{ +public: + + ChartUIObject(const VclPtr& xChartWindow, + const OUString& rCID); + + StringMap get_state() override; + + virtual void execute(const OUString& rAction, + const StringMap& rParameters) override; + + virtual std::unique_ptr get_child(const OUString& rID) override; + + virtual std::set get_children() const override; + + virtual OUString get_type() const override; + +private: + + OUString maCID; + VclPtr mxChartWindow; + std::vector> maCommands; + + DECL_LINK(PostCommand, void*, void); +}; + +class ChartWindowUIObject final : public WindowUIObject +{ + VclPtr mxChartWindow; + +public: + + ChartWindowUIObject(const VclPtr& xChartWindow); + + virtual StringMap get_state() override; + + virtual void execute(const OUString& rAction, + const StringMap& rParameters) override; + + virtual std::unique_ptr get_child(const OUString& rID) override; + + virtual std::set get_children() const override; + + static std::unique_ptr create(vcl::Window* pWindow); + +protected: + + virtual OUString get_name() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx b/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx new file mode 100644 index 000000000..20ad1504f --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/AxisItemConverter.cxx @@ -0,0 +1,987 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::chart::TimeInterval; +using ::com::sun::star::chart::TimeIncrement; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetAxisPropertyMap() +{ + static ItemPropertyMapType aAxisPropertyMap{ + {SCHATTR_AXIS_SHOWDESCR, {"DisplayLabels", 0}}, + {SCHATTR_AXIS_TICKS, {"MajorTickmarks", 0}}, + {SCHATTR_AXIS_HELPTICKS, {"MinorTickmarks", 0}}, + {SCHATTR_AXIS_LABEL_ORDER, {"ArrangeOrder", 0}}, + {SCHATTR_TEXT_STACKED, {"StackCharacters", 0}}, + {SCHATTR_AXIS_LABEL_BREAK, {"TextBreak", 0}}, + {SCHATTR_AXIS_LABEL_OVERLAP, {"TextOverlap", 0}}}; + return aAxisPropertyMap; +}; + +} // anonymous namespace + +AxisItemConverter::AxisItemConverter( + const Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + ::chart::ExplicitScaleData const * pScale /* = NULL */, + ::chart::ExplicitIncrementData const * pIncrement /* = NULL */, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ), + m_xChartDoc( xChartDoc ) +{ + if( pScale ) + m_pExplicitScale.reset( new ::chart::ExplicitScaleData( *pScale ) ); + if( pIncrement ) + m_pExplicitIncrement.reset( new ::chart::ExplicitIncrementData( *pIncrement ) ); + + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xChartDoc, + GraphicObjectType::LineProperties )); + m_aConverters.emplace_back( + new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + + m_xAxis.set( Reference< chart2::XAxis >( rPropertySet, uno::UNO_QUERY ) ); + OSL_ASSERT( m_xAxis.is()); +} + +AxisItemConverter::~AxisItemConverter() +{ +} + +void AxisItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool AxisItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& AxisItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nAxisWhichPairs; +} + +bool AxisItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetAxisPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + + return true; +} + +static bool lcl_hasTimeIntervalValue( const uno::Any& rAny ) +{ + bool bRet = false; + TimeInterval aValue; + if( rAny >>= aValue ) + bRet = true; + return bRet; +} + +void AxisItemConverter::FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + if( !m_xAxis.is() ) + return; + + const chart2::ScaleData& rScale( m_xAxis->getScaleData() ); + const chart2::IncrementData& rIncrement( rScale.IncrementData ); + const uno::Sequence< chart2::SubIncrement >& rSubIncrements( rScale.IncrementData.SubIncrements ); + const TimeIncrement& rTimeIncrement( rScale.TimeIncrement ); + bool bDateAxis = (rScale.AxisType == chart2::AxisType::DATE); + if( m_pExplicitScale ) + bDateAxis = (m_pExplicitScale->AxisType == chart2::AxisType::DATE); + + switch( nWhichId ) + { + case SCHATTR_AXIS_AUTO_MAX: + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rScale.Maximum) ) ); + break; + + case SCHATTR_AXIS_MAX: + { + double fMax = 10.0; + if( rScale.Maximum >>= fMax ) + rOutItemSet.Put( SvxDoubleItem( fMax, SCHATTR_AXIS_MAX ) ); + else + { + if( m_pExplicitScale ) + fMax = m_pExplicitScale->Maximum; + rOutItemSet.Put( SvxDoubleItem( fMax, SCHATTR_AXIS_MAX ) ); + } + } + break; + + case SCHATTR_AXIS_AUTO_MIN: + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rScale.Minimum) ) ); + break; + + case SCHATTR_AXIS_MIN: + { + double fMin = 0.0; + if( rScale.Minimum >>= fMin ) + rOutItemSet.Put( SvxDoubleItem( fMin, SCHATTR_AXIS_MIN ) ); + else if( m_pExplicitScale ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitScale->Minimum, SCHATTR_AXIS_MIN )); + } + break; + + case SCHATTR_AXIS_LOGARITHM: + { + bool bValue = AxisHelper::isLogarithmic( rScale.Scaling ); + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + break; + + case SCHATTR_AXIS_REVERSE: + rOutItemSet.Put( SfxBoolItem( nWhichId, (rScale.Orientation == AxisOrientation_REVERSE) )); + break; + + // Increment + case SCHATTR_AXIS_AUTO_STEP_MAIN: + if( bDateAxis ) + rOutItemSet.Put( SfxBoolItem( nWhichId, !lcl_hasTimeIntervalValue(rTimeIncrement.MajorTimeInterval) ) ); + else + rOutItemSet.Put( SfxBoolItem( nWhichId, !hasDoubleValue(rIncrement.Distance) ) ); + break; + + case SCHATTR_AXIS_MAIN_TIME_UNIT: + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MajorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.TimeUnit ) ); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MajorTimeInterval.TimeUnit ) ); + } + break; + + case SCHATTR_AXIS_STEP_MAIN: + if( bDateAxis ) + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MajorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SvxDoubleItem(aTimeInterval.Number, SCHATTR_AXIS_STEP_MAIN )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitIncrement->MajorTimeInterval.Number, SCHATTR_AXIS_STEP_MAIN )); + } + else + { + double fDistance = 1.0; + if( rIncrement.Distance >>= fDistance ) + rOutItemSet.Put( SvxDoubleItem(fDistance, SCHATTR_AXIS_STEP_MAIN )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SvxDoubleItem( m_pExplicitIncrement->Distance, SCHATTR_AXIS_STEP_MAIN )); + } + break; + + // SubIncrement + case SCHATTR_AXIS_AUTO_STEP_HELP: + if( bDateAxis ) + rOutItemSet.Put( SfxBoolItem( nWhichId, !lcl_hasTimeIntervalValue(rTimeIncrement.MinorTimeInterval) ) ); + else + rOutItemSet.Put( SfxBoolItem( nWhichId, + ! ( rSubIncrements.hasElements() && rSubIncrements[0].IntervalCount.hasValue() ))); + break; + + case SCHATTR_AXIS_HELP_TIME_UNIT: + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MinorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.TimeUnit ) ); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MinorTimeInterval.TimeUnit ) ); + } + break; + + case SCHATTR_AXIS_STEP_HELP: + if( bDateAxis ) + { + TimeInterval aTimeInterval; + if( rTimeIncrement.MinorTimeInterval >>= aTimeInterval ) + rOutItemSet.Put( SfxInt32Item( nWhichId, aTimeInterval.Number )); + else if( m_pExplicitIncrement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitIncrement->MinorTimeInterval.Number )); + } + else + { + if( rSubIncrements.hasElements() && rSubIncrements[0].IntervalCount.hasValue()) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, + *o3tl::doAccess( + rSubIncrements[0].IntervalCount) )); + } + else + { + if( m_pExplicitIncrement && !m_pExplicitIncrement->SubIncrements.empty() ) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, + m_pExplicitIncrement->SubIncrements[0].IntervalCount )); + } + } + } + break; + + case SCHATTR_AXIS_AUTO_TIME_RESOLUTION: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, + !rTimeIncrement.TimeResolution.hasValue() )); + } + break; + case SCHATTR_AXIS_TIME_RESOLUTION: + { + sal_Int32 nTimeResolution=0; + if( rTimeIncrement.TimeResolution >>= nTimeResolution ) + rOutItemSet.Put( SfxInt32Item( nWhichId, nTimeResolution ) ); + else if( m_pExplicitScale ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_pExplicitScale->TimeResolution ) ); + } + break; + + case SCHATTR_AXIS_AUTO_ORIGIN: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, ( !hasDoubleValue(rScale.Origin) ))); + } + break; + + case SCHATTR_AXIS_ORIGIN: + { + double fOrigin = 0.0; + if( !(rScale.Origin >>= fOrigin) ) + { + if( m_pExplicitScale ) + fOrigin = m_pExplicitScale->Origin; + } + rOutItemSet.Put( SvxDoubleItem( fOrigin, SCHATTR_AXIS_ORIGIN )); + } + break; + + case SCHATTR_AXIS_POSITION: + { + css::chart::ChartAxisPosition eAxisPos( css::chart::ChartAxisPosition_ZERO ); + GetPropertySet()->getPropertyValue( "CrossoverPosition" ) >>= eAxisPos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast(eAxisPos) ) ); + } + break; + + case SCHATTR_AXIS_POSITION_VALUE: + { + double fValue = 0.0; + if( GetPropertySet()->getPropertyValue( "CrossoverValue" ) >>= fValue ) + rOutItemSet.Put( SvxDoubleItem( fValue, SCHATTR_AXIS_POSITION_VALUE ) ); + } + break; + + case SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT: + { + //read only item + //necessary tp display the crossing value with an appropriate format + + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + xCrossingMainAxis, xCooSys, m_xChartDoc); + + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + break; + + case SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION: + rOutItemSet.Put(SfxBoolItem(nWhichId, rScale.ShiftedCategoryPosition)); + break; + + case SCHATTR_AXIS_LABEL_POSITION: + { + css::chart::ChartAxisLabelPosition ePos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + GetPropertySet()->getPropertyValue( "LabelPosition" ) >>= ePos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast(ePos) ) ); + } + break; + + case SCHATTR_AXIS_MARK_POSITION: + { + css::chart::ChartAxisMarkPosition ePos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + GetPropertySet()->getPropertyValue( "MarkPosition" ) >>= ePos; + rOutItemSet.Put( SfxInt32Item( nWhichId, static_cast(ePos) ) ); + } + break; + + case SCHATTR_TEXT_DEGREES: + { + // convert double to int (times 100) + double fVal = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fVal ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fVal * 100.0 )) ) )); + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + if( m_pExplicitScale ) + { + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + m_xAxis, xCooSys, m_xChartDoc); + + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bLinkToSource = true; + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource; + rOutItemSet.Put(SfxBoolItem(nWhichId, bLinkToSource)); + } + break; + + case SCHATTR_AXISTYPE: + rOutItemSet.Put( SfxInt32Item( nWhichId, rScale.AxisType )); + break; + + case SCHATTR_AXIS_AUTO_DATEAXIS: + rOutItemSet.Put( SfxBoolItem( nWhichId, rScale.AutoDateAxis )); + break; + + case SCHATTR_AXIS_ALLOW_DATEAXIS: + { + rtl::Reference< BaseCoordinateSystem > xCooSys( + AxisHelper::getCoordinateSystemOfAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0; + AxisHelper::getIndicesForAxis(m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex ); + rOutItemSet.Put( SfxBoolItem( nWhichId, bChartTypeAllowsDateAxis )); + } + break; + } +} + +static bool lcl_isDateAxis( const SfxItemSet & rItemSet ) +{ + sal_Int32 nAxisType = rItemSet.Get( SCHATTR_AXISTYPE ).GetValue();//css::chart2::AxisType + return (nAxisType == chart2::AxisType::DATE); +} + +static bool lcl_isAutoMajor( const SfxItemSet & rItemSet ) +{ + bool bRet = rItemSet.Get( SCHATTR_AXIS_AUTO_STEP_MAIN ).GetValue(); + return bRet; +} + +static bool lcl_isAutoMinor( const SfxItemSet & rItemSet ) +{ + bool bRet = rItemSet.Get( SCHATTR_AXIS_AUTO_STEP_HELP ).GetValue(); + return bRet; +} + +bool AxisItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + if( !m_xAxis.is() ) + return false; + + chart2::ScaleData aScale( m_xAxis->getScaleData() ); + + bool bSetScale = false; + bool bChangedOtherwise = false; + + uno::Any aValue; + + switch( nWhichId ) + { + case SCHATTR_AXIS_AUTO_MAX: + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Maximum.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_MAX must have some value + break; + + case SCHATTR_AXIS_MAX: + // only if auto if false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_MAX ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Maximum != aValue ) + { + aScale.Maximum = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_AUTO_MIN: + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Minimum.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_MIN must have some value + break; + + case SCHATTR_AXIS_MIN: + // only if auto if false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_MIN ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Minimum != aValue ) + { + aScale.Minimum = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_LOGARITHM: + { + bool bWasLogarithm = AxisHelper::isLogarithmic( aScale.Scaling ); + + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + // logarithm is true + if( ! bWasLogarithm ) + { + aScale.Scaling = AxisHelper::createLogarithmicScaling( 10.0 ); + bSetScale = true; + } + } + else + { + // logarithm is false => linear scaling + if( bWasLogarithm ) + { + aScale.Scaling = AxisHelper::createLinearScaling(); + bSetScale = true; + } + } + } + break; + + case SCHATTR_AXIS_REVERSE: + { + bool bWasReverse = ( aScale.Orientation == AxisOrientation_REVERSE ); + bool bNewReverse = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( bWasReverse != bNewReverse ) + { + aScale.Orientation = bNewReverse ? AxisOrientation_REVERSE : AxisOrientation_MATHEMATICAL; + bSetScale = true; + } + } + break; + + // Increment + case SCHATTR_AXIS_AUTO_STEP_MAIN: + if( lcl_isAutoMajor(rItemSet) ) + { + aScale.IncrementData.Distance.clear(); + aScale.TimeIncrement.MajorTimeInterval.clear(); + bSetScale = true; + } + // else SCHATTR_AXIS_STEP_MAIN must have some value + break; + + case SCHATTR_AXIS_MAIN_TIME_UNIT: + if( !lcl_isAutoMajor(rItemSet) ) + { + if( rItemSet.Get( nWhichId ).QueryValue( aValue ) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MajorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.TimeUnit; + aScale.TimeIncrement.MajorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_STEP_MAIN: + // only if auto if false + if( !lcl_isAutoMajor(rItemSet) ) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + if( lcl_isDateAxis(rItemSet) ) + { + double fValue = 1.0; + if( aValue >>= fValue ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MajorTimeInterval >>= aTimeInterval; + aTimeInterval.Number = static_cast(fValue); + aScale.TimeIncrement.MajorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + else if( aScale.IncrementData.Distance != aValue ) + { + aScale.IncrementData.Distance = aValue; + bSetScale = true; + } + } + break; + + // SubIncrement + case SCHATTR_AXIS_AUTO_STEP_HELP: + if( lcl_isAutoMinor(rItemSet) ) + { + if( aScale.IncrementData.SubIncrements.hasElements() && + aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() ) + { + aScale.IncrementData.SubIncrements.getArray()[0].IntervalCount.clear(); + bSetScale = true; + } + if( aScale.TimeIncrement.MinorTimeInterval.hasValue() ) + { + aScale.TimeIncrement.MinorTimeInterval.clear(); + bSetScale = true; + } + } + // else SCHATTR_AXIS_STEP_MAIN must have some value + break; + + case SCHATTR_AXIS_HELP_TIME_UNIT: + if( !lcl_isAutoMinor(rItemSet) ) + { + if( rItemSet.Get( nWhichId ).QueryValue( aValue ) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MinorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.TimeUnit; + aScale.TimeIncrement.MinorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_STEP_HELP: + // only if auto is false + if( !lcl_isAutoMinor(rItemSet) ) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + if( lcl_isDateAxis(rItemSet) ) + { + TimeInterval aTimeInterval; + aScale.TimeIncrement.MinorTimeInterval >>= aTimeInterval; + aValue >>= aTimeInterval.Number; + aScale.TimeIncrement.MinorTimeInterval <<= aTimeInterval; + bSetScale = true; + } + else if( aScale.IncrementData.SubIncrements.hasElements() ) + { + if( ! aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue() || + aScale.IncrementData.SubIncrements[0].IntervalCount != aValue ) + { + OSL_ASSERT( aValue.getValueTypeClass() == uno::TypeClass_LONG ); + aScale.IncrementData.SubIncrements.getArray()[0].IntervalCount = aValue; + bSetScale = true; + } + } + } + break; + + case SCHATTR_AXIS_AUTO_TIME_RESOLUTION: + if( static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.TimeIncrement.TimeResolution.clear(); + bSetScale = true; + } + break; + case SCHATTR_AXIS_TIME_RESOLUTION: + // only if auto is false + if( ! ( rItemSet.Get( SCHATTR_AXIS_AUTO_TIME_RESOLUTION ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.TimeIncrement.TimeResolution != aValue ) + { + aScale.TimeIncrement.TimeResolution = aValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_AUTO_ORIGIN: + { + if( static_cast< const SfxBoolItem & >(rItemSet.Get( nWhichId )).GetValue() ) + { + aScale.Origin.clear(); + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_ORIGIN: + { + // only if auto is false + if( ! (rItemSet.Get( SCHATTR_AXIS_AUTO_ORIGIN ).GetValue() )) + { + rItemSet.Get( nWhichId ).QueryValue( aValue ); + + if( aScale.Origin != aValue ) + { + aScale.Origin = aValue; + bSetScale = true; + + if( !AxisHelper::isAxisPositioningEnabled() ) + { + //keep old and new settings for axis positioning in sync somehow + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ) && nAxisIndex==0 ) + { + rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ); + if( xCrossingMainAxis.is() ) + { + double fValue = 0.0; + if( aValue >>= fValue ) + { + xCrossingMainAxis->setPropertyValue( "CrossoverPosition" , uno::Any( css::chart::ChartAxisPosition_VALUE )); + xCrossingMainAxis->setPropertyValue( "CrossoverValue" , uno::Any( fValue )); + } + else + xCrossingMainAxis->setPropertyValue( "CrossoverPosition" , uno::Any( css::chart::ChartAxisPosition_START )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_POSITION: + { + css::chart::ChartAxisPosition eAxisPos = + static_cast(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisPosition eOldAxisPos( css::chart::ChartAxisPosition_ZERO ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "CrossoverPosition" ) >>= eOldAxisPos ); + + if( !bPropExisted || ( eOldAxisPos != eAxisPos )) + { + GetPropertySet()->setPropertyValue( "CrossoverPosition" , uno::Any( eAxisPos )); + bChangedOtherwise = true; + + //move the parallel axes to the other side if necessary + if( eAxisPos==css::chart::ChartAxisPosition_START || eAxisPos==css::chart::ChartAxisPosition_END ) + { + rtl::Reference< Axis > xParallelAxis = AxisHelper::getParallelAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + if( xParallelAxis.is() ) + { + css::chart::ChartAxisPosition eOtherPos; + if( xParallelAxis->getPropertyValue( "CrossoverPosition" ) >>= eOtherPos ) + { + if( eOtherPos == eAxisPos ) + { + css::chart::ChartAxisPosition eOppositePos = + (eAxisPos==css::chart::ChartAxisPosition_START) + ? css::chart::ChartAxisPosition_END + : css::chart::ChartAxisPosition_START; + xParallelAxis->setPropertyValue( "CrossoverPosition" , uno::Any( eOppositePos )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_POSITION_VALUE: + { + double fValue = static_cast< const SvxDoubleItem & >( rItemSet.Get( nWhichId )).GetValue(); + + double fOldValue = 0.0; + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "CrossoverValue" ) >>= fOldValue ); + + if( !bPropExisted || ( fOldValue != fValue )) + { + GetPropertySet()->setPropertyValue( "CrossoverValue" , uno::Any( fValue )); + bChangedOtherwise = true; + + //keep old and new settings for axis positioning in sync somehow + { + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ) ); + + sal_Int32 nDimensionIndex=0; + sal_Int32 nAxisIndex=0; + if( AxisHelper::getIndicesForAxis( m_xAxis, xCooSys, nDimensionIndex, nAxisIndex ) && nAxisIndex==0 ) + { + Reference< chart2::XAxis > xCrossingMainAxis( AxisHelper::getCrossingMainAxis( m_xAxis, xCooSys ) ); + if( xCrossingMainAxis.is() ) + { + ScaleData aCrossingScale( xCrossingMainAxis->getScaleData() ); + aCrossingScale.Origin <<= fValue; + xCrossingMainAxis->setScaleData(aCrossingScale); + } + } + } + } + } + break; + + case SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION: + { + bool bNewValue = static_cast (rItemSet.Get(nWhichId)).GetValue(); + bool bOldValue = aScale.ShiftedCategoryPosition; + if (bOldValue != bNewValue) + { + aScale.ShiftedCategoryPosition = bNewValue; + bSetScale = true; + } + } + break; + + case SCHATTR_AXIS_LABEL_POSITION: + { + css::chart::ChartAxisLabelPosition ePos = + static_cast(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisLabelPosition eOldPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "LabelPosition" ) >>= eOldPos ); + + if( !bPropExisted || ( eOldPos != ePos )) + { + GetPropertySet()->setPropertyValue( "LabelPosition" , uno::Any( ePos )); + bChangedOtherwise = true; + + //move the parallel axes to the other side if necessary + if( ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_START || ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + { + rtl::Reference< Axis > xParallelAxis = AxisHelper::getParallelAxis( m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + if( xParallelAxis.is() ) + { + css::chart::ChartAxisLabelPosition eOtherPos; + if( xParallelAxis->getPropertyValue( "LabelPosition" ) >>= eOtherPos ) + { + if( eOtherPos == ePos ) + { + css::chart::ChartAxisLabelPosition eOppositePos = + (ePos==css::chart::ChartAxisLabelPosition_OUTSIDE_START) + ? css::chart::ChartAxisLabelPosition_OUTSIDE_END + : css::chart::ChartAxisLabelPosition_OUTSIDE_START; + xParallelAxis->setPropertyValue( "LabelPosition" , uno::Any( eOppositePos )); + } + } + } + } + } + } + break; + + case SCHATTR_AXIS_MARK_POSITION: + { + css::chart::ChartAxisMarkPosition ePos = + static_cast(static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue()); + + css::chart::ChartAxisMarkPosition eOldPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + bool bPropExisted = ( GetPropertySet()->getPropertyValue( "MarkPosition" ) >>= eOldPos ); + + if( !bPropExisted || ( eOldPos != ePos )) + { + GetPropertySet()->setPropertyValue( "MarkPosition" , uno::Any( ePos )); + bChangedOtherwise = true; + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fVal = toDegrees(rItemSet.Get(SCHATTR_TEXT_DEGREES).GetValue()); + double fOldVal = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldVal ); + + if( ! bPropExisted || fOldVal != fVal ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fVal )); + bChangedOtherwise = true; + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + if( m_pExplicitScale ) + { + bool bUseSourceFormat = + rItemSet.Get( SID_ATTR_NUMBERFORMAT_SOURCE ).GetValue(); + + if( ! bUseSourceFormat ) + { + sal_Int32 nFmt = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + + aValue <<= nFmt; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) != aValue) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT , aValue); + bChangedOtherwise = true; + } + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = + static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + GetPropertySet()->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue(); + + bChangedOtherwise = (bUseSourceFormat == bNumberFormatIsSet); + if( bChangedOtherwise ) + { + if( ! bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( SID_ATTR_NUMBERFORMAT_VALUE ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFormatKey = static_cast< sal_Int32 >( + rItemSet.Get( SID_ATTR_NUMBERFORMAT_VALUE ).GetValue()); + aValue <<= nFormatKey; + } + else + { + rtl::Reference< BaseCoordinateSystem > xCooSys = + AxisHelper::getCoordinateSystemOfAxis( + m_xAxis, ChartModelHelper::findDiagram( m_xChartDoc ) ); + + sal_Int32 nFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + m_xAxis, xCooSys, m_xChartDoc); + + aValue <<= nFormatKey; + } + } + // else set a void Any + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT , aValue); + } + } + break; + + case SCHATTR_AXISTYPE: + { + sal_Int32 nNewAxisType = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue();//css::chart2::AxisType + aScale.AxisType = nNewAxisType; + bSetScale = true; + } + break; + + case SCHATTR_AXIS_AUTO_DATEAXIS: + { + bool bNewValue = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOldValue = aScale.AutoDateAxis; + if( bOldValue != bNewValue ) + { + aScale.AutoDateAxis = bNewValue; + bSetScale = true; + } + } + break; + } + + if( bSetScale ) + m_xAxis->setScaleData( aScale ); + + return (bSetScale || bChangedOtherwise); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx b/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx new file mode 100644 index 000000000..5345f9168 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/CharacterPropertyItemConverter.cxx @@ -0,0 +1,556 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetCharacterPropertyPropertyMap() +{ + static ItemPropertyMapType aCharacterPropertyMap{ + {EE_CHAR_COLOR, {"CharColor", 0}}, + {EE_CHAR_LANGUAGE, {"CharLocale", MID_LANG_LOCALE}}, + {EE_CHAR_LANGUAGE_CJK, {"CharLocaleAsian", MID_LANG_LOCALE}}, + {EE_CHAR_LANGUAGE_CTL, {"CharLocaleComplex", MID_LANG_LOCALE}}, + + {EE_CHAR_STRIKEOUT, {"CharStrikeout", MID_CROSS_OUT}}, + {EE_CHAR_WLM, {"CharWordMode", 0}}, + {EE_CHAR_SHADOW, {"CharShadowed", 0}}, + {EE_CHAR_RELIEF, {"CharRelief", 0}}, + {EE_CHAR_OUTLINE, {"CharContoured", 0}}, + {EE_CHAR_EMPHASISMARK, {"CharEmphasis", 0}}, + + {EE_PARA_WRITINGDIR, {"WritingMode", 0}}, + + {EE_PARA_ASIANCJKSPACING, {"ParaIsCharacterDistance", 0}}}; + + return aCharacterPropertyMap; +} +} // anonymous namespace + +CharacterPropertyItemConverter::CharacterPropertyItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + ItemConverter( rPropertySet, rItemPool ) +{} + +CharacterPropertyItemConverter::CharacterPropertyItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + const awt::Size* pRefSize, + const OUString & rRefSizePropertyName, + const uno::Reference< beans::XPropertySet > & rRefSizePropSet ) : + ItemConverter( rPropertySet, rItemPool ), + m_aRefSizePropertyName( rRefSizePropertyName ), + m_xRefSizePropSet( rRefSizePropSet.is() ? rRefSizePropSet : rPropertySet ) +{ + if (pRefSize) + m_pRefSize = *pRefSize; +} + +CharacterPropertyItemConverter::~CharacterPropertyItemConverter() +{} + +const WhichRangesContainer& CharacterPropertyItemConverter::GetWhichPairs() const +{ + return nCharacterPropertyWhichPairs; +} + +bool CharacterPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetCharacterPropertyPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +void CharacterPropertyItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTINFO_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTINFO_CTL ) + aPostfix = "Complex"; + + SvxFontItem aItem( nWhichId ); + + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontName" + aPostfix), + MID_FONT_FAMILY_NAME ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontFamily" + aPostfix), + MID_FONT_FAMILY ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontStyleName" + aPostfix), + MID_FONT_STYLE_NAME ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontCharSet" + aPostfix), + MID_FONT_CHAR_SET ); + aItem.PutValue( GetPropertySet()->getPropertyValue( "CharFontPitch" + aPostfix), + MID_FONT_PITCH ); + + rOutItemSet.Put( aItem ); + } + break; + + case EE_CHAR_UNDERLINE: + { + SvxUnderlineItem aItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE); + bool bModified = false; + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharUnderline" )); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_TL_STYLE ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharUnderlineHasColor" ); + if( aValue.hasValue() && *o3tl::doAccess(aValue) ) + { + aItem.PutValue( aValue, MID_TL_HASCOLOR ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharUnderlineColor" ); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_TL_COLOR ); + bModified = true; + } + + if( bModified ) + rOutItemSet.Put( aItem ); + } + break; + + case EE_CHAR_OVERLINE: + { + SvxOverlineItem aItem( LINESTYLE_NONE, EE_CHAR_OVERLINE ); + bool bModified = false; + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharOverline" ) ); + if ( aValue.hasValue() ) + { + aItem.PutValue( aValue, MID_TL_STYLE ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharOverlineHasColor" ); + if ( aValue.hasValue() && *o3tl::doAccess(aValue) ) + { + aItem.PutValue( aValue, MID_TL_HASCOLOR ); + bModified = true; + } + + aValue = GetPropertySet()->getPropertyValue( "CharOverlineColor" ); + if ( aValue.hasValue() ) + { + aItem.PutValue( aValue, MID_TL_COLOR ); + bModified = true; + } + + if ( bModified ) + { + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_ITALIC_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_ITALIC_CTL ) + aPostfix = "Complex"; + + SvxPostureItem aItem( ITALIC_NONE, nWhichId ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharPosture" + aPostfix)); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_POSTURE ); + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_WEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_WEIGHT_CTL ) + aPostfix = "Complex"; + + SvxWeightItem aItem( WEIGHT_NORMAL, nWhichId ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharWeight" + aPostfix)); + if( aValue.hasValue()) + { + aItem.PutValue( aValue, MID_WEIGHT ); + rOutItemSet.Put( aItem ); + } + } + break; + + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTHEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL ) + aPostfix = "Complex"; + + SvxFontHeightItem aItem( 240, 100, nWhichId ); + + try + { + uno::Any aValue( GetPropertySet()->getPropertyValue( "CharHeight" + aPostfix )); + float fHeight; + if( aValue >>= fHeight ) + { + if (m_pRefSize) + { + awt::Size aOldRefSize; + if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize ) + { + // calculate font height in view + fHeight = static_cast< float >( + RelativeSizeHelper::calculate( fHeight, aOldRefSize, *m_pRefSize )); + aValue <<= fHeight; + } + } + + aItem.PutValue( aValue, MID_FONTHEIGHT ); + rOutItemSet.Put( aItem ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + break; + + case SID_CHAR_DLG_PREVIEW_STRING: + { + uno::Reference< chart2::XFormattedString > xFormattedString( GetPropertySet(), uno::UNO_QUERY ); + if( xFormattedString.is() ) + { + OUString aString = xFormattedString->getString(); + rOutItemSet.Put( SfxStringItem( nWhichId, aString ) ); + } + else + rOutItemSet.Put( SfxStringItem( nWhichId, OUString() ) ); + } + break; + + case EE_PARA_FORBIDDENRULES: + case EE_PARA_HANGINGPUNCTUATION: + rOutItemSet.DisableItem( nWhichId ); + break; + } +} + +bool CharacterPropertyItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + uno::Any aValue; + + switch( nWhichId ) + { + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTINFO_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTINFO_CTL ) + aPostfix = "Complex"; + + const SvxFontItem & rItem = + static_cast< const SvxFontItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_FONT_FAMILY_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontName" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontName" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_FAMILY )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontFamily" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontFamily" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_STYLE_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontStyleName" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontStyleName" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_CHAR_SET )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontCharSet" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontCharSet" + aPostfix, aValue ); + bChanged = true; + } + } + if( rItem.QueryValue( aValue, MID_FONT_PITCH )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharFontPitch" + aPostfix )) + { + GetPropertySet()->setPropertyValue( "CharFontPitch" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_UNDERLINE: + { + const SvxUnderlineItem & rItem = + static_cast< const SvxUnderlineItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_TL_STYLE )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderline" )) + { + GetPropertySet()->setPropertyValue( "CharUnderline" , aValue ); + bChanged = true; + } + } + + if( rItem.QueryValue( aValue, MID_TL_COLOR )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderlineColor" )) + { + GetPropertySet()->setPropertyValue( "CharUnderlineColor" , aValue ); + bChanged = true; + } + } + + if( rItem.QueryValue( aValue, MID_TL_HASCOLOR )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharUnderlineHasColor" )) + { + GetPropertySet()->setPropertyValue( "CharUnderlineHasColor" , aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_OVERLINE: + { + const SvxOverlineItem& rItem = static_cast< const SvxOverlineItem & >( rItemSet.Get( nWhichId ) ); + + if ( rItem.QueryValue( aValue, MID_TL_STYLE ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverline" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverline" , aValue ); + bChanged = true; + } + } + + if ( rItem.QueryValue( aValue, MID_TL_COLOR ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverlineColor" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverlineColor" , aValue ); + bChanged = true; + } + } + + if ( rItem.QueryValue( aValue, MID_TL_HASCOLOR ) ) + { + if ( aValue != GetPropertySet()->getPropertyValue( "CharOverlineHasColor" ) ) + { + GetPropertySet()->setPropertyValue( "CharOverlineHasColor" , aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_ITALIC_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_ITALIC_CTL ) + aPostfix = "Complex"; + + const SvxPostureItem & rItem = + static_cast< const SvxPostureItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_POSTURE )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharPosture" + aPostfix)) + { + GetPropertySet()->setPropertyValue( "CharPosture" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_WEIGHT_CJK ) + aPostfix = "Asian" ; + else if( nWhichId == EE_CHAR_WEIGHT_CTL ) + aPostfix = "Complex"; + + const SvxWeightItem & rItem = + static_cast< const SvxWeightItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_WEIGHT )) + { + if( aValue != GetPropertySet()->getPropertyValue( "CharWeight" + aPostfix)) + { + GetPropertySet()->setPropertyValue( "CharWeight" + aPostfix, aValue ); + bChanged = true; + } + } + } + break; + + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + OUString aPostfix; + if( nWhichId == EE_CHAR_FONTHEIGHT_CJK ) + aPostfix = "Asian"; + else if( nWhichId == EE_CHAR_FONTHEIGHT_CTL ) + aPostfix = "Complex"; + + const SvxFontHeightItem & rItem = + static_cast< const SvxFontHeightItem & >( + rItemSet.Get( nWhichId )); + + try + { + if( rItem.QueryValue( aValue, MID_FONTHEIGHT ) ) + { + bool bSetValue = false; + if( aValue != GetPropertySet()->getPropertyValue( "CharHeight" + aPostfix )) + bSetValue = true; + else + { + if (m_pRefSize) + { + awt::Size aNewRefSize = *m_pRefSize; + awt::Size aOldRefSize; + if( GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ) >>= aOldRefSize ) + { + if( aNewRefSize.Width != aOldRefSize.Width + || aNewRefSize.Height != aOldRefSize.Height ) + bSetValue = true; + } + } + } + if( bSetValue ) + { + // set new reference size only if there was a reference size before (auto-scaling on) + if (m_pRefSize && GetRefSizePropertySet()->getPropertyValue( m_aRefSizePropertyName ).hasValue()) + { + GetRefSizePropertySet()->setPropertyValue( + m_aRefSizePropertyName, uno::Any(*m_pRefSize)); + } + + GetPropertySet()->setPropertyValue( "CharHeight" + aPostfix, aValue ); + bChanged = true; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + break; + } + + return bChanged; +} + +const uno::Reference& CharacterPropertyItemConverter::GetRefSizePropertySet() const +{ + return m_xRefSizePropSet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx new file mode 100644 index 000000000..a6c4c34dc --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/DataPointItemConverter.cxx @@ -0,0 +1,822 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetDataPointPropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyMap{ + {SCHATTR_STYLE_SHAPE, {"Geometry3D", 0}}}; + return aDataPointPropertyMap; +}; + +sal_Int32 lcl_getSymbolStyleForSymbol( const chart2::Symbol & rSymbol ) +{ + sal_Int32 nStyle = SVX_SYMBOLTYPE_UNKNOWN; + switch( rSymbol.Style ) + { + case chart2::SymbolStyle_NONE: + nStyle = SVX_SYMBOLTYPE_NONE; + break; + case chart2::SymbolStyle_AUTO: + nStyle = SVX_SYMBOLTYPE_AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nStyle = SVX_SYMBOLTYPE_BRUSHITEM; + break; + case chart2::SymbolStyle_STANDARD: + nStyle = rSymbol.StandardSymbol; + break; + + case chart2::SymbolStyle_POLYGON: + // to avoid warning + case chart2::SymbolStyle::SymbolStyle_MAKE_FIXED_SIZE: + // nothing + break; + } + return nStyle; +} + +bool lcl_NumberFormatFromItemToPropertySet( sal_uInt16 nWhichId, const SfxItemSet & rItemSet, const uno::Reference< beans::XPropertySet > & xPropertySet, bool bOverwriteAttributedDataPointsAlso ) +{ + bool bChanged = false; + if( !xPropertySet.is() ) + return bChanged; + OUString aPropertyName = (nWhichId==SID_ATTR_NUMBERFORMAT_VALUE) ? OUString(CHART_UNONAME_NUMFMT) : OUString( "PercentageNumberFormat" ); + sal_uInt16 nSourceWhich = (nWhichId==SID_ATTR_NUMBERFORMAT_VALUE) ? SID_ATTR_NUMBERFORMAT_SOURCE : SCHATTR_PERCENT_NUMBERFORMAT_SOURCE; + + if( rItemSet.GetItemState( nSourceWhich ) != SfxItemState::SET ) + return bChanged; + + uno::Any aValue; + bool bUseSourceFormat = static_cast< const SfxBoolItem & >( + rItemSet.Get( nSourceWhich )).GetValue(); + if( !bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( nWhichId ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFmt = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + aValue <<= nFmt; + } + else + return bChanged; + } + + uno::Any aOldValue( xPropertySet->getPropertyValue(aPropertyName) ); + if( bOverwriteAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( xPropertySet, uno::UNO_QUERY); + if( aValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, aPropertyName, aOldValue ) ) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, aPropertyName, aValue ); + bChanged = true; + } + } + else if( aOldValue != aValue ) + { + xPropertySet->setPropertyValue(aPropertyName, aValue ); + bChanged = true; + } + return bChanged; +} + +bool lcl_UseSourceFormatFromItemToPropertySet( sal_uInt16 nWhichId, const SfxItemSet & rItemSet, const uno::Reference< beans::XPropertySet > & xPropertySet, bool bOverwriteAttributedDataPointsAlso ) +{ + bool bChanged = false; + if( !xPropertySet.is() ) + return bChanged; + OUString aPropertyName = (nWhichId==SID_ATTR_NUMBERFORMAT_SOURCE) ? OUString(CHART_UNONAME_NUMFMT) : OUString( "PercentageNumberFormat" ); + sal_uInt16 nFormatWhich = (nWhichId==SID_ATTR_NUMBERFORMAT_SOURCE) ? SID_ATTR_NUMBERFORMAT_VALUE : SCHATTR_PERCENT_NUMBERFORMAT_VALUE; + + if( rItemSet.GetItemState( nWhichId ) != SfxItemState::SET ) + return bChanged; + + uno::Any aNewValue; + bool bUseSourceFormat = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + xPropertySet->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + if( !bUseSourceFormat ) + { + SfxItemState aState = rItemSet.GetItemState( nFormatWhich ); + if( aState == SfxItemState::SET ) + { + sal_Int32 nFormatKey = static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nFormatWhich )).GetValue()); + aNewValue <<= nFormatKey; + } + else + return bChanged; + } + + uno::Any aOldValue( xPropertySet->getPropertyValue(aPropertyName) ); + if( bOverwriteAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( xPropertySet, uno::UNO_QUERY); + if( aNewValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, aPropertyName, aOldValue ) ) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, aPropertyName, aNewValue ); + bChanged = true; + } + } + else if( aOldValue != aNewValue ) + { + xPropertySet->setPropertyValue( aPropertyName, aNewValue ); + bChanged = true; + } + + return bChanged; +} + +} // anonymous namespace + +DataPointItemConverter::DataPointItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + const uno::Reference< uno::XComponentContext > & xContext, + const uno::Reference< beans::XPropertySet > & rPropertySet, + const rtl::Reference< DataSeries > & xSeries, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference& xNamedPropertyContainerFactory, + GraphicObjectType eMapTo, + const awt::Size* pRefSize, + bool bDataSeries, + bool bUseSpecialFillColor, + sal_Int32 nSpecialFillColor, + bool bOverwriteLabelsForAttributedDataPointsAlso, + sal_Int32 nNumberFormat, + sal_Int32 nPercentNumberFormat, + sal_Int32 nPointIndex ) : + ItemConverter( rPropertySet, rItemPool ), + m_bDataSeries( bDataSeries ), + m_bOverwriteLabelsForAttributedDataPointsAlso(m_bDataSeries && bOverwriteLabelsForAttributedDataPointsAlso), + m_bUseSpecialFillColor(bUseSpecialFillColor), + m_nSpecialFillColor(ColorTransparency, nSpecialFillColor), + m_nNumberFormat(nNumberFormat), + m_nPercentNumberFormat(nPercentNumberFormat), + m_bForbidPercentValue(true), + m_bHideLegendEntry(false), + m_nPointIndex(nPointIndex), + m_xSeries(xSeries) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, xNamedPropertyContainerFactory, eMapTo )); + m_aConverters.emplace_back( new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + if( bDataSeries ) + { + m_aConverters.emplace_back( new StatisticsItemConverter( xChartModel, rPropertySet, rItemPool )); + m_aConverters.emplace_back( new SeriesOptionsItemConverter( xChartModel, xContext, rPropertySet, rItemPool )); + } + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xSeries ) ); + bool bFound = false; + bool bAmbiguous = false; + bool bSwapXAndY = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + m_aAvailableLabelPlacements = ChartTypeHelper::getSupportedLabelPlacements( xChartType, bSwapXAndY, xSeries ); + + m_bForbidPercentValue = ChartTypeHelper::getAxisType( xChartType, 0 ) != AxisType::CATEGORY; + + if (bDataSeries) + return; + + uno::Sequence deletedLegendEntriesSeq; + xSeries->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (nPointIndex == deletedLegendEntry) + { + m_bHideLegendEntry = true; + break; + } + } +} + +DataPointItemConverter::~DataPointItemConverter() +{ +} + +void DataPointItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); + + if( m_bUseSpecialFillColor ) + { + Color aColor(m_nSpecialFillColor); + rOutItemSet.Put( XFillColorItem( OUString(), aColor ) ); + } +} + +bool DataPointItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& DataPointItemConverter::GetWhichPairs() const +{ + // must span all used items! + if( m_bDataSeries ) + return nRowWhichPairs; + return nDataPointWhichPairs; +} + +bool DataPointItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetDataPointPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool DataPointItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + const SfxBoolItem & rItem = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )); + + uno::Any aOldValue = GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL); + chart2::DataPointLabel aLabel; + if( aOldValue >>= aLabel ) + { + sal_Bool& rValue = (nWhichId==SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol ))); + bool bOldValue = rValue; + rValue = rItem.GetValue(); + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOldValue != bool(rValue) || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, CHART_UNONAME_LABEL , aOldValue ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL , uno::Any( aLabel ) ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any() ); + bChanged = true; + } + } + else if( bOldValue != bool(rValue) ) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_LABEL , uno::Any(aLabel)); + bChanged = true; + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: //fall through intended + { + bChanged = lcl_NumberFormatFromItemToPropertySet( nWhichId, rItemSet, GetPropertySet(), m_bOverwriteLabelsForAttributedDataPointsAlso ); + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: //fall through intended + { + bChanged = lcl_UseSourceFormatFromItemToPropertySet( nWhichId, rItemSet, GetPropertySet(), m_bOverwriteLabelsForAttributedDataPointsAlso ); + } + break; + + case SCHATTR_DATADESCR_SEPARATOR: + { + OUString aNewValue = static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue(); + try + { + OUString aOldValue; + GetPropertySet()->getPropertyValue( "LabelSeparator" ) >>= aOldValue; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( aOldValue != aNewValue || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "LabelSeparator" , uno::Any( aOldValue ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "LabelSeparator" , uno::Any( aNewValue ) ); + bChanged = true; + } + } + else if( aOldValue != aNewValue ) + { + GetPropertySet()->setPropertyValue( "LabelSeparator" , uno::Any( aNewValue )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_WRAP_TEXT: + { + + try + { + bool bNew = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOld = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bOld; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOld!=bNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "TextWordWrap", uno::Any( bOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "TextWordWrap", uno::Any( bNew ) ); + bChanged = true; + } + } + else if( bOld!=bNew ) + { + GetPropertySet()->setPropertyValue( "TextWordWrap", uno::Any( bNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_PLACEMENT: + { + + try + { + sal_Int32 nNew = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + sal_Int32 nOld = -1; + RelativePosition aCustomLabelPosition; + GetPropertySet()->getPropertyValue("LabelPlacement") >>= nOld; + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( nOld!=nNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "LabelPlacement" , uno::Any( nOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "LabelPlacement" , uno::Any( nNew ) ); + bChanged = true; + } + } + else if( nOld!=nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) ) + { + GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew)); + GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any()); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_STYLE_SYMBOL: + { + sal_Int32 nStyle = + static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + sal_Int32 nOldStyle = lcl_getSymbolStyleForSymbol( aSymbol ); + + if( nStyle != nOldStyle ) + { + bool bDeleteSymbol = false; + switch( nStyle ) + { + case SVX_SYMBOLTYPE_NONE: + aSymbol.Style = chart2::SymbolStyle_NONE; + break; + case SVX_SYMBOLTYPE_AUTO: + aSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case SVX_SYMBOLTYPE_BRUSHITEM: + aSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + case SVX_SYMBOLTYPE_UNKNOWN: + bDeleteSymbol = true; + break; + + default: + aSymbol.Style = chart2::SymbolStyle_STANDARD; + aSymbol.StandardSymbol = nStyle; + } + + if( bDeleteSymbol ) + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any()); + else + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + break; + + case SCHATTR_SYMBOL_SIZE: + { + Size aSize = static_cast< const SvxSizeItem & >( + rItemSet.Get( nWhichId )).GetSize(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + if( aSize.getWidth() != aSymbol.Size.Width || + aSize.getHeight() != aSymbol.Size.Height ) + { + aSymbol.Size.Width = aSize.getWidth(); + aSymbol.Size.Height = aSize.getHeight(); + + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + break; + + case SCHATTR_SYMBOL_BRUSH: + { + const SvxBrushItem & rBrshItem( static_cast< const SvxBrushItem & >( + rItemSet.Get( nWhichId ))); + uno::Any aXGraphicAny; + const Graphic *pGraphic( rBrshItem.GetGraphic()); + if( pGraphic ) + { + uno::Reference< graphic::XGraphic > xGraphic( pGraphic->GetXGraphic()); + if( xGraphic.is()) + { + aXGraphicAny <<= xGraphic; + chart2::Symbol aSymbol; + GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol; + if( aSymbol.Graphic != xGraphic ) + { + aSymbol.Graphic = xGraphic; + GetPropertySet()->setPropertyValue( "Symbol" , uno::Any( aSymbol )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fValue = toDegrees(rItemSet.Get(SCHATTR_TEXT_DEGREES).GetValue()); + double fOldValue = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldValue ); + + if( ! bPropExisted || fOldValue != fValue ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY: + { + bool bHideLegendEntry = static_cast(rItemSet.Get(nWhichId)).GetValue(); + if (bHideLegendEntry != m_bHideLegendEntry) + { + uno::Sequence deletedLegendEntriesSeq; + m_xSeries->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + std::vector deletedLegendEntries; + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (bHideLegendEntry || m_nPointIndex != deletedLegendEntry) + deletedLegendEntries.push_back(deletedLegendEntry); + } + if (bHideLegendEntry) + deletedLegendEntries.push_back(m_nPointIndex); + m_xSeries->setPropertyValue("DeletedLegendEntries", uno::Any(comphelper::containerToSequence(deletedLegendEntries))); + } + } + break; + + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bNew = static_cast(rItemSet.Get(nWhichId)).GetValue(); + bool bOld = true; + if( (m_xSeries->getPropertyValue("ShowCustomLeaderLines") >>= bOld) && bOld != bNew ) + { + m_xSeries->setPropertyValue("ShowCustomLeaderLines", uno::Any(bNew)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + } + + return bChanged; +} + +void DataPointItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + chart2::DataPointLabel aLabel; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel) + { + bool bValue = (nWhichId==SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId==SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol ))); + + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + + if( m_bOverwriteLabelsForAttributedDataPointsAlso ) + { + if( DataSeriesHelper::hasAttributedDataPointDifferentValue( + Reference< chart2::XDataSeries >( GetPropertySet(), uno::UNO_QUERY), CHART_UNONAME_LABEL , uno::Any(aLabel) ) ) + { + rOutItemSet.InvalidateItem(nWhichId); + } + } + } + } + break; + + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nKey)) + nKey = m_nNumberFormat; + rOutItemSet.Put( SfxUInt32Item( nWhichId, nKey )); + } + break; + + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if( !(GetPropertySet()->getPropertyValue( "PercentageNumberFormat" ) >>= nKey) ) + nKey = m_nPercentNumberFormat; + rOutItemSet.Put( SfxUInt32Item( nWhichId, nKey )); + } + break; + + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue() && !bUseSourceFormat; + rOutItemSet.Put( SfxBoolItem( nWhichId, ! bNumberFormatIsSet )); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue( "PercentageNumberFormat" ).hasValue() && !bUseSourceFormat; + rOutItemSet.Put( SfxBoolItem( nWhichId, ! bNumberFormatIsSet )); + } + break; + + case SCHATTR_DATADESCR_SEPARATOR: + { + try + { + OUString aValue; + GetPropertySet()->getPropertyValue( "LabelSeparator" ) >>= aValue; + rOutItemSet.Put( SfxStringItem( nWhichId, aValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_WRAP_TEXT: + { + try + { + bool bValue = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bValue; + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nPlacement=0; + RelativePosition aCustomLabelPosition; + if( !m_bOverwriteLabelsForAttributedDataPointsAlso && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) ) + rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM)); + else if( GetPropertySet()->getPropertyValue( "LabelPlacement" ) >>= nPlacement ) + rOutItemSet.Put( SfxInt32Item( nWhichId, nPlacement )); + else if( m_aAvailableLabelPlacements.hasElements() ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_aAvailableLabelPlacements[0] )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + + case SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS: + { + rOutItemSet.Put( SfxIntegerListItem( nWhichId, m_aAvailableLabelPlacements ) ); + } + break; + + case SCHATTR_DATADESCR_NO_PERCENTVALUE: + { + rOutItemSet.Put( SfxBoolItem( nWhichId, m_bForbidPercentValue )); + } + break; + + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bValue = true; + if( m_xSeries->getPropertyValue( "ShowCustomLeaderLines" ) >>= bValue ) + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + + case SCHATTR_STYLE_SYMBOL: + { + chart2::Symbol aSymbol; + if( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + rOutItemSet.Put( SfxInt32Item( nWhichId, lcl_getSymbolStyleForSymbol( aSymbol ) )); + } + break; + + case SCHATTR_SYMBOL_SIZE: + { + chart2::Symbol aSymbol; + if( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + rOutItemSet.Put( + SvxSizeItem( nWhichId, Size( aSymbol.Size.Width, aSymbol.Size.Height ) )); + } + break; + + case SCHATTR_SYMBOL_BRUSH: + { + chart2::Symbol aSymbol; + if(( GetPropertySet()->getPropertyValue( "Symbol" ) >>= aSymbol ) + && aSymbol.Graphic.is() ) + { + rOutItemSet.Put( SvxBrushItem( Graphic( aSymbol.Graphic ), GPOS_MM, SCHATTR_SYMBOL_BRUSH )); + } + } + break; + + case SCHATTR_TEXT_DEGREES: + { + double fValue = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fValue ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fValue * 100.0 ) ) ))); + } + } + break; + + case SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, m_bHideLegendEntry)); + break; + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx b/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx new file mode 100644 index 000000000..8e23902f6 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/ErrorBarItemConverter.cxx @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ + +void lcl_getErrorValues( const uno::Reference< beans::XPropertySet > & xErrorBarProp, + double & rOutPosError, double & rOutNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "PositiveError" ) >>= rOutPosError; + xErrorBarProp->getPropertyValue( "NegativeError" ) >>= rOutNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void lcl_getErrorIndicatorValues( + const uno::Reference< beans::XPropertySet > & xErrorBarProp, + bool & rOutShowPosError, bool & rOutShowNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "ShowPositiveError" ) >>= rOutShowPosError; + xErrorBarProp->getPropertyValue( "ShowNegativeError" ) >>= rOutShowNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +ErrorBarItemConverter::ErrorBarItemConverter( + const uno::Reference< frame::XModel > & xModel, + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) : + ItemConverter( rPropertySet, rItemPool ), + m_spGraphicConverter( std::make_shared( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineProperties )), + m_xModel( xModel ) +{} + +ErrorBarItemConverter::~ErrorBarItemConverter() +{} + +void ErrorBarItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + m_spGraphicConverter->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool ErrorBarItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = m_spGraphicConverter->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& ErrorBarItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nErrorBarWhichPairs; +} + +bool ErrorBarItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, + tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + return false; +} + +bool ErrorBarItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + // Attention !!! This case must be passed before SCHATTR_STAT_PERCENT, + // SCHATTR_STAT_BIGERROR, SCHATTR_STAT_CONSTPLUS, + // SCHATTR_STAT_CONSTMINUS and SCHATTR_STAT_INDICATE + case SCHATTR_STAT_KIND_ERROR: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + SvxChartKindError eErrorKind = + static_cast< const SvxChartKindErrorItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + if( !xErrorBarProp.is() && eErrorKind == SvxChartKindError::NONE) + { + //nothing to do + } + else + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + switch( eErrorKind ) + { + case SvxChartKindError::NONE: + nStyle = css::chart::ErrorBarStyle::NONE; break; + case SvxChartKindError::Variant: + nStyle = css::chart::ErrorBarStyle::VARIANCE; break; + case SvxChartKindError::Sigma: + nStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; break; + case SvxChartKindError::Percent: + nStyle = css::chart::ErrorBarStyle::RELATIVE; break; + case SvxChartKindError::BigError: + nStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; break; + case SvxChartKindError::Const: + nStyle = css::chart::ErrorBarStyle::ABSOLUTE; break; + case SvxChartKindError::StdError: + nStyle = css::chart::ErrorBarStyle::STANDARD_ERROR; break; + case SvxChartKindError::Range: + nStyle = css::chart::ErrorBarStyle::FROM_DATA; break; + } + + xErrorBarProp->setPropertyValue( "ErrorBarStyle" , uno::Any( nStyle )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_PERCENT: + case SCHATTR_STAT_BIGERROR: + { + OSL_FAIL( "Deprecated item" ); + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( ! ( ::rtl::math::approxEqual( fPos, fValue ) && + ::rtl::math::approxEqual( fNeg, fValue ))) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + + if( ! ::rtl::math::approxEqual( fPos, fValue )) + { + GetPropertySet()->setPropertyValue( "PositiveError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( ! ::rtl::math::approxEqual( fNeg, fValue )) + { + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_INDICATE: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + SvxChartIndicate eIndicate = + static_cast< const SvxChartIndicateItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + bool bNewIndPos = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Up ); + bool bNewIndNeg = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Down ); + + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bShowPos != bNewIndPos || + bShowNeg != bNewIndNeg ) + { + xErrorBarProp->setPropertyValue( "ShowPositiveError" , uno::Any( bNewIndPos )); + xErrorBarProp->setPropertyValue( "ShowNegativeError" , uno::Any( bNewIndNeg )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + // @todo: also be able to deal with x-error bars + const bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xChartDoc( m_xModel, uno::UNO_QUERY ); + uno::Reference< chart2::data::XDataProvider > xDataProvider; + + if( xChartDoc.is()) + xDataProvider.set( xChartDoc->getDataProvider()); + if( xErrorBarSource.is() && xDataProvider.is()) + { + OUString aNewRange( static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue()); + bool bApplyNewRange = false; + + bool bIsPositiveValue( nWhichId == SCHATTR_STAT_RANGE_POS ); + if( xChartDoc->hasInternalDataProvider()) + { + if( !aNewRange.isEmpty()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + if( ! xSeq.is()) + { + // no data range for error bars yet => create + uno::Reference< chart2::XInternalDataProvider > xIntDataProvider( xDataProvider, uno::UNO_QUERY ); + OSL_ASSERT( xIntDataProvider.is()); + if( xIntDataProvider.is()) + { + xIntDataProvider->appendSequence(); + aNewRange = "last"; + bApplyNewRange = true; + } + } + } + } + else + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + bApplyNewRange = + ! ( xSeq.is() && (aNewRange == xSeq->getSourceRangeRepresentation())); + } + + if( bApplyNewRange ) + StatisticsHelper::setErrorDataSequence( + xErrorBarSource, xDataProvider, aNewRange, bIsPositiveValue, bYError ); + } + } + break; + } + + return bChanged; +} + +void ErrorBarItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_STAT_KIND_ERROR: + { + SvxChartKindError eErrorKind = SvxChartKindError::NONE; + uno::Reference< beans::XPropertySet > xErrorBarProp( GetPropertySet()); + + sal_Int32 nStyle = 0; + if( xErrorBarProp->getPropertyValue( "ErrorBarStyle" ) >>= nStyle ) + { + switch( nStyle ) + { + case css::chart::ErrorBarStyle::NONE: + break; + case css::chart::ErrorBarStyle::VARIANCE: + eErrorKind = SvxChartKindError::Variant; break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + eErrorKind = SvxChartKindError::Sigma; break; + case css::chart::ErrorBarStyle::ABSOLUTE: + eErrorKind = SvxChartKindError::Const; break; + case css::chart::ErrorBarStyle::RELATIVE: + eErrorKind = SvxChartKindError::Percent; break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + eErrorKind = SvxChartKindError::BigError; break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + eErrorKind = SvxChartKindError::StdError; break; + case css::chart::ErrorBarStyle::FROM_DATA: + eErrorKind = SvxChartKindError::Range; break; + } + } + rOutItemSet.Put( SvxChartKindErrorItem( eErrorKind, SCHATTR_STAT_KIND_ERROR )); + } + break; + + case SCHATTR_STAT_PERCENT: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_PERCENT )); + } + break; + + case SCHATTR_STAT_BIGERROR: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_BIGERROR )); + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fPos, SCHATTR_STAT_CONSTPLUS )); + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( GetPropertySet(), fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fNeg, SCHATTR_STAT_CONSTMINUS )); + } + break; + + case SCHATTR_STAT_INDICATE: + { + SvxChartIndicate eIndicate = SvxChartIndicate::Both; + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( GetPropertySet(), bShowPos, bShowNeg ); + + if( bShowPos ) + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Both; + else + eIndicate = SvxChartIndicate::Up; + } + else + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Down; + else + eIndicate = SvxChartIndicate::NONE; + } + rOutItemSet.Put( SvxChartIndicateItem( eIndicate, SCHATTR_STAT_INDICATE )); + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + const bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< chart2::data::XDataSource > xErrorBarSource( GetPropertySet(), uno::UNO_QUERY ); + if( xErrorBarSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, (nWhichId == SCHATTR_STAT_RANGE_POS), bYError )); + if( xSeq.is()) + rOutItemSet.Put( SfxStringItem( nWhichId, xSeq->getSourceRangeRepresentation())); + } + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx new file mode 100644 index 000000000..e265e4198 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx @@ -0,0 +1,751 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetDataPointFilledPropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyFilledMap{ + {XATTR_FILLSTYLE, {"FillStyle", 0}}, + {XATTR_FILLCOLOR, {"Color", 0}}, + {XATTR_LINECOLOR, {"BorderColor", 0}}, + {XATTR_LINESTYLE, {"BorderStyle", 0}}, + {XATTR_LINEWIDTH, {"BorderWidth", 0}}, + {XATTR_FILLBACKGROUND, {"FillBackground", 0}}, + {XATTR_FILLBMP_POS, {"FillBitmapRectanglePoint", 0}}, + {XATTR_FILLBMP_SIZEX, {"FillBitmapSizeX", 0}}, + {XATTR_FILLBMP_SIZEY, {"FillBitmapSizeY", 0}}, + {XATTR_FILLBMP_SIZELOG, {"FillBitmapLogicalSize", 0}}, + {XATTR_FILLBMP_TILEOFFSETX, {"FillBitmapOffsetX", 0}}, + {XATTR_FILLBMP_TILEOFFSETY, {"FillBitmapOffsetY", 0}}, + {XATTR_FILLBMP_POSOFFSETX, {"FillBitmapPositionOffsetX", 0}}, + {XATTR_FILLBMP_POSOFFSETY, {"FillBitmapPositionOffsetY", 0}}}; + return aDataPointPropertyFilledMap; +} +ItemPropertyMapType & lcl_GetDataPointLinePropertyMap() +{ + static ItemPropertyMapType aDataPointPropertyLineMap{ + {XATTR_LINECOLOR, {"Color", 0}}, + {XATTR_LINESTYLE, {"LineStyle", 0}}, + {XATTR_LINEWIDTH, {"LineWidth", 0}}, + {XATTR_LINECAP, {"LineCap", 0}}}; + return aDataPointPropertyLineMap; +} +ItemPropertyMapType & lcl_GetLinePropertyMap() +{ + static ItemPropertyMapType aLinePropertyMap{ + {XATTR_LINESTYLE, {"LineStyle", 0}}, + {XATTR_LINEWIDTH, {"LineWidth", 0}}, + {XATTR_LINECOLOR, {"LineColor", 0}}, + {XATTR_LINEJOINT, {"LineJoint", 0}}, + {XATTR_LINECAP, {"LineCap", 0}}}; + return aLinePropertyMap; +} +ItemPropertyMapType & lcl_GetFillPropertyMap() +{ + static ItemPropertyMapType aFillPropertyMap{ + {XATTR_FILLSTYLE, {"FillStyle", 0}}, + {XATTR_FILLCOLOR, {"FillColor", 0}}, + {XATTR_FILLBACKGROUND, {"FillBackground", 0}}, + {XATTR_FILLBMP_POS, {"FillBitmapRectanglePoint", 0}}, + {XATTR_FILLBMP_SIZEX, {"FillBitmapSizeX", 0}}, + {XATTR_FILLBMP_SIZEY, {"FillBitmapSizeY", 0}}, + {XATTR_FILLBMP_SIZELOG, {"FillBitmapLogicalSize", 0}}, + {XATTR_FILLBMP_TILEOFFSETX, {"FillBitmapOffsetX", 0}}, + {XATTR_FILLBMP_TILEOFFSETY, {"FillBitmapOffsetY", 0}}, + {XATTR_FILLBMP_POSOFFSETX, {"FillBitmapPositionOffsetX", 0}}, + {XATTR_FILLBMP_POSOFFSETY, {"FillBitmapPositionOffsetY", 0}}}; + return aFillPropertyMap; +} + +bool lcl_supportsFillProperties( ::chart::wrapper::GraphicObjectType eType ) +{ + return ( eType == ::chart::wrapper::GraphicObjectType::FilledDataPoint || + eType == ::chart::wrapper::GraphicObjectType::LineAndFillProperties ); +} + +bool lcl_SetContentForNamedProperty( + const uno::Reference< lang::XMultiServiceFactory > & xFactory, + const OUString & rTableName, + NameOrIndex & rItem, sal_uInt8 nMemberId ) +{ + bool bResult = false; + if( xFactory.is()) + { + OUString aPropertyValue( rItem.GetName()); + uno::Reference< container::XNameAccess > xNameAcc( + xFactory->createInstance( rTableName ), + uno::UNO_QUERY ); + if( xNameAcc.is() && + xNameAcc->hasByName( aPropertyValue )) + { + rItem.PutValue( xNameAcc->getByName( aPropertyValue ), nMemberId ); + bResult = true; + } + } + return bResult; +} + +} // anonymous namespace + +GraphicPropertyItemConverter::GraphicPropertyItemConverter( + const uno::Reference< + beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + GraphicObjectType eObjectType /* = FILL_PROPERTIES */ ) : + ItemConverter( rPropertySet, rItemPool ), + m_GraphicObjectType( eObjectType ), + m_rDrawModel( rDrawModel ), + m_xNamedPropertyTableFactory( xNamedPropertyContainerFactory ) +{} + +GraphicPropertyItemConverter::~GraphicPropertyItemConverter() +{} + +const WhichRangesContainer& GraphicPropertyItemConverter::GetWhichPairs() const +{ + switch( m_GraphicObjectType ) + { + case GraphicObjectType::LineDataPoint: + case GraphicObjectType::FilledDataPoint: + return nRowWhichPairs; + case GraphicObjectType::LineProperties: + return nLinePropertyWhichPairs; + case GraphicObjectType::LineAndFillProperties: + return nLineAndFillPropertyWhichPairs; + } + + static const WhichRangesContainer empty; + return empty; +} + +bool GraphicPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType::const_iterator aEndIt; + ItemPropertyMapType::const_iterator aIt; + + switch( m_GraphicObjectType ) + { + case GraphicObjectType::LineDataPoint: + aEndIt = lcl_GetDataPointLinePropertyMap().end(); + aIt = lcl_GetDataPointLinePropertyMap().find( nWhichId ); + break; + case GraphicObjectType::FilledDataPoint: + aEndIt = lcl_GetDataPointFilledPropertyMap().end(); + aIt = lcl_GetDataPointFilledPropertyMap().find( nWhichId ); + break; + case GraphicObjectType::LineProperties: + aEndIt = lcl_GetLinePropertyMap().end(); + aIt = lcl_GetLinePropertyMap().find( nWhichId ); + break; + + case GraphicObjectType::LineAndFillProperties: + // line + aEndIt = lcl_GetLinePropertyMap().end(); + aIt = lcl_GetLinePropertyMap().find( nWhichId ); + + // not found => try fill + if( aIt == aEndIt ) + { + aEndIt = lcl_GetFillPropertyMap().end(); + aIt = lcl_GetFillPropertyMap().find( nWhichId ); + } + break; + } + + if( aIt == aEndIt ) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +void GraphicPropertyItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + // bitmap property + case XATTR_FILLBMP_TILE: + case XATTR_FILLBMP_STRETCH: + { + drawing::BitmapMode aMode = drawing::BitmapMode_REPEAT; + if( GetPropertySet()->getPropertyValue( "FillBitmapMode" ) >>= aMode ) + { + rOutItemSet.Put( XFillBmpTileItem( aMode == drawing::BitmapMode_REPEAT )); + rOutItemSet.Put( XFillBmpStretchItem( aMode == drawing::BitmapMode_STRETCH )); + } + } + break; + + case XATTR_FILLFLOATTRANSPARENCE: + try + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( aPropName )); + if( aValue.hasValue()) + { + XFillFloatTransparenceItem aItem; + aItem.PutValue( aValue, MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.TransparencyGradientTable" , + aItem, MID_FILLGRADIENT ); + + // this is important to enable the item + OUString aName; + if( (aValue >>= aName) && + !aName.isEmpty()) + { + aItem.SetEnabled( true ); + rOutItemSet.Put( aItem ); + } + } + } + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + break; + + case XATTR_GRADIENTSTEPCOUNT: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientStepCount" ) + : OUString( "FillGradientStepCount" ); + + uno::Any aValue( GetPropertySet()->getPropertyValue( aPropName ) ); + if( hasLongOrShortValue(aValue) ) + { + sal_Int16 nStepCount = getShortForLongAlso(aValue); + rOutItemSet.Put( XGradientStepCountItem( nStepCount )); + } + } + break; + + case XATTR_LINEDASH: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderDashName" ) + : OUString( "LineDashName" ); + + XLineDashItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.DashTable" , + aItem, MID_LINEDASH ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLGRADIENT: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientName" ) + : OUString( "FillGradientName" ); + + XFillGradientItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.GradientTable" , + aItem, MID_FILLGRADIENT ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put(std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLHATCH: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "HatchName" ) + : OUString( "FillHatchName" ); + + XFillHatchItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.HatchTable" , + aItem, MID_FILLHATCH ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + case XATTR_FILLBITMAP: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + XFillBitmapItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( "FillBitmapName" ), MID_NAME ); + + lcl_SetContentForNamedProperty( + m_xNamedPropertyTableFactory, "com.sun.star.drawing.BitmapTable" , + aItem, MID_BITMAP ); + + // translate model name to UI-name for predefined entries, so + // that the correct entry is chosen in the list of UI-names + std::unique_ptr pItemToPut = aItem.checkForUniqueItem( & m_rDrawModel ); + + if(pItemToPut) + rOutItemSet.Put( std::move(pItemToPut) ); + else + rOutItemSet.Put(aItem); + } + break; + + // hack, because QueryValue of XLineTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_LINETRANSPARENCE: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderTransparency" ) + : (m_GraphicObjectType == GraphicObjectType::LineDataPoint) + ? OUString( "Transparency" ) + : OUString( "LineTransparence" ); + + XLineTransparenceItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), 0 ); + + rOutItemSet.Put( aItem ); + } + break; + + // hack, because QueryValue of XFillTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_FILLTRANSPARENCE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "Transparency" ) + : OUString( "FillTransparence" ); + + XFillTransparenceItem aItem; + aItem.PutValue( GetPropertySet()->getPropertyValue( aPropName ), 0 ); + + rOutItemSet.Put( aItem ); + } + break; + } +} + +bool GraphicPropertyItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + uno::Any aValue; + + switch( nWhichId ) + { + // bitmap property + case XATTR_FILLBMP_STRETCH: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + static const OUStringLiteral aModePropName(u"FillBitmapMode"); + bool bStretched = rItemSet.Get( XATTR_FILLBMP_STRETCH ).GetValue(); + drawing::BitmapMode aMode = + (bStretched ? drawing::BitmapMode_STRETCH : drawing::BitmapMode_NO_REPEAT); + drawing::BitmapMode aOtherMode = drawing::BitmapMode_NO_REPEAT; + + aValue <<= aMode; + GetPropertySet()->getPropertyValue( aModePropName ) >>= aOtherMode; + + // don't overwrite if it has been set to BitmapMode_REPEAT (= tiled) already + // XATTR_FILLBMP_STRETCH and XATTR_FILLBMP_TILE often come in pairs, tdf#104658 + if( aMode != aOtherMode && aOtherMode != drawing::BitmapMode_REPEAT ) + { + GetPropertySet()->setPropertyValue( aModePropName, aValue ); + bChanged = true; + } + } + break; + + case XATTR_FILLBMP_TILE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + static const OUStringLiteral aModePropName(u"FillBitmapMode"); + bool bTiled = rItemSet.Get( XATTR_FILLBMP_TILE ).GetValue(); + drawing::BitmapMode aMode = + (bTiled ? drawing::BitmapMode_REPEAT : drawing::BitmapMode_NO_REPEAT); + + aValue <<= aMode; + if( aValue != GetPropertySet()->getPropertyValue( aModePropName )) + { + GetPropertySet()->setPropertyValue( aModePropName, aValue ); + bChanged = true; + } + } + break; + + case XATTR_FILLFLOATTRANSPARENCE: + try + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + + const XFillFloatTransparenceItem & rItem = + static_cast< const XFillFloatTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.IsEnabled() && + rItem.QueryValue( aValue, MID_NAME )) + { + uno::Any aGradient; + rItem.QueryValue( aGradient, MID_FILLGRADIENT ); + + // add TransparencyGradient to list if it does not already exist + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addTransparencyGradientUniqueNameToTable( + aGradient, m_xNamedPropertyTableFactory, aPreferredName ); + + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + else + { + OUString aName; + if( ( GetPropertySet()->getPropertyValue( aPropName ) >>= aName ) + && !aName.isEmpty() ) + { + uno::Reference< beans::XPropertyState > xState( GetPropertySet(), uno::UNO_QUERY ); + if( xState.is()) + xState->setPropertyToDefault( aPropName ); + bChanged = true; + } + } + } + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + break; + + case XATTR_GRADIENTSTEPCOUNT: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientStepCount" ) + : OUString( "FillGradientStepCount" ); + + sal_Int16 nStepCount = static_cast< const XGradientStepCountItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + aValue <<= nStepCount; + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + break; + + case XATTR_LINEDASH: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderDashName" ) + : OUString( "LineDashName" ); + + const XLineDashItem & rItem = + static_cast< const XLineDashItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add LineDash to list + uno::Any aLineDash; + rItem.QueryValue( aLineDash, MID_LINEDASH ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addLineDashUniqueNameToTable( + aLineDash, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + break; + + case XATTR_FILLGRADIENT: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "GradientName" ) + : OUString( "FillGradientName" ); + + const XFillGradientItem & rItem = + static_cast< const XFillGradientItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add Gradient to list + uno::Any aGradient; + rItem.QueryValue( aGradient, MID_FILLGRADIENT ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addGradientUniqueNameToTable( + aGradient, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + } + break; + + case XATTR_FILLHATCH: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "HatchName" ) + : OUString( "FillHatchName" ); + + const XFillHatchItem & rItem = + static_cast< const XFillHatchItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( aPropName )) + { + // add Hatch to list + uno::Any aHatch; + rItem.QueryValue( aHatch, MID_FILLHATCH ); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addHatchUniqueNameToTable( + aHatch, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + } + } + } + break; + + case XATTR_FILLBITMAP: + { + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + const XFillBitmapItem & rItem = + static_cast< const XFillBitmapItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue, MID_NAME )) + { + if( aValue != GetPropertySet()->getPropertyValue( "FillBitmapName" )) + { + // add Bitmap to list + uno::Any aBitmap; + rItem.QueryValue(aBitmap, MID_BITMAP); + OUString aPreferredName; + aValue >>= aPreferredName; + aValue <<= PropertyHelper::addBitmapUniqueNameToTable( + aBitmap, m_xNamedPropertyTableFactory, aPreferredName ); + + GetPropertySet()->setPropertyValue( "FillBitmapName" , aValue ); + bChanged = true; + } + } + } + } + break; + + // hack, because QueryValue of XLineTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_LINETRANSPARENCE: + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "BorderTransparency" ) + : (m_GraphicObjectType == GraphicObjectType::LineDataPoint) + ? OUString( "Transparency" ) + : OUString( "LineTransparence" ); + + const XLineTransparenceItem & rItem = + static_cast< const XLineTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue )) + { + OSL_ENSURE( ! aValue.isExtractableTo( + cppu::UnoType::get()), + "TransparenceItem QueryValue bug is fixed. Remove hack." ); + sal_Int32 nValue = 0; + if( aValue >>= nValue ) + { + OSL_ENSURE( nValue < SAL_MAX_INT16, "Transparency value too large" ); + sal_Int16 nValueToSet( static_cast< sal_Int16 >( nValue )); + aValue <<= nValueToSet; + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + bChanged = true; + } + else + { + OSL_FAIL( "Wrong type in Transparency Any" ); + } + } + } + break; + + // hack, because QueryValue of XFillTransparenceItem returns sal_Int32 + // instead of sal_Int16 + case XATTR_FILLTRANSPARENCE: + if( lcl_supportsFillProperties( m_GraphicObjectType )) + { + OUString aPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "Transparency" ) + : OUString( "FillTransparence" ); + + const XFillTransparenceItem & rItem = + static_cast< const XFillTransparenceItem & >( + rItemSet.Get( nWhichId )); + + if( rItem.QueryValue( aValue )) + { + OSL_ENSURE( ! aValue.isExtractableTo( + cppu::UnoType::get()), + "TransparenceItem QueryValue bug is fixed. Remove hack." ); + sal_Int32 nValue = 0; + if( aValue >>= nValue ) + { + OSL_ENSURE( nValue < SAL_MAX_INT16, "Transparency value too large" ); + sal_Int16 nValueToSet( static_cast< sal_Int16 >( nValue )); + aValue <<= nValueToSet; + + GetPropertySet()->setPropertyValue( aPropName, aValue ); + // if linear or no transparence is set, delete the gradient + OUString aTransGradPropName = + (m_GraphicObjectType == GraphicObjectType::FilledDataPoint) + ? OUString( "TransparencyGradientName" ) + : OUString( "FillTransparenceGradientName" ); + GetPropertySet()->setPropertyValue( + aTransGradPropName, uno::Any( OUString() )); + + bChanged = true; + } + else + { + OSL_FAIL( "Wrong type in Transparency Any" ); + } + } + } + break; + } + + return bChanged; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/ItemConverter.cxx b/chart2/source/controller/itemsetwrapper/ItemConverter.cxx new file mode 100644 index 000000000..d79079b77 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/ItemConverter.cxx @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +ItemConverter::ItemConverter( + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + m_xPropertySet( rPropertySet ), + m_rItemPool( rItemPool ) +{ + resetPropertySet( m_xPropertySet ); +} + +ItemConverter::~ItemConverter() +{ + stopAllComponentListening(); +} + +void ItemConverter::resetPropertySet( + const uno::Reference< beans::XPropertySet > & xPropSet ) +{ + if( !xPropSet.is()) + return; + + stopAllComponentListening(); + m_xPropertySet = xPropSet; + m_xPropertySetInfo = m_xPropertySet->getPropertySetInfo(); + + uno::Reference< lang::XComponent > xComp( m_xPropertySet, uno::UNO_QUERY ); + if( xComp.is()) + { + // method of base class ::utl::OEventListenerAdapter + startComponentListening( xComp ); + } +} + +SfxItemSet ItemConverter::CreateEmptyItemSet() const +{ + return SfxItemSet( GetItemPool(), GetWhichPairs() ); +} + +void ItemConverter::_disposing( const lang::EventObject& ) +{ +} + +void ItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + const WhichRangesContainer& pRanges = rOutItemSet.GetRanges(); + tPropertyNameWithMemberId aProperty; + SfxItemPool & rPool = GetItemPool(); + + assert(!pRanges.empty()); + OSL_ASSERT( m_xPropertySetInfo.is()); + OSL_ASSERT( m_xPropertySet.is()); + + for(const auto& rPair : pRanges) + { + sal_uInt16 nBeg = rPair.first; + sal_uInt16 nEnd = rPair.second; + + OSL_ASSERT( nBeg <= nEnd ); + for( sal_uInt16 nWhich = nBeg; nWhich <= nEnd; ++nWhich ) + { + if( GetItemProperty( nWhich, aProperty )) + { + // put the Property into the itemset + std::unique_ptr pItem(rPool.GetDefaultItem( nWhich ).Clone()); + + if( pItem ) + { + try + { + if( pItem->PutValue( m_xPropertySet->getPropertyValue( aProperty.first ), + aProperty.second // nMemberId + )) + { + pItem->SetWhich(nWhich); + rOutItemSet.Put( std::move(pItem) ); + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "unknown Property: " << aProperty.first); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + else + { + try + { + FillSpecialItem( nWhich, rOutItemSet ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } +} + +void ItemConverter::FillSpecialItem( + sal_uInt16 /*nWhichId*/, SfxItemSet & /*rOutItemSet*/ ) const +{ + OSL_FAIL( "ItemConverter: Unhandled special item found!" ); +} + +bool ItemConverter::ApplySpecialItem( + sal_uInt16 /*nWhichId*/, const SfxItemSet & /*rItemSet*/ ) +{ + OSL_FAIL( "ItemConverter: Unhandled special item found!" ); + return false; +} + +bool ItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + OSL_ASSERT( m_xPropertySet.is()); + + bool bItemsChanged = false; + SfxItemIter aIter( rItemSet ); + tPropertyNameWithMemberId aProperty; + uno::Any aValue; + + for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem()) + { + if( aIter.GetItemState( false ) == SfxItemState::SET ) + { + if( GetItemProperty( pItem->Which(), aProperty )) + { + pItem->QueryValue( aValue, aProperty.second /* nMemberId */ ); + + try + { + if( aValue != m_xPropertySet->getPropertyValue( aProperty.first )) + { + m_xPropertySet->setPropertyValue( aProperty.first, aValue ); + bItemsChanged = true; + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "unknown Property: " << aProperty.first); + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION( "chart2", "" ); + } + } + else + { + bItemsChanged = ApplySpecialItem( pItem->Which(), rItemSet ) || bItemsChanged; + } + } + } + + return bItemsChanged; +} + +void ItemConverter::InvalidateUnequalItems( SfxItemSet &rDestSet, const SfxItemSet &rSourceSet ) +{ + SfxWhichIter aIter (rSourceSet); + sal_uInt16 nWhich = aIter.FirstWhich (); + const SfxPoolItem *pPoolItem = nullptr; + + while (nWhich) + { + SfxItemState nSourceItemState = aIter.GetItemState(true, &pPoolItem); + if ((nSourceItemState == SfxItemState::SET) && + (rDestSet.GetItemState(nWhich, true, &pPoolItem) == SfxItemState::SET)) + { + if (rSourceSet.Get(nWhich) != rDestSet.Get(nWhich)) + { + if( nWhich != SID_CHAR_DLG_PREVIEW_STRING ) + { + rDestSet.InvalidateItem(nWhich); + } + } + } + else if( nSourceItemState == SfxItemState::DONTCARE ) + rDestSet.InvalidateItem(nWhich); + + nWhich = aIter.NextWhich (); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx b/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx new file mode 100644 index 000000000..7a8dab188 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/LegendItemConverter.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper +{ + +LegendItemConverter::LegendItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + m_aConverters.emplace_back( new CharacterPropertyItemConverter( + rPropertySet, rItemPool, pRefSize, + "ReferencePageSize" )); +} + +LegendItemConverter::~LegendItemConverter() +{ +} + +void LegendItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool LegendItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& LegendItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nLegendWhichPairs; +} + +bool LegendItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + // No own (non-special) properties + return false; +} + +bool LegendItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet& rInItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_LEGEND_SHOW: + { + if( const SfxBoolItem* pShowItem = rInItemSet.GetItemIfSet( SCHATTR_LEGEND_SHOW ) ) + { + bool bShow = pShowItem->GetValue(); + bool bWasShown = true; + if( ! (GetPropertySet()->getPropertyValue( "Show" ) >>= bWasShown) || + ( bWasShown != bShow )) + { + GetPropertySet()->setPropertyValue( "Show" , uno::Any( bShow )); + bChanged = true; + } + } + + } + break; + case SCHATTR_LEGEND_POS: + { + if( const SfxInt32Item* pPosItem = rInItemSet.GetItemIfSet( SCHATTR_LEGEND_POS ) ) + { + chart2::LegendPosition eNewPos = static_cast(pPosItem->GetValue()); + + css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH; + switch( eNewPos ) + { + case chart2::LegendPosition_LINE_START: + case chart2::LegendPosition_LINE_END: + eExpansion = css::chart::ChartLegendExpansion_HIGH; + break; + case chart2::LegendPosition_PAGE_START: + case chart2::LegendPosition_PAGE_END: + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + default: + break; + } + + try + { + chart2::LegendPosition eOldPos; + if( ! ( GetPropertySet()->getPropertyValue( "AnchorPosition" ) >>= eOldPos ) || + ( eOldPos != eNewPos )) + { + GetPropertySet()->setPropertyValue( "AnchorPosition" , uno::Any( eNewPos )); + GetPropertySet()->setPropertyValue( "Expansion" , uno::Any( eExpansion )); + GetPropertySet()->setPropertyValue( "RelativePosition" , uno::Any()); + bChanged = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + break; + case SCHATTR_LEGEND_NO_OVERLAY: + { + if(const SfxBoolItem* pNoOverlayItem = rInItemSet.GetItemIfSet(SCHATTR_LEGEND_NO_OVERLAY)) + { + bool bOverlay = !pNoOverlayItem->GetValue(); + bool bOldOverlay = false; + if(!(GetPropertySet()->getPropertyValue("Overlay") >>= bOldOverlay) || + (bOldOverlay != bOverlay)) + { + GetPropertySet()->setPropertyValue("Overlay", uno::Any(bOverlay)); + bChanged = true; + } + } + + } + break; + } + + return bChanged; +} + +void LegendItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_LEGEND_SHOW: + { + bool bShow = true; + GetPropertySet()->getPropertyValue( "Show" ) >>= bShow; + rOutItemSet.Put( SfxBoolItem(SCHATTR_LEGEND_SHOW, bShow) ); + } + break; + case SCHATTR_LEGEND_POS: + { + chart2::LegendPosition eLegendPos( chart2::LegendPosition_LINE_END ); + GetPropertySet()->getPropertyValue( "AnchorPosition" ) >>= eLegendPos; + rOutItemSet.Put( SfxInt32Item(SCHATTR_LEGEND_POS, static_cast(eLegendPos) ) ); + } + break; + case SCHATTR_LEGEND_NO_OVERLAY: + { + bool bOverlay = false; + GetPropertySet()->getPropertyValue("Overlay") >>= bOverlay; + rOutItemSet.Put(SfxBoolItem(SCHATTR_LEGEND_NO_OVERLAY, !bOverlay)); + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx b/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx new file mode 100644 index 000000000..5f460be98 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/MultipleChartConverters.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart::wrapper { + +AllAxisItemConverter::AllAxisItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const awt::Size* pRefSize ) + : MultipleItemConverter( rItemPool ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + const std::vector< rtl::Reference< Axis > > aElementList = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aElementList ) + { + uno::Reference< beans::XPropertySet > xObjectProperties(axis); + m_aConverters.emplace_back( new ::chart::wrapper::AxisItemConverter( + xObjectProperties, rItemPool, rDrawModel, + xChartModel, nullptr, nullptr, + pRefSize)); + } +} + +AllAxisItemConverter::~AllAxisItemConverter() +{ +} + +const WhichRangesContainer& AllAxisItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nAllAxisWhichPairs; +} + +AllGridItemConverter::AllGridItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + const Sequence< Reference< beans::XPropertySet > > aElementList( AxisHelper::getAllGrids( xDiagram ) ); + for( Reference< beans::XPropertySet > const & xObjectProperties : aElementList ) + { + m_aConverters.emplace_back( new ::chart::wrapper::GraphicPropertyItemConverter( + xObjectProperties, rItemPool, rDrawModel, xNamedPropertyContainerFactory, + ::chart::wrapper::GraphicObjectType::LineProperties ) ); + } +} + +AllGridItemConverter::~AllGridItemConverter() +{ +} + +const WhichRangesContainer& AllGridItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nGridWhichPairs; +} + +AllDataLabelItemConverter::AllDataLabelItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::ChartModelHelper::getDataSeries( xChartModel ); + + for (auto const& series : aSeriesList) + { + uno::Reference< uno::XComponentContext> xContext;//do not need Context for label properties + + sal_Int32 nNumberFormat=ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( series ); + sal_Int32 nPercentNumberFormat=ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + series,xChartModel); + + m_aConverters.emplace_back( + new ::chart::wrapper::DataPointItemConverter( + xChartModel, xContext, series, series, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, GraphicObjectType::FilledDataPoint, + nullptr, true, false, 0, true, nNumberFormat, nPercentNumberFormat)); + } +} + +AllDataLabelItemConverter::~AllDataLabelItemConverter() +{ +} + +const WhichRangesContainer& AllDataLabelItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nDataLabelWhichPairs; +} + +AllTitleItemConverter::AllTitleItemConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) + : MultipleItemConverter( rItemPool ) +{ + for(sal_Int32 nTitle = TitleHelper::TITLE_BEGIN; nTitle < TitleHelper::NORMAL_TITLE_END; nTitle++ ) + { + uno::Reference< chart2::XTitle > xTitle( TitleHelper::getTitle( TitleHelper::eTitleType(nTitle), xChartModel ) ); + if(!xTitle.is()) + continue; + uno::Reference< beans::XPropertySet > xObjectProperties( xTitle, uno::UNO_QUERY); + m_aConverters.emplace_back( + new ::chart::wrapper::TitleItemConverter( + xObjectProperties, rItemPool, rDrawModel, xNamedPropertyContainerFactory, nullptr)); + } +} + +AllTitleItemConverter::~AllTitleItemConverter() +{ +} + +const WhichRangesContainer& AllTitleItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTitleWhichPairs; +} + +AllSeriesStatisticsConverter::AllSeriesStatisticsConverter( + const rtl::Reference<::chart::ChartModel> & xChartModel, + SfxItemPool& rItemPool ) + : MultipleItemConverter( rItemPool ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesList = + ::chart::ChartModelHelper::getDataSeries( xChartModel ); + + for (auto const& series : aSeriesList) + { + m_aConverters.emplace_back( new ::chart::wrapper::StatisticsItemConverter( + xChartModel, series, rItemPool )); + } +} + +AllSeriesStatisticsConverter::~AllSeriesStatisticsConverter() +{} + +const WhichRangesContainer& AllSeriesStatisticsConverter::GetWhichPairs() const +{ + // must span all used items! + return nStatWhichPairs; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx b/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx new file mode 100644 index 000000000..5937575cc --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/MultipleItemConverter.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +MultipleItemConverter::MultipleItemConverter( SfxItemPool& rItemPool ) + : ItemConverter( nullptr, rItemPool ) +{ +} +MultipleItemConverter::~MultipleItemConverter() +{ +} + +void MultipleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + auto aIter = m_aConverters.begin(); + auto aEnd = m_aConverters.end(); + if( aIter != aEnd ) + { + (*aIter)->FillItemSet( rOutItemSet ); + ++aIter; + } + for( ; aIter != aEnd; ++aIter ) + { + SfxItemSet aSet = CreateEmptyItemSet(); + (*aIter)->FillItemSet( aSet ); + InvalidateUnequalItems( rOutItemSet, aSet ); + } + // no own items +} + +bool MultipleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // no own items + return bResult; +} + +bool MultipleItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx new file mode 100644 index 000000000..5683b468c --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx @@ -0,0 +1,350 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "SchWhichPairs.hxx" +#include +#include + +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +template +bool lclConvertToPropertySet(const SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast(static_cast(rItemSet.Get( nWhichId )).GetValue()); + T aOldValue = aValue; + bool aSuccess = xProperties->getPropertyValue( aPropertyID ) >>= aOldValue; + if (!aSuccess || aOldValue != aValue) + { + xProperties->setPropertyValue( aPropertyID , uno::Any( aValue )); + return true; + } + } + return false; +} + +template +void lclConvertToItemSet(SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast(static_cast(rItemSet.Get( nWhichId )).GetValue()); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(D( nWhichId, aValue )); + } + } +} + +void lclConvertToItemSetDouble(SfxItemSet& rItemSet, TypedWhichId nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + double aValue = rItemSet.Get( nWhichId ).GetValue(); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(SvxDoubleItem( aValue, nWhichId )); + } + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +RegressionCurveItemConverter::RegressionCurveItemConverter( + const uno::Reference< beans::XPropertySet >& rPropertySet, + const rtl::Reference< DataSeries >& xContainer, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory ) : + ItemConverter( rPropertySet, rItemPool ), + m_spGraphicConverter( std::make_shared( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineProperties )), + m_xCurveContainer( xContainer ) +{} + +RegressionCurveItemConverter::~RegressionCurveItemConverter() +{} + +void RegressionCurveItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + m_spGraphicConverter->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool RegressionCurveItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = m_spGraphicConverter->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& RegressionCurveItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nRegressionCurveWhichPairs; +} + +bool RegressionCurveItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + // No own (non-special) properties + return false; +} + +bool RegressionCurveItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + uno::Reference< chart2::XRegressionCurve > xCurve( GetPropertySet(), uno::UNO_QUERY ); + bool bChanged = false; + + OSL_ASSERT(xCurve.is()); + if(!xCurve.is()) + return false; + + switch( nWhichId ) + { + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = RegressionCurveHelper::getRegressionType(xCurve); + SvxChartRegress eNewRegress = static_cast< const SvxChartRegressItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( eRegress != eNewRegress ) + { + // note that changing the regression type changes the object + // for which this converter was created. Not optimal, but + // currently the only way to handle the type in the + // regression curve properties dialog + xCurve = RegressionCurveHelper::changeRegressionCurveType( + eNewRegress, + m_xCurveContainer, + xCurve); + uno::Reference xProperties( xCurve, uno::UNO_QUERY ); + resetPropertySet( xProperties ); + bChanged = true; + } + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + } + return bChanged; +} + +void RegressionCurveItemConverter::FillSpecialItem(sal_uInt16 nWhichId, SfxItemSet& rOutItemSet ) const +{ + uno::Reference xCurve(GetPropertySet(), uno::UNO_QUERY); + OSL_ASSERT(xCurve.is()); + if(!xCurve.is()) + return; + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + + switch( nWhichId ) + { + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = RegressionCurveHelper::getRegressionType(xCurve); + rOutItemSet.Put( SvxChartRegressItem( eRegress, SCHATTR_REGRESSION_TYPE )); + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_INTERCEPT_VALUE, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + lclConvertToItemSet(rOutItemSet, nWhichId, xCurve->getEquationProperties(), "ShowCorrelationCoefficient"); + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx b/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx new file mode 100644 index 000000000..22fc379b2 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/RegressionEquationItemConverter.cxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetEquationPropertyMap() +{ + static ItemPropertyMapType aEquationPropertyMap; + + return aEquationPropertyMap; +}; + +} // anonymous namespace + +RegressionEquationItemConverter::RegressionEquationItemConverter( + const css::uno::Reference< css::beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + + m_aConverters.emplace_back( + new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); +} + +RegressionEquationItemConverter::~RegressionEquationItemConverter() +{ +} + +void RegressionEquationItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool RegressionEquationItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ); + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& RegressionEquationItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nRegEquationWhichPairs; +} + +bool RegressionEquationItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetEquationPropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool RegressionEquationItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SID_ATTR_NUMBERFORMAT_VALUE: + { + uno::Any aValue( static_cast< sal_Int32 >( + static_cast< const SfxUInt32Item & >( + rItemSet.Get( nWhichId )).GetValue())); + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) != aValue) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_NUMFMT, aValue); + bChanged = true; + } + } + break; + } + + return bChanged; +} + +void RegressionEquationItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nFormatKey = 0; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormatKey) + { + rOutItemSet.Put( SfxUInt32Item( nWhichId, nFormatKey )); + } + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx new file mode 100644 index 000000000..3c1387009 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include + +const WhichRangesContainer nTitleWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nAxisWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + SCHATTR_AXIS_START, SCHATTR_AXIS_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE, // 10585 - 10585 svx/svxids.hrc + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, // 11432 svx/svxids.hrc + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nAllAxisWhichPairs(svl::Items< + SCHATTR_TEXT_START, SCHATTR_TEXT_END, + SCHATTR_AXIS_LABEL_START, SCHATTR_AXIS_LABEL_END, + XATTR_LINE_FIRST, XATTR_LINE_LAST, + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nGridWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nLegendWhichPairs(svl::Items< + SCHATTR_LEGEND_START, SCHATTR_LEGEND_END, // 3 - 3 sch/schattr.hxx + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nDataLabelWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, + SCHATTR_TEXT_DEGREES,SCHATTR_TEXT_DEGREES, + EE_PARA_WRITINGDIR,EE_PARA_WRITINGDIR, + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE /* 11432 svx/svxids.hrc */ +>); + +const WhichRangesContainer nDataPointWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /* 1 - 2 sch/schattr.hxx*/ + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_START,SCHATTR_STYLE_END, /* 59 - 68 sch/schattr.hxx*/ + SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH, /* 94 sch/schattr.hxx*/ + SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE, /* 97 sch/schattr.hxx*/ + SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, + XATTR_LINE_FIRST, XATTR_LINE_LAST, /* 1000 - 1016 svx/xdef.hxx */ + XATTR_FILL_FIRST, XATTR_FILL_LAST, /* 1018 - 1046 svx/xdef.hxx */ + SDRATTR_3D_FIRST, SDRATTR_3D_LAST, /* 1244 - 1334 svx/svddef.hxx */ + EE_ITEMS_START, EE_ITEMS_END, /* 3994 - 4037 editeng/eeitem.hxx */ + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432 svx/svxids.hrc */ + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nTextLabelWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_SYMBOL, SCHATTR_STYLE_SYMBOL, + SCHATTR_SYMBOL_BRUSH, SCHATTR_SYMBOL_BRUSH, + SCHATTR_SYMBOL_SIZE, SCHATTR_SYMBOL_SIZE, + XATTR_LINESTYLE, XATTR_LINECOLOR, + XATTR_LINETRANSPARENCE, XATTR_LINETRANSPARENCE, + EE_ITEMS_START, EE_ITEMS_END, + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nSeriesOptionsWhichPairs(svl::Items< + SCHATTR_AXIS,SCHATTR_AXIS, /* 69 sch/schattr.hxx*/ + SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT, /* 98 - 100 (incl. SCHATTR_GAPWIDTH) */ + SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES +>); + +// nDataPointWhichPairs + nSeriesOptionsWhichPairs +const WhichRangesContainer nRowWhichPairs(svl::Items< + SCHATTR_DATADESCR_START, SCHATTR_DATADESCR_END, /* 1 - 2 sch/schattr.hxx*/ + SCHATTR_TEXT_DEGREES, SCHATTR_TEXT_DEGREES, + SCHATTR_STYLE_START,SCHATTR_STYLE_END, /* 59 - 68 sch/schattr.hxx*/ + SCHATTR_AXIS,SCHATTR_AXIS, /* 69 sch/schattr.hxx*/ + SCHATTR_SYMBOL_BRUSH,SCHATTR_SYMBOL_BRUSH, /* 94 sch/schattr.hxx*/ + SCHATTR_SYMBOL_SIZE,SCHATTR_SYMBOL_SIZE, /* 97 sch/schattr.hxx*/ + SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, + SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT, /* 98 - 100 (incl. SCHATTR_GAPWIDTH) */ + SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES, + XATTR_LINE_FIRST, XATTR_LINE_LAST, /* 1000 - 1016 svx/xdef.hxx */ + XATTR_FILL_FIRST, XATTR_FILL_LAST, /* 1018 - 1046 svx/xdef.hxx */ + SDRATTR_3D_FIRST, SDRATTR_3D_LAST, /* 1244 - 1334 svx/svddef.hxx */ + EE_ITEMS_START, EE_ITEMS_END, /* 3994 - 4037 editeng/eeitem.hxx */ + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO, /* 10585 - 10585 svx/svxids.hrc */ + SID_ATTR_NUMBERFORMAT_SOURCE, SID_ATTR_NUMBERFORMAT_SOURCE, /* 11432 svx/svxids.hrc */ + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING +>); + +const WhichRangesContainer nStatWhichPairs(svl::Items< + SCHATTR_STAT_START, SCHATTR_STAT_END, // 45 - 52 sch/schattr.hxx + SCHATTR_REGRESSION_START, SCHATTR_REGRESSION_END // 108 - 109 +>); + +const WhichRangesContainer nErrorBarWhichPairs(svl::Items< + SCHATTR_STAT_START, SCHATTR_STAT_END, // 45 - 52 sch/schattr.hxx + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +// for CharacterProperties + +const WhichRangesContainer nCharacterPropertyWhichPairs(svl::Items< + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +const WhichRangesContainer nLinePropertyWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nLineAndFillPropertyWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1000 - 1016 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST // 1067 - 1078 svx/svddef.hxx +>); + +const WhichRangesContainer nRegressionCurveWhichPairs(svl::Items< + SCHATTR_REGRESSION_START, SCHATTR_REGRESSION_END, // 108 - 109 + XATTR_LINE_FIRST, XATTR_LINE_LAST // 1000 - 1016 svx/xdef.hxx +>); + +const WhichRangesContainer nRegEquationWhichPairs(svl::Items< + XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx + XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx + SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx + EE_ITEMS_START, EE_ITEMS_END, // Characters + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_VALUE, // 10585 - 10585 svx/svxids.hrc + SID_CHAR_DLG_PREVIEW_STRING, SID_CHAR_DLG_PREVIEW_STRING // Characters +>); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx b/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx new file mode 100644 index 000000000..2f84084a1 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/SeriesOptionsItemConverter.cxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart::wrapper +{ + +SeriesOptionsItemConverter::SeriesOptionsItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const uno::Reference< uno::XComponentContext > & xContext + , const uno::Reference< beans::XPropertySet >& xPropertySet + , SfxItemPool& rItemPool ) + : ItemConverter( xPropertySet, rItemPool ) + , m_xChartModel(xChartModel) + , m_xCC(xContext) + , m_bAttachToMainAxis(true) + , m_bSupportingOverlapAndGapWidthProperties(false) + , m_bSupportingBarConnectors(false) + , m_nBarOverlap(0) + , m_nGapWidth(100) + , m_bConnectBars(false) + , m_bSupportingAxisSideBySide(false) + , m_bGroupBarsPerAxis(true) + , m_bSupportingStartingAngle(false) + , m_nStartingAngle(90) + , m_bClockwise(false) + , m_nMissingValueTreatment(0) + , m_bSupportingPlottingOfHiddenCells(false) + , m_bIncludeHiddenCells(true) + , m_bHideLegendEntry(false) +{ + try + { + uno::Reference< XDataSeries > xDataSeries( xPropertySet, uno::UNO_QUERY ); + + m_bAttachToMainAxis = DiagramHelper::isSeriesAttachedToMainAxis( xDataSeries ); + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xDataSeries ) ); + + m_xCooSys = DataSeriesHelper::getCoordinateSystemOfSeries( xDataSeries, xDiagram ); + if( m_xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, 0, m_xCooSys ); + chart2::ScaleData aScale( xAxis->getScaleData() ); + m_bClockwise = (aScale.Orientation == chart2::AxisOrientation_REVERSE); + } + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + m_bSupportingOverlapAndGapWidthProperties = ChartTypeHelper::isSupportingOverlapAndGapWidthProperties( xChartType, nDimensionCount ); + + if( m_bSupportingOverlapAndGapWidthProperties ) + { + + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + + uno::Sequence< sal_Int32 > aBarPositionSequence; + if( xChartType.is() ) + { + if( xChartType->getPropertyValue( "OverlapSequence" ) >>= aBarPositionSequence ) + { + if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + m_nBarOverlap = aBarPositionSequence[nAxisIndex]; + } + if( xChartType->getPropertyValue( "GapwidthSequence" ) >>= aBarPositionSequence ) + { + if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + m_nGapWidth = aBarPositionSequence[nAxisIndex]; + } + } + } + + m_bSupportingBarConnectors = ChartTypeHelper::isSupportingBarConnectors( xChartType, nDimensionCount ); + if( m_bSupportingBarConnectors && xDiagram.is() ) + { + xDiagram->getPropertyValue( "ConnectBars" ) >>= m_bConnectBars; + } + + m_bSupportingAxisSideBySide = ChartTypeHelper::isSupportingAxisSideBySide( xChartType, nDimensionCount ); + if( m_bSupportingAxisSideBySide && xDiagram.is() ) + { + xDiagram->getPropertyValue( "GroupBarsPerAxis" ) >>= m_bGroupBarsPerAxis; + } + + m_bSupportingStartingAngle = ChartTypeHelper::isSupportingStartingAngle( xChartType ); + if( m_bSupportingStartingAngle ) + { + xDiagram->getPropertyValue( "StartingAngle" ) >>= m_nStartingAngle; + } + + m_aSupportedMissingValueTreatments = ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ); + m_nMissingValueTreatment = DiagramHelper::getCorrectedMissingValueTreatment( + ChartModelHelper::findDiagram(m_xChartModel), xChartType ); + + uno::Reference< beans::XPropertySet > xProp( m_xChartModel->getDataProvider(), uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + //test whether the data provider offers this property + xProp->getPropertyValue( "IncludeHiddenCells" ); + //if not exception is thrown the property is offered + m_bSupportingPlottingOfHiddenCells = true; + xDiagram->getPropertyValue( "IncludeHiddenCells" ) >>= m_bIncludeHiddenCells; + } + catch( const beans::UnknownPropertyException& ) + { + } + } + + m_bHideLegendEntry = !xPropertySet->getPropertyValue("ShowLegendEntry").get(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +SeriesOptionsItemConverter::~SeriesOptionsItemConverter() +{ +} + +const WhichRangesContainer& SeriesOptionsItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nSeriesOptionsWhichPairs; +} + +bool SeriesOptionsItemConverter::GetItemProperty( tWhichIdType /*nWhichId*/, tPropertyNameWithMemberId & /*rOutProperty*/ ) const +{ + return false; +} + +bool SeriesOptionsItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + switch( nWhichId ) + { + case SCHATTR_AXIS: + { + sal_Int32 nItemValue = static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue(); + bool bAttachToMainAxis = nItemValue == CHART_AXIS_PRIMARY_Y; + if( bAttachToMainAxis != m_bAttachToMainAxis ) + { + //change model: + bChanged = DiagramHelper::attachSeriesToAxis( bAttachToMainAxis, uno::Reference< XDataSeries >::query( GetPropertySet() ) + , ChartModelHelper::findDiagram(m_xChartModel), m_xCC ); + + if( bChanged ) + m_bAttachToMainAxis = bAttachToMainAxis; + } + } + break; + + case SCHATTR_BAR_OVERLAP: + case SCHATTR_BAR_GAPWIDTH: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + { + sal_Int32& rBarPosition = ( nWhichId == SCHATTR_BAR_OVERLAP ) ? m_nBarOverlap : m_nGapWidth; + rBarPosition = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + + OUString aPropName("GapwidthSequence" ); + if( nWhichId == SCHATTR_BAR_OVERLAP ) + aPropName = "OverlapSequence"; + + uno::Reference< XDataSeries > xDataSeries( GetPropertySet(), uno::UNO_QUERY ); + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(m_xChartModel) ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram , xDataSeries ) ); + if( xChartType.is() ) + { + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + uno::Sequence< sal_Int32 > aBarPositionSequence; + if( xChartType->getPropertyValue( aPropName ) >>= aBarPositionSequence ) + { + bool bGroupBarsPerAxis = rItemSet.Get( SCHATTR_GROUP_BARS_PER_AXIS ).GetValue(); + if(!bGroupBarsPerAxis) + { + //set the same value for all axes + for( auto & pos : asNonConstRange(aBarPositionSequence) ) + pos = rBarPosition; + } + else if( nAxisIndex >= 0 && nAxisIndex < aBarPositionSequence.getLength() ) + aBarPositionSequence.getArray()[nAxisIndex] = rBarPosition; + + xChartType->setPropertyValue( aPropName, uno::Any(aBarPositionSequence) ); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_BAR_CONNECT: + { + m_bConnectBars = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_bSupportingBarConnectors ) + { + bool bOldConnectBars = false; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() && + (xDiagramProperties->getPropertyValue( "ConnectBars" ) >>= bOldConnectBars) && + bOldConnectBars != m_bConnectBars ) + { + xDiagramProperties->setPropertyValue( "ConnectBars" , uno::Any(m_bConnectBars) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_GROUP_BARS_PER_AXIS: + { + m_bGroupBarsPerAxis = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_bSupportingAxisSideBySide ) + { + bool bOldGroupBarsPerAxis = true; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() && + (xDiagramProperties->getPropertyValue( "GroupBarsPerAxis" ) >>= bOldGroupBarsPerAxis) && + bOldGroupBarsPerAxis != m_bGroupBarsPerAxis ) + { + xDiagramProperties->setPropertyValue( "GroupBarsPerAxis" , uno::Any(m_bGroupBarsPerAxis) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_STARTING_ANGLE: + { + if( m_bSupportingStartingAngle ) + { + m_nStartingAngle = static_cast< const SdrAngleItem & >( rItemSet.Get( nWhichId )).GetValue().get() / 100; + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() ) + { + xDiagramProperties->setPropertyValue( "StartingAngle" , uno::Any(m_nStartingAngle) ); + bChanged = true; + } + } + } + break; + + case SCHATTR_CLOCKWISE: + { + bool bClockwise = static_cast< const SfxBoolItem & >( + rItemSet.Get( nWhichId )).GetValue(); + if( m_xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, 0, m_xCooSys ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + aScaleData.Orientation = bClockwise ? chart2::AxisOrientation_REVERSE : chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + bChanged = true; + } + } + } + break; + + case SCHATTR_MISSING_VALUE_TREATMENT: + { + if( m_aSupportedMissingValueTreatments.hasElements() ) + { + sal_Int32 nNew = static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + if( m_nMissingValueTreatment != nNew ) + { + try + { + rtl::Reference< Diagram > xDiagramProperties( ChartModelHelper::findDiagram(m_xChartModel), uno::UNO_QUERY ); + if( xDiagramProperties.is() ) + { + xDiagramProperties->setPropertyValue( "MissingValueTreatment" , uno::Any( nNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + } + break; + case SCHATTR_INCLUDE_HIDDEN_CELLS: + { + if( m_bSupportingPlottingOfHiddenCells ) + { + bool bIncludeHiddenCells = static_cast(rItemSet.Get(nWhichId)).GetValue(); + if (bIncludeHiddenCells != m_bIncludeHiddenCells) + { + if (m_xChartModel) + bChanged = ChartModelHelper::setIncludeHiddenCells( bIncludeHiddenCells, *m_xChartModel ); + } + } + } + break; + case SCHATTR_HIDE_LEGEND_ENTRY: + { + bool bHideLegendEntry = static_cast(rItemSet.Get(nWhichId)).GetValue(); + if (bHideLegendEntry != m_bHideLegendEntry) + { + GetPropertySet()->setPropertyValue("ShowLegendEntry", css::uno::Any(!bHideLegendEntry)); + } + } + break; + } + return bChanged; +} + +void SeriesOptionsItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_AXIS: + { + sal_Int32 nItemValue = m_bAttachToMainAxis ? CHART_AXIS_PRIMARY_Y : CHART_AXIS_SECONDARY_Y; + rOutItemSet.Put( SfxInt32Item(nWhichId,nItemValue ) ); + break; + } + case SCHATTR_BAR_OVERLAP: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + rOutItemSet.Put( SfxInt32Item(nWhichId,m_nBarOverlap) ); + break; + } + case SCHATTR_BAR_GAPWIDTH: + { + if( m_bSupportingOverlapAndGapWidthProperties ) + rOutItemSet.Put( SfxInt32Item(nWhichId,m_nGapWidth) ); + break; + } + case SCHATTR_BAR_CONNECT: + { + if( m_bSupportingBarConnectors ) + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bConnectBars)); + break; + } + case SCHATTR_GROUP_BARS_PER_AXIS: + { + if( m_bSupportingAxisSideBySide ) + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bGroupBarsPerAxis) ); + break; + } + case SCHATTR_AXIS_FOR_ALL_SERIES: + { + break; + } + case SCHATTR_STARTING_ANGLE: + { + if( m_bSupportingStartingAngle ) + rOutItemSet.Put( SdrAngleItem(SCHATTR_STARTING_ANGLE, Degree100(m_nStartingAngle*100)) ); + break; + } + case SCHATTR_CLOCKWISE: + { + rOutItemSet.Put( SfxBoolItem(nWhichId,m_bClockwise) ); + break; + } + case SCHATTR_MISSING_VALUE_TREATMENT: + { + if( m_aSupportedMissingValueTreatments.hasElements() ) + rOutItemSet.Put( SfxInt32Item( nWhichId, m_nMissingValueTreatment )); + break; + } + case SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS: + { + rOutItemSet.Put( SfxIntegerListItem( nWhichId, m_aSupportedMissingValueTreatments ) ); + break; + } + case SCHATTR_INCLUDE_HIDDEN_CELLS: + { + if( m_bSupportingPlottingOfHiddenCells ) + rOutItemSet.Put( SfxBoolItem(nWhichId, m_bIncludeHiddenCells) ); + break; + } + case SCHATTR_HIDE_LEGEND_ENTRY: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, m_bHideLegendEntry)); + break; + } + default: + break; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx new file mode 100644 index 000000000..5e230a434 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx @@ -0,0 +1,858 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ + +uno::Reference< beans::XPropertySet > lcl_GetErrorBar( + const uno::Reference< beans::XPropertySet > & xProp, bool bYError ) +{ + uno::Reference< beans::XPropertySet > xResult; + + if( xProp.is()) + try + { + ( xProp->getPropertyValue( bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X) ) >>= xResult ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +uno::Reference< beans::XPropertySet > lcl_GetDefaultErrorBar() +{ + return uno::Reference< beans::XPropertySet >( new ::chart::ErrorBar ); +} + +void lcl_getErrorValues( const uno::Reference< beans::XPropertySet > & xErrorBarProp, + double & rOutPosError, double & rOutNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "PositiveError" ) >>= rOutPosError; + xErrorBarProp->getPropertyValue( "NegativeError" ) >>= rOutNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void lcl_getErrorIndicatorValues( + const uno::Reference< beans::XPropertySet > & xErrorBarProp, + bool & rOutShowPosError, bool & rOutShowNegError ) +{ + if( ! xErrorBarProp.is()) + return; + + try + { + xErrorBarProp->getPropertyValue( "ShowPositiveError" ) >>= rOutShowPosError; + xErrorBarProp->getPropertyValue( "ShowNegativeError" ) >>= rOutShowNegError; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +uno::Reference< beans::XPropertySet > lcl_getEquationProperties( + const uno::Reference< beans::XPropertySet > & xSeriesPropSet, const SfxItemSet * pItemSet ) +{ + bool bEquationExists = true; + + // ensure that a trendline is on + if( pItemSet ) + { + if( const SvxChartRegressItem* pRegressionItem = pItemSet->GetItemIfSet( SCHATTR_REGRESSION_TYPE ) ) + { + SvxChartRegress eRegress = pRegressionItem->GetValue(); + bEquationExists = ( eRegress != SvxChartRegress::NONE ); + } + } + + if( bEquationExists ) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropSet, uno::UNO_QUERY ); + rtl::Reference< ::chart::RegressionCurveModel > xCurve = + ::chart::RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt ); + if( xCurve.is()) + { + return xCurve->getEquationProperties(); + } + } + + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< beans::XPropertySet > lcl_getCurveProperties( + const uno::Reference< beans::XPropertySet > & xSeriesPropSet, const SfxItemSet * pItemSet ) +{ + bool bExists = true; + + // ensure that a trendline is on + if( pItemSet ) + { + if( const SvxChartRegressItem* pRegressionItem = pItemSet->GetItemIfSet( SCHATTR_REGRESSION_TYPE ) ) + { + SvxChartRegress eRegress = pRegressionItem->GetValue(); + bExists = ( eRegress != SvxChartRegress::NONE ); + } + } + + if( bExists ) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropSet, uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurve > xCurve( + ::chart::RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt )); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + return xProperties; + } + } + + return uno::Reference< beans::XPropertySet >(); +} + +template +bool lclConvertToPropertySet(const SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast(static_cast(rItemSet.Get( nWhichId )).GetValue()); + T aOldValue = aValue; + bool aSuccess = xProperties->getPropertyValue( aPropertyID ) >>= aOldValue; + if (!aSuccess || aOldValue != aValue) + { + xProperties->setPropertyValue( aPropertyID , uno::Any( aValue )); + return true; + } + } + return false; +} + +template +void lclConvertToItemSet(SfxItemSet& rItemSet, sal_uInt16 nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + T aValue = static_cast(static_cast(rItemSet.Get( nWhichId )).GetValue()); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(D( nWhichId, aValue )); + } + } +} + +void lclConvertToItemSetDouble(SfxItemSet& rItemSet, TypedWhichId nWhichId, const uno::Reference& xProperties, const OUString& aPropertyID) +{ + OSL_ASSERT(xProperties.is()); + if( xProperties.is() ) + { + double aValue = rItemSet.Get( nWhichId ).GetValue(); + if(xProperties->getPropertyValue( aPropertyID ) >>= aValue) + { + rItemSet.Put(SvxDoubleItem( aValue, nWhichId )); + } + } +} + +} // anonymous namespace + +namespace chart::wrapper +{ + +StatisticsItemConverter::StatisticsItemConverter( + const rtl::Reference<::chart::ChartModel> & xModel, + const uno::Reference< beans::XPropertySet > & rPropertySet, + SfxItemPool& rItemPool ) : + ItemConverter( rPropertySet, rItemPool ), + m_xModel( xModel ) +{ +} + +StatisticsItemConverter::~StatisticsItemConverter() +{ +} + +const WhichRangesContainer& StatisticsItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nStatWhichPairs; +} + +bool StatisticsItemConverter::GetItemProperty( + tWhichIdType /* nWhichId */, + tPropertyNameWithMemberId & /* rOutProperty */ ) const +{ + return false; +} + +bool StatisticsItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_STAT_AVERAGE: + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( + GetPropertySet(), uno::UNO_QUERY ); + bool bOldHasMeanValueLine = RegressionCurveHelper::hasMeanValueLine( xRegCnt ); + + bool bNewHasMeanValueLine = + static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + + if( bOldHasMeanValueLine != bNewHasMeanValueLine ) + { + if( ! bNewHasMeanValueLine ) + RegressionCurveHelper::removeMeanValueLine( xRegCnt ); + else + RegressionCurveHelper::addMeanValueLine( xRegCnt, GetPropertySet() ); + bChanged = true; + } + } + break; + + // Attention !!! This case must be passed before SCHATTR_STAT_PERCENT, + // SCHATTR_STAT_BIGERROR, SCHATTR_STAT_CONSTPLUS, + // SCHATTR_STAT_CONSTMINUS and SCHATTR_STAT_INDICATE + case SCHATTR_STAT_KIND_ERROR: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError )); + + SvxChartKindError eErrorKind = + static_cast< const SvxChartKindErrorItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + if( !xErrorBarProp.is() && eErrorKind == SvxChartKindError::NONE) + { + //nothing to do + } + else + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + switch( eErrorKind ) + { + case SvxChartKindError::NONE: + nStyle = css::chart::ErrorBarStyle::NONE; break; + case SvxChartKindError::Variant: + nStyle = css::chart::ErrorBarStyle::VARIANCE; break; + case SvxChartKindError::Sigma: + nStyle = css::chart::ErrorBarStyle::STANDARD_DEVIATION; break; + case SvxChartKindError::Percent: + nStyle = css::chart::ErrorBarStyle::RELATIVE; break; + case SvxChartKindError::BigError: + nStyle = css::chart::ErrorBarStyle::ERROR_MARGIN; break; + case SvxChartKindError::Const: + nStyle = css::chart::ErrorBarStyle::ABSOLUTE; break; + case SvxChartKindError::StdError: + nStyle = css::chart::ErrorBarStyle::STANDARD_ERROR; break; + case SvxChartKindError::Range: + nStyle = css::chart::ErrorBarStyle::FROM_DATA; break; + } + + if( !xErrorBarProp.is() ) + { + xErrorBarProp = lcl_GetDefaultErrorBar(); + GetPropertySet()->setPropertyValue( bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X), + uno::Any( xErrorBarProp )); + } + + xErrorBarProp->setPropertyValue( "ErrorBarStyle" , uno::Any( nStyle )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_PERCENT: + case SCHATTR_STAT_BIGERROR: + { + OSL_FAIL( "Deprecated item" ); + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ( ::rtl::math::approxEqual( fPos, fValue ) && + ::rtl::math::approxEqual( fNeg, fValue ))) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ::rtl::math::approxEqual( fPos, fValue )) + { + xErrorBarProp->setPropertyValue( "PositiveError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + double fValue = + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue(); + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + + if( bOldHasErrorBar && + ! ::rtl::math::approxEqual( fNeg, fValue )) + { + xErrorBarProp->setPropertyValue( "NegativeError" , uno::Any( fValue )); + bChanged = true; + } + } + break; + + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = + static_cast< const SvxChartRegressItem& >( + rItemSet.Get( nWhichId )).GetValue(); + + uno::Reference< chart2::XRegressionCurve > xCurve( GetPropertySet(), uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurveContainer > xContainer( GetPropertySet(), uno::UNO_QUERY ); + + if( eRegress == SvxChartRegress::NONE ) + { + if ( xContainer.is() ) + { + xContainer->removeRegressionCurve( xCurve ); + bChanged = true; + } + } + else + { + if ( xCurve.is() ) + { + SvxChartRegress eOldRegress( + RegressionCurveHelper::getRegressionType(xCurve)); + + if( eOldRegress != eRegress ) + { + xCurve = RegressionCurveHelper::changeRegressionCurveType( + eRegress, + xContainer, + xCurve); + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + resetPropertySet( xProperties ); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); + bChanged = lclConvertToPropertySet(rItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + case SCHATTR_STAT_INDICATE: + { + bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(),bYError)); + bool bOldHasErrorBar = xErrorBarProp.is(); + + SvxChartIndicate eIndicate = + static_cast< const SvxChartIndicateItem & >( + rItemSet.Get( nWhichId )).GetValue(); + + bool bNewIndPos = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Up ); + bool bNewIndNeg = (eIndicate == SvxChartIndicate::Both || eIndicate == SvxChartIndicate::Down ); + + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bOldHasErrorBar && + ( bShowPos != bNewIndPos || + bShowNeg != bNewIndNeg )) + { + xErrorBarProp->setPropertyValue( "ShowPositiveError" , uno::Any( bNewIndPos )); + xErrorBarProp->setPropertyValue( "ShowNegativeError" , uno::Any( bNewIndNeg )); + bChanged = true; + } + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + const bool bYError = + rItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< chart2::data::XDataSource > xErrorBarSource( lcl_GetErrorBar( GetPropertySet(), bYError), + uno::UNO_QUERY ); + uno::Reference< chart2::data::XDataProvider > xDataProvider; + + if( m_xModel.is()) + xDataProvider.set( m_xModel->getDataProvider()); + if( xErrorBarSource.is() && xDataProvider.is()) + { + OUString aNewRange( static_cast< const SfxStringItem & >( rItemSet.Get( nWhichId )).GetValue()); + bool bApplyNewRange = false; + + bool bIsPositiveValue( nWhichId == SCHATTR_STAT_RANGE_POS ); + if( m_xModel->hasInternalDataProvider()) + { + if( !aNewRange.isEmpty()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + if( ! xSeq.is()) + { + // no data range for error bars yet => create + uno::Reference< chart2::XInternalDataProvider > xIntDataProvider( xDataProvider, uno::UNO_QUERY ); + OSL_ASSERT( xIntDataProvider.is()); + if( xIntDataProvider.is()) + { + xIntDataProvider->appendSequence(); + aNewRange = "last"; + bApplyNewRange = true; + } + } + } + } + else + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, bIsPositiveValue, bYError )); + bApplyNewRange = + ! ( xSeq.is() && (aNewRange == xSeq->getSourceRangeRepresentation())); + } + + if( bApplyNewRange ) + StatisticsHelper::setErrorDataSequence( + xErrorBarSource, xDataProvider, aNewRange, bIsPositiveValue, bYError ); + } + } + break; + } + + return bChanged; +} + +void StatisticsItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_STAT_AVERAGE: + rOutItemSet.Put( + SfxBoolItem( nWhichId, + RegressionCurveHelper::hasMeanValueLine( + uno::Reference< chart2::XRegressionCurveContainer >( + GetPropertySet(), uno::UNO_QUERY )))); + break; + + case SCHATTR_STAT_KIND_ERROR: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + SvxChartKindError eErrorKind = SvxChartKindError::NONE; + uno::Reference< beans::XPropertySet > xErrorBarProp( + lcl_GetErrorBar( GetPropertySet(), bYError)); + if( xErrorBarProp.is() ) + { + sal_Int32 nStyle = 0; + if( xErrorBarProp->getPropertyValue( "ErrorBarStyle" ) >>= nStyle ) + { + switch( nStyle ) + { + case css::chart::ErrorBarStyle::NONE: + break; + case css::chart::ErrorBarStyle::VARIANCE: + eErrorKind = SvxChartKindError::Variant; break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + eErrorKind = SvxChartKindError::Sigma; break; + case css::chart::ErrorBarStyle::ABSOLUTE: + eErrorKind = SvxChartKindError::Const; break; + case css::chart::ErrorBarStyle::RELATIVE: + eErrorKind = SvxChartKindError::Percent; break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + eErrorKind = SvxChartKindError::BigError; break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + eErrorKind = SvxChartKindError::StdError; break; + case css::chart::ErrorBarStyle::FROM_DATA: + eErrorKind = SvxChartKindError::Range; break; + } + } + } + rOutItemSet.Put( SvxChartKindErrorItem( eErrorKind, SCHATTR_STAT_KIND_ERROR )); + } + break; + + case SCHATTR_STAT_PERCENT: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_PERCENT )); + } + } + break; + + case SCHATTR_STAT_BIGERROR: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( ( fPos + fNeg ) / 2.0, SCHATTR_STAT_BIGERROR )); + } + } + break; + + case SCHATTR_STAT_CONSTPLUS: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fPos, SCHATTR_STAT_CONSTPLUS )); + } + } + break; + + case SCHATTR_STAT_CONSTMINUS: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + if( xErrorBarProp.is()) + { + double fPos(0.0), fNeg(0.0); + lcl_getErrorValues( xErrorBarProp, fPos, fNeg ); + rOutItemSet.Put( SvxDoubleItem( fNeg, SCHATTR_STAT_CONSTMINUS )); + } + } + break; + + case SCHATTR_REGRESSION_TYPE: + { + SvxChartRegress eRegress = + RegressionCurveHelper::getFirstRegressTypeNotMeanValueLine( + uno::Reference< chart2::XRegressionCurveContainer >( + GetPropertySet(), uno::UNO_QUERY ) ); + rOutItemSet.Put( SvxChartRegressItem( eRegress, SCHATTR_REGRESSION_TYPE )); + } + break; + + case SCHATTR_REGRESSION_DEGREE: + { + + uno::Reference xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "PolynomialDegree"); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "MovingAveragePeriod"); + } + break; + + case SCHATTR_REGRESSION_MOVING_TYPE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "MovingAverageType"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD, xProperties, "ExtrapolateForward"); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD, xProperties, "ExtrapolateBackward"); + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "ForceIntercept"); + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSetDouble(rOutItemSet, SCHATTR_REGRESSION_INTERCEPT_VALUE, xProperties, "InterceptValue"); + } + break; + + case SCHATTR_REGRESSION_CURVE_NAME: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xProperties, "CurveName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xEqProp, "ShowEquation"); + } + break; + + case SCHATTR_REGRESSION_XNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xEqProp, "XName"); + } + break; + + case SCHATTR_REGRESSION_YNAME: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xEqProp, "YName"); + } + break; + + case SCHATTR_REGRESSION_SHOW_COEFF: + { + uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), nullptr )); + lclConvertToItemSet(rOutItemSet, nWhichId, xEqProp, "ShowCorrelationCoefficient"); + } + break; + + case SCHATTR_STAT_INDICATE: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< beans::XPropertySet > xErrorBarProp( lcl_GetErrorBar( GetPropertySet(),bYError)); + SvxChartIndicate eIndicate = SvxChartIndicate::Both; + if( xErrorBarProp.is()) + { + bool bShowPos(false), bShowNeg(false); + lcl_getErrorIndicatorValues( xErrorBarProp, bShowPos, bShowNeg ); + + if( bShowPos ) + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Both; + else + eIndicate = SvxChartIndicate::Up; + } + else + { + if( bShowNeg ) + eIndicate = SvxChartIndicate::Down; + else + eIndicate = SvxChartIndicate::NONE; + } + } + rOutItemSet.Put( SvxChartIndicateItem( eIndicate, SCHATTR_STAT_INDICATE )); + } + break; + + case SCHATTR_STAT_RANGE_POS: + case SCHATTR_STAT_RANGE_NEG: + { + bool bYError = + rOutItemSet.Get(SCHATTR_STAT_ERRORBAR_TYPE).GetValue(); + uno::Reference< chart2::data::XDataSource > xErrorBarSource( lcl_GetErrorBar( GetPropertySet(),bYError), + uno::UNO_QUERY ); + if( xErrorBarSource.is()) + { + uno::Reference< chart2::data::XDataSequence > xSeq( + StatisticsHelper::getErrorDataSequenceFromDataSource( + xErrorBarSource, (nWhichId == SCHATTR_STAT_RANGE_POS), bYError )); + if( xSeq.is()) + rOutItemSet.Put( SfxStringItem( nWhichId, xSeq->getSourceRangeRepresentation())); + } + } + break; + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx new file mode 100644 index 000000000..644d8d80c --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/TextLabelItemConverter.cxx @@ -0,0 +1,723 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SchWhichPairs.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::chart2; +using com::sun::star::uno::Reference; + +namespace chart::wrapper { + +namespace { + +const ItemPropertyMapType& getTextLabelPropertyMap() +{ + static ItemPropertyMapType aMap{ + {XATTR_LINESTYLE, {CHART_UNONAME_LABEL_BORDER_STYLE, 0}}, + {XATTR_LINEWIDTH, {CHART_UNONAME_LABEL_BORDER_WIDTH, 0}}, + {XATTR_LINEDASH, {CHART_UNONAME_LABEL_BORDER_DASH, 0}}, + {XATTR_LINECOLOR, {CHART_UNONAME_LABEL_BORDER_COLOR, 0}}, + {XATTR_LINETRANSPARENCE, {CHART_UNONAME_LABEL_BORDER_TRANS, 0}}}; + return aMap; +}; + +sal_Int32 getSymbolStyleForSymbol( const chart2::Symbol& rSymbol ) +{ + sal_Int32 nStyle = SVX_SYMBOLTYPE_UNKNOWN; + switch (rSymbol.Style) + { + case chart2::SymbolStyle_NONE: + nStyle = SVX_SYMBOLTYPE_NONE; + break; + case chart2::SymbolStyle_AUTO: + nStyle = SVX_SYMBOLTYPE_AUTO; + break; + case chart2::SymbolStyle_GRAPHIC: + nStyle = SVX_SYMBOLTYPE_BRUSHITEM; + break; + case chart2::SymbolStyle_STANDARD: + nStyle = rSymbol.StandardSymbol; + break; + case chart2::SymbolStyle_POLYGON: + default: + ; + } + return nStyle; +} + +bool numberFormatFromItemToPropertySet( + sal_uInt16 nWhichId, const SfxItemSet& rItemSet, const uno::Reference& xPropertySet, + bool bOverwriteDataPoints ) +{ + bool bChanged = false; + if (!xPropertySet.is()) + return bChanged; + + OUString aPropertyName = (nWhichId == SID_ATTR_NUMBERFORMAT_VALUE) ? OUString(CHART_UNONAME_NUMFMT) : OUString("PercentageNumberFormat"); + sal_uInt16 nSourceWhich = (nWhichId == SID_ATTR_NUMBERFORMAT_VALUE) ? SID_ATTR_NUMBERFORMAT_SOURCE : SCHATTR_PERCENT_NUMBERFORMAT_SOURCE; + + if (rItemSet.GetItemState(nSourceWhich) != SfxItemState::SET) + return bChanged; + + uno::Any aValue; + bool bUseSourceFormat = static_cast(rItemSet.Get(nSourceWhich)).GetValue(); + if (!bUseSourceFormat) + { + SfxItemState aState = rItemSet.GetItemState(nWhichId); + if (aState == SfxItemState::SET) + { + sal_Int32 nFmt = static_cast( + static_cast( + rItemSet.Get(nWhichId)).GetValue()); + aValue <<= nFmt; + } + else + return bChanged; + } + + uno::Any aOldValue = xPropertySet->getPropertyValue(aPropertyName); + if (bOverwriteDataPoints) + { + Reference xSeries(xPropertySet, uno::UNO_QUERY); + if (aValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, aPropertyName, aOldValue)) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, aPropertyName, aValue); + bChanged = true; + } + } + else if (aOldValue != aValue) + { + xPropertySet->setPropertyValue(aPropertyName, aValue); + bChanged = true; + } + return bChanged; +} + +bool useSourceFormatFromItemToPropertySet( + sal_uInt16 nWhichId, const SfxItemSet& rItemSet, const uno::Reference& xPropertySet, + bool bOverwriteDataPoints ) +{ + bool bChanged = false; + if (!xPropertySet.is()) + return bChanged; + OUString aPropertyName = (nWhichId == SID_ATTR_NUMBERFORMAT_SOURCE) ? OUString(CHART_UNONAME_NUMFMT) : OUString("PercentageNumberFormat"); + sal_uInt16 nFormatWhich = (nWhichId == SID_ATTR_NUMBERFORMAT_SOURCE) ? SID_ATTR_NUMBERFORMAT_VALUE : SCHATTR_PERCENT_NUMBERFORMAT_VALUE; + + if (rItemSet.GetItemState(nWhichId) != SfxItemState::SET) + return bChanged; + + uno::Any aNewValue; + bool bUseSourceFormat = static_cast( + rItemSet.Get(nWhichId)).GetValue(); + xPropertySet->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(bUseSourceFormat)); + if (!bUseSourceFormat) + { + SfxItemState aState = rItemSet.GetItemState(nFormatWhich); + if (aState == SfxItemState::SET) + { + sal_Int32 nFormatKey = static_cast( + static_cast( + rItemSet.Get(nFormatWhich)).GetValue()); + aNewValue <<= nFormatKey; + } + else + return bChanged; + } + + uno::Any aOldValue(xPropertySet->getPropertyValue(aPropertyName)); + if (bOverwriteDataPoints) + { + Reference xSeries(xPropertySet, uno::UNO_QUERY); + if (aNewValue != aOldValue || + ::chart::DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, aPropertyName, aOldValue)) + { + ::chart::DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, aPropertyName, aNewValue); + bChanged = true; + } + } + else if (aOldValue != aNewValue) + { + xPropertySet->setPropertyValue(aPropertyName, aNewValue); + bChanged = true; + } + + return bChanged; +} + +} // anonymous namespace + +TextLabelItemConverter::TextLabelItemConverter( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference& rPropertySet, + const rtl::Reference& xSeries, + SfxItemPool& rItemPool, const awt::Size* pRefSize, + bool bDataSeries, sal_Int32 nNumberFormat, sal_Int32 nPercentNumberFormat ) : + ItemConverter(rPropertySet, rItemPool), + mnNumberFormat(nNumberFormat), + mnPercentNumberFormat(nPercentNumberFormat), + mbDataSeries(bDataSeries), + mbForbidPercentValue(true), + m_xSeries(xSeries) +{ + maConverters.emplace_back(new CharacterPropertyItemConverter(rPropertySet, rItemPool, pRefSize, "ReferencePageSize")); + + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xChartModel)); + rtl::Reference< ChartType > xChartType(DiagramHelper::getChartTypeOfSeries(xDiagram, xSeries)); + bool bFound = false; + bool bAmbiguous = false; + bool bSwapXAndY = DiagramHelper::getVertical(xDiagram, bFound, bAmbiguous); + maAvailableLabelPlacements = ChartTypeHelper::getSupportedLabelPlacements(xChartType, bSwapXAndY, xSeries); + + mbForbidPercentValue = ChartTypeHelper::getAxisType(xChartType, 0) != AxisType::CATEGORY; +} + +TextLabelItemConverter::~TextLabelItemConverter() +{ +} + +void TextLabelItemConverter::FillItemSet( SfxItemSet& rOutItemSet ) const +{ + for( const auto& pConv : maConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet(rOutItemSet); +} + +bool TextLabelItemConverter::ApplyItemSet( const SfxItemSet& rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv: maConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet(rItemSet) || bResult; +} + +const WhichRangesContainer& TextLabelItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTextLabelWhichPairs; +} + +bool TextLabelItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId& rOutProperty ) const +{ + const ItemPropertyMapType& rMap = getTextLabelPropertyMap(); + ItemPropertyMapType::const_iterator it = rMap.find(nWhichId); + + if (it == rMap.end()) + return false; + + rOutProperty = it->second; + return true; +} + +bool TextLabelItemConverter::ApplySpecialItem( sal_uInt16 nWhichId, const SfxItemSet& rItemSet ) +{ + bool bChanged = false; + + switch (nWhichId) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + const SfxBoolItem& rItem = static_cast(rItemSet.Get(nWhichId)); + + uno::Any aOldValue = GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL); + chart2::DataPointLabel aLabel; + if (aOldValue >>= aLabel) + { + sal_Bool& rValue = (nWhichId == SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : + (nWhichId == SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol)); + bool bOldValue = rValue; + rValue = rItem.GetValue(); + if (mbDataSeries) + { + Reference xSeries(GetPropertySet(), uno::UNO_QUERY); + if (bOldValue != bool(rValue) || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, CHART_UNONAME_LABEL, aOldValue)) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel)); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + bChanged = true; + } + } + else if (bOldValue != bool(rValue)) + { + GetPropertySet()->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + bChanged = true; + } + } + } + break; + case SID_ATTR_NUMBERFORMAT_VALUE: + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: //fall through intended + { + bChanged = numberFormatFromItemToPropertySet(nWhichId, rItemSet, GetPropertySet(), mbDataSeries); + } + break; + case SID_ATTR_NUMBERFORMAT_SOURCE: + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: //fall through intended + { + bChanged = useSourceFormatFromItemToPropertySet(nWhichId, rItemSet, GetPropertySet(), mbDataSeries); + } + break; + case SCHATTR_DATADESCR_SEPARATOR: + { + OUString aNewValue = static_cast(rItemSet.Get(nWhichId)).GetValue(); + try + { + OUString aOldValue; + GetPropertySet()->getPropertyValue("LabelSeparator") >>= aOldValue; + if (mbDataSeries) + { + Reference xSeries(GetPropertySet(), uno::UNO_QUERY); + if (aOldValue != aNewValue || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, "LabelSeparator", uno::Any(aOldValue))) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, "LabelSeparator", uno::Any(aNewValue)); + bChanged = true; + } + } + else if (aOldValue != aNewValue) + { + GetPropertySet()->setPropertyValue("LabelSeparator", uno::Any(aNewValue)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + case SCHATTR_DATADESCR_WRAP_TEXT: + { + + try + { + bool bNew = static_cast< const SfxBoolItem & >( rItemSet.Get( nWhichId )).GetValue(); + bool bOld = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bOld; + if( mbDataSeries ) + { + Reference< chart2::XDataSeries > xSeries( GetPropertySet(), uno::UNO_QUERY); + if( bOld!=bNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries, "TextWordWrap", uno::Any( bOld ) ) ) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "TextWordWrap", uno::Any( bNew ) ); + bChanged = true; + } + } + else if( bOld!=bNew ) + { + GetPropertySet()->setPropertyValue( "TextWordWrap", uno::Any( bNew )); + bChanged = true; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nNew = static_cast(rItemSet.Get(nWhichId)).GetValue(); + sal_Int32 nOld = -1; + RelativePosition aCustomLabelPosition; + GetPropertySet()->getPropertyValue("LabelPlacement") >>= nOld; + if (mbDataSeries) + { + Reference xSeries(GetPropertySet(), uno::UNO_QUERY); + if (nOld != nNew || + DataSeriesHelper::hasAttributedDataPointDifferentValue(xSeries, "LabelPlacement", uno::Any(nOld))) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(xSeries, "LabelPlacement", uno::Any(nNew)); + bChanged = true; + } + } + else if (nOld != nNew || (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition)) + { + GetPropertySet()->setPropertyValue("LabelPlacement", uno::Any(nNew)); + GetPropertySet()->setPropertyValue("CustomLabelPosition", uno::Any()); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_STYLE_SYMBOL: + { + sal_Int32 nStyle = + static_cast( + rItemSet.Get(nWhichId)).GetValue(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + sal_Int32 nOldStyle = getSymbolStyleForSymbol(aSymbol); + + if (nStyle != nOldStyle) + { + bool bDeleteSymbol = false; + switch (nStyle) + { + case SVX_SYMBOLTYPE_NONE: + aSymbol.Style = chart2::SymbolStyle_NONE; + break; + case SVX_SYMBOLTYPE_AUTO: + aSymbol.Style = chart2::SymbolStyle_AUTO; + break; + case SVX_SYMBOLTYPE_BRUSHITEM: + aSymbol.Style = chart2::SymbolStyle_GRAPHIC; + break; + case SVX_SYMBOLTYPE_UNKNOWN: + bDeleteSymbol = true; + break; + + default: + aSymbol.Style = chart2::SymbolStyle_STANDARD; + aSymbol.StandardSymbol = nStyle; + } + + if (bDeleteSymbol) + GetPropertySet()->setPropertyValue("Symbol", uno::Any()); + else + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + break; + case SCHATTR_SYMBOL_SIZE: + { + Size aSize = static_cast( + rItemSet.Get(nWhichId)).GetSize(); + chart2::Symbol aSymbol; + + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + if (aSize.getWidth() != aSymbol.Size.Width || + aSize.getHeight() != aSymbol.Size.Height) + { + aSymbol.Size.Width = aSize.getWidth(); + aSymbol.Size.Height = aSize.getHeight(); + + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + break; + case SCHATTR_SYMBOL_BRUSH: + { + const SvxBrushItem& rBrshItem(static_cast( + rItemSet.Get(nWhichId))); + uno::Any aXGraphicAny; + const Graphic* pGraphic(rBrshItem.GetGraphic()); + if (pGraphic) + { + uno::Reference xGraphic(pGraphic->GetXGraphic()); + if (xGraphic.is()) + { + aXGraphicAny <<= xGraphic; + chart2::Symbol aSymbol; + GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol; + if (aSymbol.Graphic != xGraphic) + { + aSymbol.Graphic = xGraphic; + GetPropertySet()->setPropertyValue("Symbol", uno::Any(aSymbol)); + bChanged = true; + } + } + } + } + break; + case SCHATTR_TEXT_DEGREES: + { + double fValue = static_cast( + static_cast( + rItemSet.Get(nWhichId)).GetValue().get()) / 100.0; + double fOldValue = 0.0; + bool bPropExisted = + (GetPropertySet()->getPropertyValue("TextRotation") >>= fOldValue); + + if (!bPropExisted || fOldValue != fValue) + { + GetPropertySet()->setPropertyValue("TextRotation", uno::Any(fValue)); + bChanged = true; + } + } + break; + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bNew = static_cast(rItemSet.Get(nWhichId)).GetValue(); + bool bOld = true; + if( (m_xSeries->getPropertyValue("ShowCustomLeaderLines") >>= bOld) && bOld != bNew ) + { + m_xSeries->setPropertyValue("ShowCustomLeaderLines", uno::Any(bNew)); + bChanged = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + } + + return bChanged; +} + +void TextLabelItemConverter::FillSpecialItem( sal_uInt16 nWhichId, SfxItemSet& rOutItemSet ) const +{ + switch (nWhichId) + { + case SCHATTR_DATADESCR_SHOW_NUMBER: + case SCHATTR_DATADESCR_SHOW_PERCENTAGE: + case SCHATTR_DATADESCR_SHOW_CATEGORY: + case SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME: + case SCHATTR_DATADESCR_SHOW_SYMBOL: + { + chart2::DataPointLabel aLabel; + if (GetPropertySet()->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel) + { + bool bValue = (nWhichId == SCHATTR_DATADESCR_SHOW_NUMBER) ? aLabel.ShowNumber : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_PERCENTAGE) ? aLabel.ShowNumberInPercent : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_CATEGORY) ? aLabel.ShowCategoryName : ( + (nWhichId == SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME) ? aLabel.ShowSeriesName : aLabel.ShowLegendSymbol))); + + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + + if (mbDataSeries) + { + if (DataSeriesHelper::hasAttributedDataPointDifferentValue( + Reference(GetPropertySet(), uno::UNO_QUERY), CHART_UNONAME_LABEL, uno::Any(aLabel))) + { + rOutItemSet.InvalidateItem(nWhichId); + } + } + } + } + break; + case SID_ATTR_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nKey)) + nKey = mnNumberFormat; + rOutItemSet.Put(SfxUInt32Item(nWhichId, nKey)); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_VALUE: + { + sal_Int32 nKey = 0; + if (!(GetPropertySet()->getPropertyValue("PercentageNumberFormat") >>= nKey)) + nKey = mnPercentNumberFormat; + rOutItemSet.Put(SfxUInt32Item(nWhichId, nKey)); + } + break; + case SID_ATTR_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue(CHART_UNONAME_NUMFMT).hasValue() && !bUseSourceFormat; + rOutItemSet.Put(SfxBoolItem(nWhichId, !bNumberFormatIsSet)); + } + break; + case SCHATTR_PERCENT_NUMBERFORMAT_SOURCE: + { + bool bUseSourceFormat = false; + try + { + GetPropertySet()->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bUseSourceFormat; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + bool bNumberFormatIsSet = GetPropertySet()->getPropertyValue("PercentageNumberFormat").hasValue() && !bUseSourceFormat; + rOutItemSet.Put(SfxBoolItem(nWhichId, !bNumberFormatIsSet)); + } + break; + case SCHATTR_DATADESCR_SEPARATOR: + { + try + { + OUString aValue; + GetPropertySet()->getPropertyValue("LabelSeparator") >>= aValue; + rOutItemSet.Put(SfxStringItem(nWhichId, aValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_WRAP_TEXT: + { + try + { + bool bValue = false; + GetPropertySet()->getPropertyValue( "TextWordWrap" ) >>= bValue; + rOutItemSet.Put( SfxBoolItem( nWhichId, bValue )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_PLACEMENT: + { + try + { + sal_Int32 nPlacement = 0; + RelativePosition aCustomLabelPosition; + if (!mbDataSeries && (GetPropertySet()->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition)) + rOutItemSet.Put(SfxInt32Item(nWhichId, css::chart::DataLabelPlacement::CUSTOM)); + else if (GetPropertySet()->getPropertyValue("LabelPlacement") >>= nPlacement) + rOutItemSet.Put(SfxInt32Item(nWhichId, nPlacement)); + else if (maAvailableLabelPlacements.hasElements()) + rOutItemSet.Put(SfxInt32Item(nWhichId, maAvailableLabelPlacements[0])); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + break; + case SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS: + { + rOutItemSet.Put(SfxIntegerListItem(nWhichId, maAvailableLabelPlacements)); + } + break; + case SCHATTR_DATADESCR_NO_PERCENTVALUE: + { + rOutItemSet.Put(SfxBoolItem(nWhichId, mbForbidPercentValue)); + } + break; + case SCHATTR_DATADESCR_CUSTOM_LEADER_LINES: + { + try + { + bool bValue = true; + if( m_xSeries->getPropertyValue( "ShowCustomLeaderLines" ) >>= bValue ) + rOutItemSet.Put(SfxBoolItem(nWhichId, bValue)); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + break; + case SCHATTR_STYLE_SYMBOL: + { + chart2::Symbol aSymbol; + if (GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + rOutItemSet.Put(SfxInt32Item(nWhichId, getSymbolStyleForSymbol(aSymbol))); + } + break; + case SCHATTR_SYMBOL_SIZE: + { + chart2::Symbol aSymbol; + if (GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + rOutItemSet.Put( + SvxSizeItem(nWhichId, Size(aSymbol.Size.Width, aSymbol.Size.Height))); + } + break; + case SCHATTR_SYMBOL_BRUSH: + { + chart2::Symbol aSymbol; + if ((GetPropertySet()->getPropertyValue("Symbol") >>= aSymbol) + && aSymbol.Graphic.is()) + { + rOutItemSet.Put( + SvxBrushItem(Graphic(aSymbol.Graphic), GPOS_MM, SCHATTR_SYMBOL_BRUSH)); + } + } + break; + case SCHATTR_TEXT_DEGREES: + { + double fValue = 0; + + if (GetPropertySet()->getPropertyValue("TextRotation") >>= fValue) + { + rOutItemSet.Put( + SdrAngleItem(SCHATTR_TEXT_DEGREES, Degree100(static_cast(rtl::math::round(fValue * 100.0))))); + } + } + break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx b/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx new file mode 100644 index 000000000..7a3f57af5 --- /dev/null +++ b/chart2/source/controller/itemsetwrapper/TitleItemConverter.cxx @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "SchWhichPairs.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace chart::wrapper { + +namespace { + +ItemPropertyMapType & lcl_GetTitlePropertyMap() +{ + static ItemPropertyMapType aTitlePropertyMap{ + {SCHATTR_TEXT_STACKED, {"StackCharacters", 0}}}; + return aTitlePropertyMap; +}; + +class FormattedStringsConverter : public MultipleItemConverter +{ +public: + FormattedStringsConverter( + const uno::Sequence< uno::Reference< chart2::XFormattedString > > & aStrings, + SfxItemPool & rItemPool, + const awt::Size* pRefSize, + const uno::Reference< beans::XPropertySet > & xParentProp ); + +protected: + virtual const WhichRangesContainer& GetWhichPairs() const override; +}; + +} // anonymous namespace + +FormattedStringsConverter::FormattedStringsConverter( + const uno::Sequence< uno::Reference< chart2::XFormattedString > > & aStrings, + SfxItemPool & rItemPool, + const awt::Size* pRefSize, + const uno::Reference< beans::XPropertySet > & xParentProp ) : + MultipleItemConverter( rItemPool ) +{ + bool bHasRefSize = (pRefSize && xParentProp.is()); + for( uno::Reference< chart2::XFormattedString > const & formattedStr : aStrings ) + { + uno::Reference< beans::XPropertySet > xProp( formattedStr, uno::UNO_QUERY ); + if( xProp.is()) + { + if( bHasRefSize ) + m_aConverters.emplace_back( + new CharacterPropertyItemConverter( + xProp, rItemPool, pRefSize, "ReferencePageSize", xParentProp)); + else + m_aConverters.emplace_back( new CharacterPropertyItemConverter( xProp, rItemPool )); + } + } +} + +const WhichRangesContainer& FormattedStringsConverter::GetWhichPairs() const +{ + return nCharacterPropertyWhichPairs; +} + +TitleItemConverter::TitleItemConverter( + const uno::Reference & rPropertySet, + SfxItemPool& rItemPool, + SdrModel& rDrawModel, + const uno::Reference< lang::XMultiServiceFactory > & xNamedPropertyContainerFactory, + const awt::Size* pRefSize ) : + ItemConverter( rPropertySet, rItemPool ) +{ + m_aConverters.emplace_back( new GraphicPropertyItemConverter( + rPropertySet, rItemPool, rDrawModel, + xNamedPropertyContainerFactory, + GraphicObjectType::LineAndFillProperties )); + + // CharacterProperties are not at the title but at its contained XFormattedString objects + // take the first formatted string in the sequence + uno::Reference< chart2::XTitle > xTitle( rPropertySet, uno::UNO_QUERY ); + if( xTitle.is()) + { + uno::Sequence< uno::Reference< chart2::XFormattedString > > aStringSeq( xTitle->getText()); + if( aStringSeq.hasElements() ) + { + m_aConverters.emplace_back( + new FormattedStringsConverter( aStringSeq, rItemPool, pRefSize, rPropertySet )); + } + } +} + +TitleItemConverter::~TitleItemConverter() +{ +} + +void TitleItemConverter::FillItemSet( SfxItemSet & rOutItemSet ) const +{ + for( const auto& pConv : m_aConverters ) + pConv->FillItemSet( rOutItemSet ); + + // own items + ItemConverter::FillItemSet( rOutItemSet ); +} + +bool TitleItemConverter::ApplyItemSet( const SfxItemSet & rItemSet ) +{ + bool bResult = false; + + for( const auto& pConv : m_aConverters ) + bResult = pConv->ApplyItemSet( rItemSet ) || bResult; + + // own items + return ItemConverter::ApplyItemSet( rItemSet ) || bResult; +} + +const WhichRangesContainer& TitleItemConverter::GetWhichPairs() const +{ + // must span all used items! + return nTitleWhichPairs; +} + +bool TitleItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const +{ + ItemPropertyMapType & rMap( lcl_GetTitlePropertyMap()); + ItemPropertyMapType::const_iterator aIt( rMap.find( nWhichId )); + + if( aIt == rMap.end()) + return false; + + rOutProperty =(*aIt).second; + return true; +} + +bool TitleItemConverter::ApplySpecialItem( + sal_uInt16 nWhichId, const SfxItemSet & rItemSet ) +{ + bool bChanged = false; + + switch( nWhichId ) + { + case SCHATTR_TEXT_DEGREES: + { + // convert int to double (divided by 100) + double fVal = static_cast< double >( + static_cast< const SdrAngleItem & >( + rItemSet.Get( nWhichId )).GetValue().get()) / 100.0; + double fOldVal = 0.0; + bool bPropExisted = + ( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fOldVal ); + + if( ! bPropExisted || fOldVal != fVal ) + { + GetPropertySet()->setPropertyValue( "TextRotation" , uno::Any( fVal )); + bChanged = true; + } + } + break; + } + + return bChanged; +} + +void TitleItemConverter::FillSpecialItem( + sal_uInt16 nWhichId, SfxItemSet & rOutItemSet ) const +{ + switch( nWhichId ) + { + case SCHATTR_TEXT_DEGREES: + { + // convert double to int (times 100) + double fVal = 0; + + if( GetPropertySet()->getPropertyValue( "TextRotation" ) >>= fVal ) + { + rOutItemSet.Put( SdrAngleItem( SCHATTR_TEXT_DEGREES, Degree100(static_cast< sal_Int32 >( + ::rtl::math::round( fVal * 100.0 ) ) ))); + } + } + break; + } +} + +} // namespace chart::wrapper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController.cxx b/chart2/source/controller/main/ChartController.cxx new file mode 100644 index 000000000..9174ef885 --- /dev/null +++ b/chart2/source/controller/main/ChartController.cxx @@ -0,0 +1,1688 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ControllerCommandDispatch.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include "ChartDropTargetHelper.hxx" + +#include +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#include +#endif +#include "DrawCommandDispatch.hxx" +#include "ShapeController.hxx" +#include "UndoActions.hxx" +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +// this is needed to properly destroy the unique_ptr to the AcceleratorExecute +// object in the DTOR +#include +#include +#include + +// enable the following define to let the controller listen to model changes and +// react on this by rebuilding the view +#define TEST_ENABLE_MODIFY_LISTENER + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +ChartController::ChartController(uno::Reference const & xContext) : + m_aLifeTimeManager( nullptr ), + m_bSuspended( false ), + m_xCC(xContext), + m_aModel( nullptr, m_aModelMutex ), + m_eDragMode(SdrDragMode::Move), + m_aDoubleClickTimer("chart2 ChartController m_aDoubleClickTimer"), + m_bWaitingForDoubleClick(false), + m_bWaitingForMouseUp(false), + m_bFieldButtonDown(false), + m_bConnectingToView(false), + m_bDisposed(false), + m_aDispatchContainer( m_xCC ), + m_eDrawMode( CHARTDRAW_SELECT ), + mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler( + [this]() { return this->GetContextName(); }, + this, vcl::EnumContext::Context::Cell)) +{ + m_aDoubleClickTimer.SetInvokeHandler( LINK( this, ChartController, DoubleClickWaitingHdl ) ); +} + +ChartController::~ChartController() +{ + stopDoubleClickWaiting(); +} + +ChartController::TheModel::TheModel( const rtl::Reference<::chart::ChartModel> & xModel ) : + m_xModel( xModel ), + m_bOwnership( true ) +{ +} + +ChartController::TheModel::~TheModel() +{ +} + +void ChartController::TheModel::addListener( ChartController* pController ) +{ + if(m_xModel) + { + //if you need to be able to veto against the destruction of the model + // you must add as a close listener + + //otherwise you 'can' add as closelistener or 'must' add as dispose event listener + + m_xModel->addCloseListener( + static_cast(pController) ); + } +} + +void ChartController::TheModel::removeListener( ChartController* pController ) +{ + if(m_xModel) + m_xModel->removeCloseListener( + static_cast(pController) ); +} + +void ChartController::TheModel::tryTermination() +{ + if(!m_bOwnership) + return; + + try + { + if(m_xModel.is()) + { + try + { + //@todo ? are we allowed to use sal_True here if we have the explicit ownership? + //I think yes, because there might be other CloseListeners later in the list which might be interested still + //but make sure that we do not throw the CloseVetoException here ourselves + //so stop listening before trying to terminate or check the source of queryclosing event + m_xModel->close(true); + + m_bOwnership = false; + } + catch( const util::CloseVetoException& ) + { + //since we have indicated to give up the ownership with parameter true in close call + //the one who has thrown the CloseVetoException is the new owner + + SAL_WARN_IF( m_bOwnership, "chart2.main", "a well known owner has caught a CloseVetoException after calling close(true)"); + m_bOwnership = false; + return; + } + + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "chart2", "Termination of model failed" ); + } +} + +ChartController::TheModelRef::TheModelRef( TheModel* pTheModel, osl::Mutex& rMutex ) : + m_rModelMutex(rMutex) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = pTheModel; +} +ChartController::TheModelRef::TheModelRef( const TheModelRef& rTheModel, ::osl::Mutex& rMutex ) : + m_rModelMutex(rMutex) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = rTheModel.m_xTheModel; +} +ChartController::TheModelRef& ChartController::TheModelRef::operator=(TheModel* pTheModel) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = pTheModel; + return *this; +} +ChartController::TheModelRef& ChartController::TheModelRef::operator=(const TheModelRef& rTheModel) +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel = rTheModel.operator->(); + return *this; +} +ChartController::TheModelRef::~TheModelRef() +{ + osl::Guard< osl::Mutex > aGuard( m_rModelMutex ); + m_xTheModel.clear(); +} +bool ChartController::TheModelRef::is() const +{ + return m_xTheModel.is(); +} + +namespace { + +rtl::Reference getChartType(const rtl::Reference& xChartDoc) +{ + rtl::Reference xDiagram = xChartDoc->getFirstChartDiagram(); + if (!xDiagram.is()) + return nullptr; + + const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems()); + if (xCooSysSequence.empty()) + return nullptr; + + return xCooSysSequence[0]->getChartTypes2()[0]; +} + +} + +OUString ChartController::GetContextName() +{ + if (m_bDisposed) + return OUString(); + + uno::Any aAny = getSelection(); + if (!aAny.hasValue()) + return "Chart"; + + OUString aCID; + aAny >>= aCID; + + if (aCID.isEmpty()) + return "Chart"; + + ObjectType eObjectID = ObjectIdentifier::getObjectType(aCID); + switch (eObjectID) + { + case OBJECTTYPE_DATA_SERIES: + return "Series"; + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + return "ErrorBar"; + case OBJECTTYPE_AXIS: + return "Axis"; + case OBJECTTYPE_GRID: + return "Grid"; + case OBJECTTYPE_DIAGRAM: + { + rtl::Reference xChartType = getChartType(getChartModel()); + if (xChartType.is() && xChartType->getChartType() == "com.sun.star.chart2.PieChartType") + return "ChartElements"; + break; + } + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_AVERAGE_LINE: + return "Trendline"; + default: + break; + } + + return "Chart"; +} + +// private methods + +bool ChartController::impl_isDisposedOrSuspended() const +{ + if( m_aLifeTimeManager.impl_isDisposed() ) + return true; + + if( m_bSuspended ) + { + OSL_FAIL( "This Controller is suspended" ); + return true; + } + return false; +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartController::getImplementationName() +{ + return CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartController::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartController::getSupportedServiceNames() +{ + return { + CHART_CONTROLLER_SERVICE_NAME, + "com.sun.star.frame.Controller" + //// @todo : add additional services if you support any further + }; +} + +namespace { + +uno::Reference getSidebarFromModel(const uno::Reference& xModel) +{ + uno::Reference xChild(xModel, uno::UNO_QUERY); + if (!xChild.is()) + return nullptr; + + uno::Reference xParent (xChild->getParent(), uno::UNO_QUERY); + if (!xParent.is()) + return nullptr; + + uno::Reference xController(xParent->getCurrentController(), uno::UNO_QUERY); + if (!xController.is()) + return nullptr; + + uno::Reference xSidebarProvider = xController->getSidebar(); + if (!xSidebarProvider.is()) + return nullptr; + + return xSidebarProvider->getSidebar(); +} + +} + +// XController + +void SAL_CALL ChartController::attachFrame( + const uno::Reference& xFrame ) +{ + SolarMutexGuard aGuard; + + if( impl_isDisposedOrSuspended() ) //@todo? allow attaching the frame while suspended? + return; //behave passive if already disposed or suspended + + if(m_xFrame.is()) //what happens, if we do have a Frame already?? + { + //@todo? throw exception? + OSL_FAIL( "there is already a frame attached to the controller" ); + return; + } + + //--attach frame + m_xFrame = xFrame; //the frameloader is responsible to call xFrame->setComponent + + // Only notify after setting the frame, otherwise notification will fail + mpSelectionChangeHandler->Connect(); + + uno::Reference xSidebar = getSidebarFromModel(getChartModel()); + if (xSidebar.is()) + { + auto pSidebar = dynamic_cast(xSidebar.get()); + assert(pSidebar); + sfx2::sidebar::SidebarController::registerSidebarForFrame(pSidebar, this); + pSidebar->updateModel(getChartModel()); + css::lang::EventObject aEvent; + mpSelectionChangeHandler->selectionChanged(aEvent); + } + + //add as disposelistener to the frame (due to persistent reference) ??...: + + //the frame is considered to be owner of this controller and will live longer than we do + //the frame or the disposer of the frame has the duty to call suspend and dispose on this object + //so we do not need to add as lang::XEventListener for DisposingEvents right? + + //@todo nothing right??? + + //create view @todo is this the correct place here?? + + vcl::Window* pParent = nullptr; + //get the window parent from the frame to use as parent for our new window + if(xFrame.is()) + { + uno::Reference xContainerWindow = xFrame->getContainerWindow(); + if (xContainerWindow) + xContainerWindow->setVisible(true); + pParent = VCLUnoHelper::GetWindow( xContainerWindow ); + } + + { + // calls to VCL + SolarMutexGuard aSolarGuard; + auto pChartWindow = VclPtr::Create(this,pParent,pParent?pParent->GetStyle():0); + pChartWindow->SetBackground();//no Background + m_xViewWindow.set( pChartWindow->GetComponentInterface(), uno::UNO_QUERY ); + pChartWindow->Show(); + m_apDropTargetHelper.reset( + new ChartDropTargetHelper( pChartWindow->GetDropTarget(), getChartModel())); + + impl_createDrawViewController(); + } + + //create the menu + { + uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + try + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + { + xLayoutManager->lock(); + xLayoutManager->requestElement( "private:resource/menubar/menubar" ); + //@todo: createElement should become unnecessary, remove when #i79198# is fixed + xLayoutManager->createElement( "private:resource/toolbar/standardbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/standardbar" ); + //@todo: createElement should become unnecessary, remove when #i79198# is fixed + xLayoutManager->createElement( "private:resource/toolbar/toolbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/toolbar" ); + + // #i12587# support for shapes in chart + xLayoutManager->createElement( "private:resource/toolbar/drawbar" ); + xLayoutManager->requestElement( "private:resource/toolbar/drawbar" ); + + xLayoutManager->requestElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->unlock(); + + // add as listener to get notified when + m_xLayoutManagerEventBroadcaster.set( xLayoutManager, uno::UNO_QUERY ); + if( m_xLayoutManagerEventBroadcaster.is()) + m_xLayoutManagerEventBroadcaster->addLayoutManagerEventListener( this ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } +} + +//XModeChangeListener +void SAL_CALL ChartController::modeChanged( const util::ModeChangeEvent& rEvent ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + //adjust controller to view status changes + + if( rEvent.NewMode == "dirty" ) + { + //the view has become dirty, we should repaint it if we have a window + if( pChartWindow ) + pChartWindow->ForceInvalidate(); + } + else if( rEvent.NewMode == "invalid" ) + { + //the view is about to become invalid so end all actions on it + impl_invalidateAccessible(); + if( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() ) + this->EndTextEdit(); + if( m_pDrawViewWrapper ) + { + m_pDrawViewWrapper->UnmarkAll(); + m_pDrawViewWrapper->HideSdrPage(); + } + } + else + { + //the view was rebuild so we can start some actions on it again + if( !m_bConnectingToView ) + { + if(pChartWindow && m_aModel.is() ) + { + m_bConnectingToView = true; + + GetDrawModelWrapper(); + if(m_pDrawModelWrapper) + { + { + if( m_pDrawViewWrapper ) + m_pDrawViewWrapper->ReInit(); + } + + //reselect object + if( m_aSelection.hasSelection() ) + this->impl_selectObjectAndNotiy(); + else + ChartModelHelper::triggerRangeHighlighting( getChartModel() ); + + impl_initializeAccessible(); + + { + if( pChartWindow ) + pChartWindow->Invalidate(); + } + } + + m_bConnectingToView = false; + } + } + } +} + +sal_Bool SAL_CALL ChartController::attachModel( const uno::Reference< frame::XModel > & xModel ) +{ + impl_invalidateAccessible(); + + //is called to attach the controller to a new model. + //return true if attach was successfully, false otherwise (e.g. if you do not work with a model) + + SolarMutexResettableGuard aGuard; + if( impl_isDisposedOrSuspended() ) //@todo? allow attaching a new model while suspended? + return false; //behave passive if already disposed or suspended + aGuard.clear(); + + ::chart::ChartModel* pChartModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pChartModel); + + TheModelRef aNewModelRef( new TheModel(pChartModel), m_aModelMutex); + TheModelRef aOldModelRef(m_aModel,m_aModelMutex); + m_aModel = aNewModelRef; + + //--handle relations to the old model if any + if( aOldModelRef.is() ) + { + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->removeModeChangeListener(this); + m_pDrawModelWrapper.reset(); + + aOldModelRef->removeListener( this ); + #ifdef TEST_ENABLE_MODIFY_LISTENER + if( aOldModelRef->getModel().is()) + aOldModelRef->getModel()->removeModifyListener( this ); +#endif + } + + //--handle relations to the new model + aNewModelRef->addListener( this ); + + aGuard.reset(); // lock for m_aDispatchContainer access + // set new model at dispatchers + m_aDispatchContainer.setModel( aNewModelRef->getModel()); + rtl::Reference pDispatch = new ControllerCommandDispatch( m_xCC, this, &m_aDispatchContainer ); + pDispatch->initialize(); + + // the dispatch container will return "this" for all commands returned by + // impl_getAvailableCommands(). That means, for those commands dispatch() + // is called here at the ChartController. + m_aDispatchContainer.setChartDispatch( pDispatch, o3tl::sorted_vector(impl_getAvailableCommands()) ); + + rtl::Reference pDrawDispatch = new DrawCommandDispatch( m_xCC, this ); + pDrawDispatch->initialize(); + m_aDispatchContainer.setDrawCommandDispatch( pDrawDispatch.get() ); + + rtl::Reference pShapeController = new ShapeController( m_xCC, this ); + pShapeController->initialize(); + m_aDispatchContainer.setShapeController( pShapeController.get() ); + aGuard.clear(); + +#ifdef TEST_ENABLE_MODIFY_LISTENER + if( aNewModelRef->getModel().is()) + aNewModelRef->getModel()->addModifyListener( this ); +#endif + + // #i119999# Do not do this per default to allow the user to deselect the chart OLE with a single press to ESC + // select chart area per default: + // select( uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, OUString() ) ) ); + + rtl::Reference< ChartModel > xFact = getChartModel(); + if( xFact.is()) + { + m_xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME ); + GetDrawModelWrapper(); + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->addModeChangeListener(this); + } + + //the frameloader is responsible to call xModel->connectController + { + SolarMutexGuard aGuard2; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + pChartWindow->Invalidate(); + } + + m_xUndoManager.set( getChartModel()->getUndoManager(), uno::UNO_SET_THROW ); + + return true; +} + +uno::Reference< frame::XFrame > SAL_CALL ChartController::getFrame() +{ + //provides access to owner frame of this controller + //return the frame containing this controller + + return m_xFrame; +} + +uno::Reference< frame::XModel > SAL_CALL ChartController::getModel() +{ + return getChartModel(); +} + +rtl::Reference<::chart::ChartModel> ChartController::getChartModel() +{ + //provides access to currently attached model + //returns the currently attached model + + //return nothing, if you do not have a model + TheModelRef aModelRef( m_aModel, m_aModelMutex); + if(aModelRef.is()) + return aModelRef->getModel(); + + return nullptr; +} + +rtl::Reference<::chart::Diagram> ChartController::getFirstDiagram() +{ + return ChartModelHelper::findDiagram( getChartModel() ); +} + +uno::Any SAL_CALL ChartController::getViewData() +{ + //provides access to current view status + //set of data that can be used to restore the current view status at later time + // by using XController::restoreViewData() + + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) + return uno::Any(); //behave passive if already disposed or suspended //@todo? or throw an exception?? + + //-- collect current view state + uno::Any aRet; + //// @todo integrate specialized implementation + + return aRet; +} + +void SAL_CALL ChartController::restoreViewData( + const uno::Any& /* Value */ ) +{ + //restores the view status using the data gotten from a previous call to XController::getViewData() + + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) + return; //behave passive if already disposed or suspended //@todo? or throw an exception?? + + //// @todo integrate specialized implementation +} + +sal_Bool SAL_CALL ChartController::suspend( sal_Bool bSuspend ) +{ + //is called to prepare the controller for closing the view + //bSuspend==true: force the controller to suspend his work + //bSuspend==false try to reactivate the controller + //returns true if request was accepted and of course successfully finished, false otherwise + + //we may show dialogs here to ask the user for saving changes ... @todo? + + SolarMutexGuard aGuard; + if( m_aLifeTimeManager.impl_isDisposed() ) + return false; //behave passive if already disposed, return false because request was not accepted //@todo? correct + + if(bool(bSuspend) == m_bSuspended) + { + OSL_FAIL( "new suspend mode equals old suspend mode" ); + return true; + } + + //change suspend mode + m_bSuspended = bSuspend; + return true; +} + +void ChartController::impl_createDrawViewController() +{ + SolarMutexGuard aGuard; + if(!m_pDrawViewWrapper) + { + if( m_pDrawModelWrapper ) + { + bool bLokCalcGlobalRTL = false; + if(comphelper::LibreOfficeKit::isActive() && AllSettings::GetLayoutRTL()) + { + rtl::Reference< ChartModel > xChartModel = getChartModel(); + if (xChartModel.is()) + { + uno::Reference xSSDoc(xChartModel->getParent(), uno::UNO_QUERY); + if (xSSDoc.is()) + bLokCalcGlobalRTL = true; + } + } + + m_pDrawViewWrapper.reset( new DrawViewWrapper(m_pDrawModelWrapper->getSdrModel(),GetChartWindow()->GetOutDev()) ); + m_pDrawViewWrapper->SetNegativeX(bLokCalcGlobalRTL); + m_pDrawViewWrapper->attachParentReferenceDevice( getChartModel() ); + } + } +} + +void ChartController::impl_deleteDrawViewController() +{ + if( m_pDrawViewWrapper ) + { + SolarMutexGuard aGuard; + if( m_pDrawViewWrapper->IsTextEdit() ) + this->EndTextEdit(); + m_pDrawViewWrapper.reset(); + } +} + +// XComponent (base of XController) + +void SAL_CALL ChartController::dispose() +{ + m_bDisposed = true; + + mpSelectionChangeHandler->selectionChanged(css::lang::EventObject()); + mpSelectionChangeHandler->Disconnect(); + + if (getModel().is()) + { + uno::Reference xSidebar = getSidebarFromModel(getChartModel()); + if (sfx2::sidebar::SidebarController* pSidebar = dynamic_cast(xSidebar.get())) + { + sfx2::sidebar::SidebarController::unregisterSidebarForFrame(pSidebar, this); + } + } + + try + { + //This object should release all resources and references in the + //easiest possible manner + //This object must notify all registered listeners using the method + //XEventListener::disposing + + //hold no mutex + if( !m_aLifeTimeManager.dispose() ) + return; + +// OSL_ENSURE( m_bSuspended, "dispose was called but controller is not suspended" ); + + this->stopDoubleClickWaiting(); + + //end range highlighting + if( m_aModel.is()) + { + uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener; + rtl::Reference< ChartModel > xDataReceiver = getChartModel(); + if( xDataReceiver.is() ) + xSelectionChangeListener.set( xDataReceiver->getRangeHighlighter(), uno::UNO_QUERY ); + if( xSelectionChangeListener.is() ) + { + uno::Reference< frame::XController > xController( this ); + lang::EventObject aEvent( xController ); + xSelectionChangeListener->disposing( aEvent ); + } + } + + //--release all resources and references + { + uno::Reference< util::XModeChangeBroadcaster > xViewBroadcaster( m_xChartView, uno::UNO_QUERY ); + if( xViewBroadcaster.is() ) + xViewBroadcaster->removeModeChangeListener(this); + + impl_invalidateAccessible(); + SolarMutexGuard aSolarGuard; + impl_deleteDrawViewController(); + m_pDrawModelWrapper.reset(); + + m_apDropTargetHelper.reset(); + + //the accessible view is disposed within window destructor of m_pChartWindow + if(m_xViewWindow.is()) + m_xViewWindow->dispose(); //ChartWindow is deleted via UNO due to dispose of m_xViewWindow (triggered by Framework (Controller pretends to be XWindow also)) + m_xChartView.clear(); + } + + // remove as listener to layout manager events + if( m_xLayoutManagerEventBroadcaster.is()) + { + m_xLayoutManagerEventBroadcaster->removeLayoutManagerEventListener( this ); + m_xLayoutManagerEventBroadcaster.set( nullptr ); + } + + m_xFrame.clear(); + m_xUndoManager.clear(); + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + m_aModel = nullptr; + + if( aModelRef.is()) + { + uno::Reference< frame::XModel > xModel( aModelRef->getModel() ); + if(xModel.is()) + xModel->disconnectController( uno::Reference< frame::XController >( this )); + + aModelRef->removeListener( this ); +#ifdef TEST_ENABLE_MODIFY_LISTENER + try + { + if( aModelRef->getModel().is()) + aModelRef->getModel()->removeModifyListener( this ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +#endif + aModelRef->tryTermination(); + } + + //// @todo integrate specialized implementation + //e.g. release further resources and references + + SolarMutexGuard g; + m_aDispatchContainer.DisposeAndClear(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + assert(!m_xChartView.is()); + } + } + +void SAL_CALL ChartController::addEventListener( + const uno::Reference& xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--add listener + m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType::get(), xListener ); +} + +void SAL_CALL ChartController::removeEventListener( + const uno::Reference& xListener ) +{ + SolarMutexGuard aGuard; + if( m_aLifeTimeManager.impl_isDisposed(false) ) + return; //behave passive if already disposed or suspended + + //--remove listener + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType::get(), xListener ); +} + +// util::XCloseListener +void SAL_CALL ChartController::queryClosing( + const lang::EventObject& rSource, + sal_Bool /*bGetsOwnership*/ ) +{ + //do not use the m_aControllerMutex here because this call is not allowed to block + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + + if( !aModelRef.is() ) + return; + + if( uno::Reference(static_cast(aModelRef->getModel().get())) != rSource.Source ) + { + OSL_FAIL( "queryClosing was called on a controller from an unknown source" ); + return; + } + + //@ todo prepare to closing model -> don't start any further hindering actions +} + +void SAL_CALL ChartController::notifyClosing( + const lang::EventObject& rSource ) +{ + //Listener should deregister himself and release all references to the closing object. + + TheModelRef aModelRef( m_aModel, m_aModelMutex); + if( !impl_releaseThisModel( rSource.Source ) ) + return; + + //--stop listening to the closing model + aModelRef->removeListener( this ); + + // #i79087# If the model using this controller is closed, the frame is + // expected to be closed as well + Reference< util::XCloseable > xFrameCloseable( m_xFrame, uno::UNO_QUERY ); + if( xFrameCloseable.is()) + { + try + { + xFrameCloseable->close( false /* DeliverOwnership */ ); + m_xFrame.clear(); + } + catch( const util::CloseVetoException & ) + { + // closing was vetoed + } + } +} + +bool ChartController::impl_releaseThisModel( + const uno::Reference< uno::XInterface > & xModel ) +{ + bool bReleaseModel = false; + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aModelMutex ); + if( m_aModel.is() && uno::Reference< uno::XInterface >(static_cast(m_aModel->getModel().get())) == xModel ) + { + m_aModel = nullptr; + m_xUndoManager.clear(); + bReleaseModel = true; + } + } + if( bReleaseModel ) + { + SolarMutexGuard g; + m_aDispatchContainer.setModel( nullptr ); + } + return bReleaseModel; +} + +// util::XEventListener (base of XCloseListener) +void SAL_CALL ChartController::disposing( + const lang::EventObject& rSource ) +{ + if( !impl_releaseThisModel( rSource.Source )) + { + if( rSource.Source == m_xLayoutManagerEventBroadcaster ) + m_xLayoutManagerEventBroadcaster.set( nullptr ); + } +} + +void SAL_CALL ChartController::layoutEvent( + const lang::EventObject& aSource, + sal_Int16 eLayoutEvent, + const uno::Any& /* aInfo */ ) +{ + if( eLayoutEvent == frame::LayoutManagerEvents::MERGEDMENUBAR ) + { + Reference< frame::XLayoutManager > xLM( aSource.Source, uno::UNO_QUERY ); + if( xLM.is()) + { + xLM->createElement( "private:resource/statusbar/statusbar" ); + xLM->requestElement( "private:resource/statusbar/statusbar" ); + } + } +} + +// XDispatchProvider (required interface) + +namespace +{ + +bool lcl_isFormatObjectCommand( std::u16string_view aCommand ) +{ + return aCommand == u"MainTitle" + || aCommand == u"SubTitle" + || aCommand == u"XTitle" + || aCommand == u"YTitle" + || aCommand == u"ZTitle" + || aCommand == u"SecondaryXTitle" + || aCommand == u"SecondaryYTitle" + || aCommand == u"AllTitles" + || aCommand == u"DiagramAxisX" + || aCommand == u"DiagramAxisY" + || aCommand == u"DiagramAxisZ" + || aCommand == u"DiagramAxisA" + || aCommand == u"DiagramAxisB" + || aCommand == u"DiagramAxisAll" + || aCommand == u"DiagramGridXMain" + || aCommand == u"DiagramGridYMain" + || aCommand == u"DiagramGridZMain" + || aCommand == u"DiagramGridXHelp" + || aCommand == u"DiagramGridYHelp" + || aCommand == u"DiagramGridZHelp" + || aCommand == u"DiagramGridAll" + + || aCommand == u"DiagramWall" + || aCommand == u"DiagramFloor" + || aCommand == u"DiagramArea" + || aCommand == u"Legend" + + || aCommand == u"FormatWall" + || aCommand == u"FormatFloor" + || aCommand == u"FormatChartArea" + || aCommand == u"FormatLegend" + + || aCommand == u"FormatTitle" + || aCommand == u"FormatAxis" + || aCommand == u"FormatDataSeries" + || aCommand == u"FormatDataPoint" + || aCommand == u"FormatDataLabels" + || aCommand == u"FormatDataLabel" + || aCommand == u"FormatXErrorBars" + || aCommand == u"FormatYErrorBars" + || aCommand == u"FormatMeanValue" + || aCommand == u"FormatTrendline" + || aCommand == u"FormatTrendlineEquation" + || aCommand == u"FormatStockLoss" + || aCommand == u"FormatStockGain" + || aCommand == u"FormatMajorGrid" + || aCommand == u"FormatMinorGrid"; +} + +} // anonymous namespace + +uno::Reference SAL_CALL + ChartController::queryDispatch( + const util::URL& rURL, + const OUString& rTargetFrameName, + sal_Int32 /* nSearchFlags */) +{ + SolarMutexGuard aGuard; + + if ( !m_aLifeTimeManager.impl_isDisposed() && getModel().is() ) + { + if( !rTargetFrameName.isEmpty() && rTargetFrameName == "_self" ) + return m_aDispatchContainer.getDispatchForURL( rURL ); + } + return uno::Reference< frame::XDispatch > (); +} + +uno::Sequence > + ChartController::queryDispatches( + const uno::Sequence& xDescripts ) +{ + SolarMutexGuard g; + + if ( !m_aLifeTimeManager.impl_isDisposed() ) + { + return m_aDispatchContainer.getDispatchesForURLs( xDescripts ); + } + return uno::Sequence > (); +} + +// frame::XDispatch + +void SAL_CALL ChartController::dispatch( + const util::URL& rURL, + const uno::Sequence< beans::PropertyValue >& rArgs ) +{ + OUString aCommand = rURL.Path; + + if(aCommand == "LOKSetTextSelection") + { + if (rArgs.getLength() == 3) + { + sal_Int32 nType = -1; + rArgs[0].Value >>= nType; + sal_Int32 nX = 0; + rArgs[1].Value >>= nX; + sal_Int32 nY = 0; + rArgs[2].Value >>= nY; + executeDispatch_LOKSetTextSelection(nType, nX, nY); + } + } + else if (aCommand == "LOKTransform") + { + if (rArgs[0].Name == "Action") + { + OUString sAction; + if ((rArgs[0].Value >>= sAction) && sAction == "PieSegmentDragging") + { + if (rArgs[1].Name == "Offset") + { + sal_Int32 nOffset; + if (rArgs[1].Value >>= nOffset) + { + this->executeDispatch_LOKPieSegmentDragging(nOffset); + } + } + } + } + else + { + this->executeDispatch_PositionAndSize(&rArgs); + } + } + else if(aCommand == "FillColor") + { + if (rArgs.getLength() > 0) + { + sal_uInt32 nColor; + if (rArgs[0].Value >>= nColor) + this->executeDispatch_FillColor(nColor); + } + } + else if(aCommand == "XLineColor") + { + if (rArgs.getLength() > 0) + { + sal_Int32 nColor = -1; + rArgs[0].Value >>= nColor; + this->executeDispatch_LineColor(nColor); + } + } + else if(aCommand == "LineWidth") + { + if (rArgs.getLength() > 0) + { + sal_Int32 nWidth = -1; + rArgs[0].Value >>= nWidth; + this->executeDispatch_LineWidth(nWidth); + } + } + else if(aCommand.startsWith("FillGradient")) + { + this->executeDispatch_FillGradient(aCommand.copy(aCommand.indexOf('=') + 1)); + } + else if(aCommand == "Paste") + this->executeDispatch_Paste(); + else if(aCommand == "Copy" ) + this->executeDispatch_Copy(); + else if(aCommand == "Cut" ) + this->executeDispatch_Cut(); + else if(aCommand == "DataRanges" ) + this->executeDispatch_SourceData(); + else if(aCommand == "Update" ) //Update Chart + { + ChartViewHelper::setViewToDirtyState( getChartModel() ); + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + pChartWindow->Invalidate(); + } + else if(aCommand == "DiagramData" ) + this->executeDispatch_EditData(); + //insert objects + else if( aCommand == "InsertTitles" + || aCommand == "InsertMenuTitles") + this->executeDispatch_InsertTitles(); + else if( aCommand == "InsertMenuLegend" ) + this->executeDispatch_OpenLegendDialog(); + else if( aCommand == "InsertLegend" ) + this->executeDispatch_InsertLegend(); + else if( aCommand == "DeleteLegend" ) + this->executeDispatch_DeleteLegend(); + else if( aCommand == "InsertMenuDataLabels" ) + this->executeDispatch_InsertMenu_DataLabels(); + else if( aCommand == "InsertMenuAxes" + || aCommand == "InsertRemoveAxes" ) + this->executeDispatch_InsertAxes(); + else if( aCommand == "InsertMenuGrids" ) + this->executeDispatch_InsertGrid(); + else if( aCommand == "InsertMenuTrendlines" ) + this->executeDispatch_InsertMenu_Trendlines(); + else if( aCommand == "InsertMenuMeanValues" ) + this->executeDispatch_InsertMenu_MeanValues(); + else if( aCommand == "InsertMenuXErrorBars" ) + this->executeDispatch_InsertErrorBars(false); + else if( aCommand == "InsertMenuYErrorBars" ) + this->executeDispatch_InsertErrorBars(true); + else if( aCommand == "InsertSymbol" ) + this->executeDispatch_InsertSpecialCharacter(); + else if( aCommand == "InsertTrendline" ) + this->executeDispatch_InsertTrendline(); + else if( aCommand == "DeleteTrendline" ) + this->executeDispatch_DeleteTrendline(); + else if( aCommand == "InsertMeanValue" ) + this->executeDispatch_InsertMeanValue(); + else if( aCommand == "DeleteMeanValue" ) + this->executeDispatch_DeleteMeanValue(); + else if( aCommand == "InsertXErrorBars" ) + this->executeDispatch_InsertErrorBars(false); + else if( aCommand == "InsertYErrorBars" ) + this->executeDispatch_InsertErrorBars(true); + else if( aCommand == "DeleteXErrorBars" ) + this->executeDispatch_DeleteErrorBars(false); + else if( aCommand == "DeleteYErrorBars" ) + this->executeDispatch_DeleteErrorBars(true); + else if( aCommand == "InsertTrendlineEquation" ) + this->executeDispatch_InsertTrendlineEquation(); + else if( aCommand == "DeleteTrendlineEquation" ) + this->executeDispatch_DeleteTrendlineEquation(); + else if( aCommand == "InsertTrendlineEquationAndR2" ) + this->executeDispatch_InsertTrendlineEquation( true ); + else if( aCommand == "InsertR2Value" ) + this->executeDispatch_InsertR2Value(); + else if( aCommand == "DeleteR2Value") + this->executeDispatch_DeleteR2Value(); + else if( aCommand == "InsertDataLabels" ) + this->executeDispatch_InsertDataLabels(); + else if( aCommand == "InsertDataLabel" ) + this->executeDispatch_InsertDataLabel(); + else if( aCommand == "DeleteDataLabels") + this->executeDispatch_DeleteDataLabels(); + else if( aCommand == "DeleteDataLabel" ) + this->executeDispatch_DeleteDataLabel(); + else if( aCommand == "ResetAllDataPoints" ) + this->executeDispatch_ResetAllDataPoints(); + else if( aCommand == "ResetDataPoint" ) + this->executeDispatch_ResetDataPoint(); + else if( aCommand == "InsertAxis" ) + this->executeDispatch_InsertAxis(); + else if( aCommand == "InsertMajorGrid" ) + this->executeDispatch_InsertMajorGrid(); + else if( aCommand == "InsertMinorGrid" ) + this->executeDispatch_InsertMinorGrid(); + else if( aCommand == "InsertAxisTitle" ) + this->executeDispatch_InsertAxisTitle(); + else if( aCommand == "DeleteAxis" ) + this->executeDispatch_DeleteAxis(); + else if( aCommand == "DeleteMajorGrid") + this->executeDispatch_DeleteMajorGrid(); + else if( aCommand == "DeleteMinorGrid" ) + this->executeDispatch_DeleteMinorGrid(); + //format objects + else if( aCommand == "FormatSelection" ) + this->executeDispatch_ObjectProperties(); + else if( aCommand == "TransformDialog" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_PositionAndSize(); + } + } + else if( lcl_isFormatObjectCommand(aCommand) ) + this->executeDispatch_FormatObject(rURL.Path); + //more format + else if( aCommand == "DiagramType" ) + this->executeDispatch_ChartType(); + else if( aCommand == "View3D" ) + this->executeDispatch_View3D(); + else if ( aCommand == "Forward" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_MoveSeries( true ); + } + } + else if ( aCommand == "Backward" ) + { + if ( isShapeContext() ) + { + this->impl_ShapeControllerDispatch( rURL, rArgs ); + } + else + { + this->executeDispatch_MoveSeries( false ); + } + } + else if( aCommand == "NewArrangement") + this->executeDispatch_NewArrangement(); + else if( aCommand == "ToggleLegend" ) + this->executeDispatch_ToggleLegend(); + else if( aCommand == "ToggleGridHorizontal" ) + this->executeDispatch_ToggleGridHorizontal(); + else if( aCommand == "ToggleGridVertical" ) + this->executeDispatch_ToggleGridVertical(); + else if( aCommand == "ScaleText" ) + this->executeDispatch_ScaleText(); + else if( aCommand == "StatusBarVisible" ) + { + // workaround: this should not be necessary. + uno::Reference< beans::XPropertySet > xPropSet( m_xFrame, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + { + bool bIsVisible( xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" )); + if( bIsVisible ) + { + xLayoutManager->hideElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->destroyElement( "private:resource/statusbar/statusbar" ); + } + else + { + xLayoutManager->createElement( "private:resource/statusbar/statusbar" ); + xLayoutManager->showElement( "private:resource/statusbar/statusbar" ); + } + // @todo: update menu state (checkmark next to "Statusbar"). + } + } + } +} + +void SAL_CALL ChartController::addStatusListener( + const uno::Reference& /* xControl */, + const util::URL& /* aURL */ ) +{ + //@todo +} + +void SAL_CALL ChartController::removeStatusListener( + const uno::Reference& /* xControl */, + const util::URL& /* aURL */ ) +{ + //@todo +} + +// XContextMenuInterception (optional interface) +void SAL_CALL ChartController::registerContextMenuInterceptor( + const uno::Reference< ui::XContextMenuInterceptor >& /* xInterceptor */) +{ + //@todo +} + +void SAL_CALL ChartController::releaseContextMenuInterceptor( + const uno::Reference< ui::XContextMenuInterceptor > & /* xInterceptor */) +{ + //@todo +} + +// ____ XEmbeddedClient ____ +// implementation see: ChartController_EditData.cxx + +void ChartController::executeDispatch_ChartType() +{ + UndoLiveUpdateGuard aUndoGuard( + SchResId( STR_ACTION_EDIT_CHARTTYPE ), m_xUndoManager ); + + SolarMutexGuard aSolarGuard; + //prepare and open dialog + ChartTypeDialog aDlg(GetChartFrame(), getChartModel()); + if (aDlg.run() == RET_OK) + { + impl_adaptDataSeriesAutoResize(); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_SourceData() +{ + //convert properties to ItemSet + rtl::Reference< ::chart::ChartModel > xChartDoc = getChartModel(); + OSL_ENSURE( xChartDoc.is(), "Invalid XChartDocument" ); + if( !xChartDoc.is() ) + return; + + // If there is a data table we should ask user if we really want to destroy it + // and switch to data ranges. + ChartModel& rModel = *xChartDoc; + if ( rModel.hasInternalDataProvider() ) + { + // Check if we will able to create data provider later + css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc( + rModel.getParent(), uno::UNO_QUERY); + if (!xCreatorDoc.is()) + return; + + SolarMutexGuard aSolarGuard; + + std::unique_ptr xQueryBox(Application::CreateMessageDialog(GetChartFrame(), + VclMessageType::Question, VclButtonsType::YesNo, SchResId(STR_DLG_REMOVE_DATA_TABLE))); + // If "No" then just return + if (xQueryBox->run() == RET_NO) + return; + + // Remove data table + rModel.removeDataProviders(); + + // Ask parent document to create new data provider + + uno::Reference< data::XDataProvider > xDataProvider = xCreatorDoc->createDataProvider(); + SAL_WARN_IF( !xDataProvider.is(), "chart2.main", "Data provider was not created" ); + if (xDataProvider.is()) + { + rModel.attachDataProvider(xDataProvider); + } + } + + UndoLiveUpdateGuard aUndoGuard( + SchResId(STR_ACTION_EDIT_DATA_RANGES), m_xUndoManager); + + SolarMutexGuard aSolarGuard; + ::chart::DataSourceDialog aDlg(GetChartFrame(), xChartDoc); + if (aDlg.run() == RET_OK) + { + impl_adaptDataSeriesAutoResize(); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_MoveSeries( bool bForward ) +{ + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + //get selected series + OUString aObjectCID(m_aSelection.getSelectedCID()); + rtl::Reference< DataSeries > xGivenDataSeries = ObjectIdentifier::getDataSeriesForCID( //yyy todo also legend entries and labels? + aObjectCID, getChartModel() ); + + UndoGuardWithSelection aUndoGuard( + ActionDescriptionProvider::createDescription( + (bForward ? ActionDescriptionProvider::ActionType::MoveToTop : ActionDescriptionProvider::ActionType::MoveToBottom), + SchResId(STR_OBJECT_DATASERIES)), + m_xUndoManager ); + + bool bChanged = DiagramHelper::moveSeries( getFirstDiagram(), xGivenDataSeries, bForward ); + if( bChanged ) + { + m_aSelection.setSelection( ObjectIdentifier::getMovedSeriesCID( aObjectCID, bForward ) ); + aUndoGuard.commit(); + } +} + +// ____ XMultiServiceFactory ____ +uno::Reference< uno::XInterface > SAL_CALL + ChartController::createInstance( const OUString& aServiceSpecifier ) +{ + uno::Reference< uno::XInterface > xResult; + +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if( aServiceSpecifier == CHART_ACCESSIBLE_TEXT_SERVICE_NAME ) + xResult.set( impl_createAccessibleTextContext()); +#else + (void)aServiceSpecifier; +#endif + + return xResult; +} + +uno::Reference< uno::XInterface > SAL_CALL + ChartController::createInstanceWithArguments( + const OUString& ServiceSpecifier, + const uno::Sequence< uno::Any >& /* Arguments */ ) +{ + // ignore Arguments + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > SAL_CALL + ChartController::getAvailableServiceNames() +{ + uno::Sequence< OUString > aServiceNames { CHART_ACCESSIBLE_TEXT_SERVICE_NAME }; + return aServiceNames; +} + +// ____ XModifyListener ____ +void SAL_CALL ChartController::modified( + const lang::EventObject& /* aEvent */ ) +{ + // the source can also be a subobject of the ChartModel + // @todo: change the source in ChartModel to always be the model itself ? + //todo? update menu states ? +} + +void ChartController::NotifyUndoActionHdl( std::unique_ptr pUndoAction ) +{ + ENSURE_OR_RETURN_VOID( pUndoAction, "invalid Undo action" ); + + OUString aObjectCID = m_aSelection.getSelectedCID(); + if ( !aObjectCID.isEmpty() ) + return; + + try + { + rtl::Reference< ChartModel > xSuppUndo = getChartModel(); + const Reference< document::XUndoManager > xUndoManager( xSuppUndo->getUndoManager(), uno::UNO_SET_THROW ); + const Reference< document::XUndoAction > xAction( new impl::ShapeUndoElement( std::move(pUndoAction) ) ); + xUndoManager->addUndoAction( xAction ); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +DrawModelWrapper* ChartController::GetDrawModelWrapper() +{ + if( !m_pDrawModelWrapper ) + { + ExplicitValueProvider* pProvider = comphelper::getFromUnoTunnel( m_xChartView ); + if( pProvider ) + m_pDrawModelWrapper = pProvider->getDrawModelWrapper(); + if ( m_pDrawModelWrapper ) + { + m_pDrawModelWrapper->getSdrModel().SetNotifyUndoActionHdl( + std::bind(&ChartController::NotifyUndoActionHdl, this, std::placeholders::_1) ); + } + } + return m_pDrawModelWrapper.get(); +} + +DrawViewWrapper* ChartController::GetDrawViewWrapper() +{ + if ( !m_pDrawViewWrapper ) + { + impl_createDrawViewController(); + } + return m_pDrawViewWrapper.get(); +} + + +ChartWindow* ChartController::GetChartWindow() const +{ + // clients getting the naked VCL Window from UNO should always have the + // solar mutex (and keep it over the lifetime of this ptr), as VCL might + // might deinit otherwise + DBG_TESTSOLARMUTEX(); + if(!m_xViewWindow.is()) + return nullptr; + return dynamic_cast(VCLUnoHelper::GetWindow(m_xViewWindow)); +} + +weld::Window* ChartController::GetChartFrame() +{ + // clients getting the naked VCL Window from UNO should always have the + // solar mutex (and keep it over the lifetime of this ptr), as VCL might + // might deinit otherwise + DBG_TESTSOLARMUTEX(); + return Application::GetFrameWeld(m_xViewWindow); +} + +bool ChartController::isAdditionalShapeSelected() const +{ + return m_aSelection.isAdditionalShapeSelected(); +} + +void ChartController::SetAndApplySelection(const Reference& rxShape) +{ + if(rxShape.is()) + { + m_aSelection.setSelection(rxShape); + m_aSelection.applySelection(GetDrawViewWrapper()); + } +} + + + +uno::Reference< XAccessible > ChartController::CreateAccessible() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + uno::Reference< XAccessible > xResult = new AccessibleChartView( GetDrawViewWrapper() ); + impl_initializeAccessible( uno::Reference< lang::XInitialization >( xResult, uno::UNO_QUERY ) ); + return xResult; +#else + return uno::Reference< XAccessible >(); +#endif +} + +void ChartController::impl_invalidateAccessible() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + Reference< lang::XInitialization > xInit( pChartWindow->GetAccessible(false), uno::UNO_QUERY ); + if(xInit.is()) + { + uno::Sequence< uno::Any > aArguments(3);//empty arguments -> invalid accessible + xInit->initialize(aArguments); + } + } +} +void ChartController::impl_initializeAccessible() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + this->impl_initializeAccessible( Reference< lang::XInitialization >( pChartWindow->GetAccessible(false), uno::UNO_QUERY ) ); +} +void ChartController::impl_initializeAccessible( const uno::Reference< lang::XInitialization >& xInit ) +{ + if(!xInit.is()) + return; + + uno::Reference< XAccessible > xParent; + { + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + vcl::Window* pParentWin( pChartWindow->GetAccessibleParentWindow()); + if( pParentWin ) + xParent.set( pParentWin->GetAccessible()); + } + } + uno::Sequence< uno::Any > aArguments{ uno::Any(uno::Reference(this)), + uno::Any(getModel()), + uno::Any(m_xChartView), + uno::Any(xParent), + uno::Any(m_xViewWindow) }; + + xInit->initialize(aArguments); +} + +const o3tl::sorted_vector< OUString >& ChartController::impl_getAvailableCommands() +{ + static const o3tl::sorted_vector< OUString > s_AvailableCommands { + // commands for container forward + "AddDirect", "NewDoc", "Open", + "Save", "SaveAs", "SendMail", + "EditDoc", "ExportDirectToPDF", "PrintDefault", + + // own commands + "Cut", "Copy", "Paste", + "DataRanges", "DiagramData", + // insert objects + "InsertMenuTitles", "InsertTitles", + "InsertMenuLegend", "InsertLegend", "DeleteLegend", + "InsertMenuDataLabels", + "InsertMenuAxes", "InsertRemoveAxes", "InsertMenuGrids", + "InsertSymbol", + "InsertTrendlineEquation", "InsertTrendlineEquationAndR2", + "InsertR2Value", "DeleteR2Value", + "InsertMenuTrendlines", "InsertTrendline", + "InsertMenuMeanValues", "InsertMeanValue", + "InsertMenuXErrorBars", "InsertXErrorBars", + "InsertMenuYErrorBars", "InsertYErrorBars", + "InsertDataLabels", "InsertDataLabel", + "DeleteTrendline", "DeleteMeanValue", "DeleteTrendlineEquation", + "DeleteXErrorBars", "DeleteYErrorBars", + "DeleteDataLabels", "DeleteDataLabel", + //format objects + "FormatSelection", "TransformDialog", + "DiagramType", "View3D", + "Forward", "Backward", + "MainTitle", "SubTitle", + "XTitle", "YTitle", "ZTitle", + "SecondaryXTitle", "SecondaryYTitle", + "AllTitles", "Legend", + "DiagramAxisX", "DiagramAxisY", "DiagramAxisZ", + "DiagramAxisA", "DiagramAxisB", "DiagramAxisAll", + "DiagramGridXMain", "DiagramGridYMain", "DiagramGridZMain", + "DiagramGridXHelp", "DiagramGridYHelp", "DiagramGridZHelp", + "DiagramGridAll", + "DiagramWall", "DiagramFloor", "DiagramArea", + + //context menu - format objects entries + "FormatWall", "FormatFloor", "FormatChartArea", + "FormatLegend", + + "FormatAxis", "FormatTitle", + "FormatDataSeries", "FormatDataPoint", + "ResetAllDataPoints", "ResetDataPoint", + "FormatDataLabels", "FormatDataLabel", + "FormatMeanValue", "FormatTrendline", "FormatTrendlineEquation", + "FormatXErrorBars", "FormatYErrorBars", + "FormatStockLoss", "FormatStockGain", + + "FormatMajorGrid", "InsertMajorGrid", "DeleteMajorGrid", + "FormatMinorGrid", "InsertMinorGrid", "DeleteMinorGrid", + "InsertAxis", "DeleteAxis", "InsertAxisTitle", + + // toolbar commands + "ToggleGridHorizontal", "ToggleGridVertical", "ToggleLegend", "ScaleText", + "NewArrangement", "Update", + "DefaultColors", "BarWidth", "NumberOfLines", + "ArrangeRow", + "StatusBarVisible", + "ChartElementSelector"}; + return s_AvailableCommands; +} + +ViewElementListProvider ChartController::getViewElementListProvider() +{ + return ViewElementListProvider(m_pDrawModelWrapper.get()); +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartController_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::ChartController(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_EditData.cxx b/chart2/source/controller/main/ChartController_EditData.cxx new file mode 100644 index 000000000..c766c51cc --- /dev/null +++ b/chart2/source/controller/main/ChartController_EditData.cxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include "UndoGuard.hxx" +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +void ChartController::executeDispatch_EditData() +{ + rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel(), uno::UNO_QUERY ); + if (xChartDoc.is()) + { + SolarMutexGuard aSolarGuard; + UndoLiveUpdateGuardWithData aUndoGuard( + SchResId( STR_ACTION_EDIT_CHART_DATA ), + m_xUndoManager ); + DataEditor aDataEditorDialog(GetChartFrame(), xChartDoc, m_xCC); + aDataEditorDialog.run(); + aUndoGuard.commit(); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Insert.cxx b/chart2/source/controller/main/ChartController_Insert.cxx new file mode 100644 index 000000000..4f39f1068 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Insert.cxx @@ -0,0 +1,869 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +void lcl_InsertMeanValueLine( const rtl::Reference< ::chart::DataSeries > & xSeries ) +{ + if( xSeries.is()) + { + ::chart::RegressionCurveHelper::addMeanValueLine( + xSeries, xSeries); + } +} + +} // anonymous namespace + +namespace chart +{ + +void ChartController::executeDispatch_InsertAxes() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXES )), + m_xUndoManager ); + + try + { + InsertAxisOrGridDialogData aDialogInput; + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram ); + AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram ); + + SolarMutexGuard aGuard; + SchAxisDlg aDlg(GetChartFrame(), aDialogInput); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + InsertAxisOrGridDialogData aDialogOutput; + aDlg.getResult(aDialogOutput); + std::unique_ptr< ReferenceSizeProvider > pRefSizeProvider( + impl_createReferenceSizeProvider()); + bool bChanged = AxisHelper::changeVisibilityOfAxes( xDiagram + , aDialogInput.aExistenceList, aDialogOutput.aExistenceList, m_xCC + , pRefSizeProvider.get() ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRIDS )), + m_xUndoManager ); + + try + { + InsertAxisOrGridDialogData aDialogInput; + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + AxisHelper::getAxisOrGridExistence( aDialogInput.aExistenceList, xDiagram, false ); + AxisHelper::getAxisOrGridPossibilities( aDialogInput.aPossibilityList, xDiagram, false ); + + SolarMutexGuard aGuard; + SchGridDlg aDlg(GetChartFrame(), aDialogInput);//aItemSet, b3D, bNet, bSecondaryX, bSecondaryY ); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + InsertAxisOrGridDialogData aDialogOutput; + aDlg.getResult( aDialogOutput ); + bool bChanged = AxisHelper::changeVisibilityOfGrids( xDiagram + , aDialogInput.aExistenceList, aDialogOutput.aExistenceList ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertTitles() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLES )), + m_xUndoManager ); + + try + { + TitleDialogData aDialogInput; + aDialogInput.readFromModel( getChartModel() ); + + SolarMutexGuard aGuard; + SchTitleDlg aDlg(GetChartFrame(), aDialogInput); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + TitleDialogData aDialogOutput(impl_createReferenceSizeProvider()); + aDlg.getResult(aDialogOutput); + bool bChanged = aDialogOutput.writeDifferenceToModel( getChartModel(), m_xCC, &aDialogInput ); + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteLegend() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + LegendHelper::hideLegend(*getChartModel()); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertLegend() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + LegendHelper::showLegend(*getChartModel(), m_xCC); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_OpenLegendDialog() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + + try + { + //prepare and open dialog + SolarMutexGuard aGuard; + SchLegendDlg aDlg(GetChartFrame(), m_xCC); + aDlg.init( getChartModel() ); + if (aDlg.run() == RET_OK) + { + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aDlg.writeToModel( getChartModel() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMenu_DataLabels() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + + //if a series is selected insert labels for that series only: + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel()); + if( xSeries.is() ) + { + // add labels + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries ); + + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + OUString aObjectCID = ObjectIdentifier::createClassifiedIdentifierForParticles( + ObjectIdentifier::getSeriesParticleFromCID(m_aSelection.getSelectedCID()), aChildParticle ); + + bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, true ); + if( bSuccess ) + aUndoGuard.commit(); + return; + } + + try + { + wrapper::AllDataLabelItemConverter aItemConverter( + getChartModel(), + m_pDrawModelWrapper->GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + + //prepare and open dialog + SolarMutexGuard aGuard; + + //get number formatter + NumberFormatterWrapper aNumberFormatterWrapper( getChartModel() ); + SvNumberFormatter* pNumberFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + + DataLabelsDialog aDlg(GetChartFrame(), aItemSet, pNumberFormatter); + + if (aDlg.run() == RET_OK) + { + SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet(); + aDlg.FillItemSet(aOutItemSet); + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMeanValue() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + lcl_InsertMeanValueLine( ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), + getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertMenu_MeanValues() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + //if a series is selected insert mean value only for that series: + lcl_InsertMeanValueLine( xSeries ); + } + else + { + std::vector< rtl::Reference< DataSeries > > aSeries = + DiagramHelper::getDataSeriesFromDiagram( getFirstDiagram()); + + for( const auto& xSrs : aSeries ) + lcl_InsertMeanValueLine( xSrs ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertMenu_Trendlines() +{ + OUString aCID = m_aSelection.getSelectedCID(); + + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() ); + + if( !xSeries.is() ) + return; + + executeDispatch_InsertTrendline(); +} + +void ChartController::executeDispatch_InsertTrendline() +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel()); + + if( !xRegressionCurveContainer.is() ) + return; + + UndoLiveUpdateGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + + rtl::Reference< RegressionCurveModel > xCurve = + RegressionCurveHelper::addRegressionCurve( + SvxChartRegress::Linear, + xRegressionCurveContainer ); + + if( !xCurve.is()) + return; + + wrapper::RegressionCurveItemConverter aItemConverter( + xCurve, xRegressionCurveContainer, m_pDrawModelWrapper->getSdrModel().GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + + // open dialog + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + ObjectPropertiesDialogParameter aDialogParameter( + ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( m_aSelection.getSelectedCID()), + RegressionCurveHelper::getRegressionCurveIndex( xRegressionCurveContainer, xCurve ), false )); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get()); + SolarMutexGuard aGuard; + SchAttribTabDlg aDialog( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + + // note: when a user pressed "OK" but didn't change any settings in the + // dialog, the SfxTabDialog returns "Cancel" + if( aDialog.run() == RET_OK || aDialog.DialogWasClosedWithOK()) + { + const SfxItemSet* pOutItemSet = aDialog.GetOutputItemSet(); + if( pOutItemSet ) + { + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aItemConverter.ApplyItemSet( *pOutItemSet ); + } + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertErrorBars( bool bYError ) +{ + ObjectType objType = bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X; + + //if a series is selected insert error bars for that series only: + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + + if( xSeries.is()) + { + UndoLiveUpdateGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, + SchResId( bYError ? STR_OBJECT_ERROR_BARS_Y : STR_OBJECT_ERROR_BARS_X )), + m_xUndoManager ); + + // add error bars with standard deviation + uno::Reference< beans::XPropertySet > xErrorBarProp( + StatisticsHelper::addErrorBars( xSeries, + css::chart::ErrorBarStyle::STANDARD_DEVIATION, + bYError)); + + // get an appropriate item converter + wrapper::ErrorBarItemConverter aItemConverter( + getChartModel(), xErrorBarProp, m_pDrawModelWrapper->getSdrModel().GetItemPool(), + m_pDrawModelWrapper->getSdrModel(), + getChartModel() ); + + // open dialog + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE,bYError)); + aItemConverter.FillItemSet( aItemSet ); + ObjectPropertiesDialogParameter aDialogParameter( + ObjectIdentifier::createClassifiedIdentifierWithParent( + objType, u"", m_aSelection.getSelectedCID())); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get()); + SolarMutexGuard aGuard; + SchAttribTabDlg aDlg( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), + m_xChartView, m_aSelection.getSelectedCID())); + + // note: when a user pressed "OK" but didn't change any settings in the + // dialog, the SfxTabDialog returns "Cancel" + if (aDlg.run() == RET_OK || aDlg.DialogWasClosedWithOK()) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if( pOutItemSet ) + { + ControllerLockGuardUNO aCLGuard( getChartModel() ); + aItemConverter.ApplyItemSet( *pOutItemSet ); + } + aUndoGuard.commit(); + } + } + else + { + //if no series is selected insert error bars for all series + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, + ObjectNameProvider::getName_ObjectForAllSeries( objType ) ), + m_xUndoManager ); + + try + { + wrapper::AllSeriesStatisticsConverter aItemConverter( + getChartModel(), m_pDrawModelWrapper->GetItemPool() ); + SfxItemSet aItemSet = aItemConverter.CreateEmptyItemSet(); + aItemConverter.FillItemSet( aItemSet ); + + //prepare and open dialog + SolarMutexGuard aGuard; + InsertErrorBarsDialog aDlg( + GetChartFrame(), aItemSet, + getChartModel(), + bYError ? ErrorBarResources::ERROR_BAR_Y : ErrorBarResources::ERROR_BAR_X); + + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), m_xChartView, OUString() ) ); + + if (aDlg.run() == RET_OK) + { + SfxItemSet aOutItemSet = aItemConverter.CreateEmptyItemSet(); + aDlg.FillItemSet( aOutItemSet ); + + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bChanged = aItemConverter.ApplyItemSet( aOutItemSet );//model should be changed now + if( bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } +} + +void ChartController::executeDispatch_InsertTrendlineEquation( bool bInsertR2 ) +{ + uno::Reference< chart2::XRegressionCurve > xRegCurve( + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ), uno::UNO_QUERY ); + if( !xRegCurve.is() ) + { + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + xRegCurve.set( RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCurveCnt ) ); + } + if( !xRegCurve.is()) + return; + + uno::Reference< beans::XPropertySet > xEqProp( xRegCurve->getEquationProperties()); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowEquation", uno::Any( true )); + xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") )); + xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") )); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( bInsertR2 )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertR2Value() +{ + uno::Reference< beans::XPropertySet > xEqProp = + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( true )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteR2Value() +{ + uno::Reference< beans::XPropertySet > xEqProp = + ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ); + if( xEqProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false )); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteMeanValue() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteTrendline() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + RegressionCurveHelper::removeAllExceptMeanValueLine( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteTrendlineEquation() +{ + rtl::Reference< DataSeries > xRegCurveCnt = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + RegressionCurveHelper::removeEquations( xRegCurveCnt ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteErrorBars( bool bYError ) +{ + rtl::Reference< DataSeries > xDataSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xDataSeries.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + m_xUndoManager ); + StatisticsHelper::removeErrorBars( xDataSeries, bYError ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertDataLabels() +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert, + SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints( xSeries ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_InsertDataLabel() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Insert, + SchResId( STR_OBJECT_LABEL )), + m_xUndoManager ); + DataSeriesHelper::insertDataLabelToPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_DeleteDataLabels() +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete, + SchResId( STR_OBJECT_DATALABELS )), + m_xUndoManager ); + DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints( xSeries ); + aUndoGuard.commit(); + } +} + +void ChartController::executeDispatch_DeleteDataLabel() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Delete, + SchResId( STR_OBJECT_LABEL )), + m_xUndoManager ); + DataSeriesHelper::deleteDataLabelsFromPoint( ObjectIdentifier::getObjectPropertySet( m_aSelection.getSelectedCID(), getChartModel() ) ); + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ResetAllDataPoints() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format, + SchResId( STR_OBJECT_DATAPOINTS )), + m_xUndoManager ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + xSeries->resetAllDataPoints(); + aUndoGuard.commit(); +} +void ChartController::executeDispatch_ResetDataPoint() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( ActionDescriptionProvider::ActionType::Format, + SchResId( STR_OBJECT_DATAPOINT )), + m_xUndoManager ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xSeries.is() ) + { + sal_Int32 nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() ); + xSeries->resetDataPoint( nPointIndex ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_InsertAxisTitle() +{ + try + { + uno::Reference< XTitle > xTitle; + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_TITLE )), + m_xUndoManager ); + + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, getFirstDiagram(), nCooSysIndex, nDimensionIndex, nAxisIndex ); + + TitleHelper::eTitleType eTitleType = TitleHelper::X_AXIS_TITLE; + if( nDimensionIndex==0 ) + eTitleType = nAxisIndex==0 ? TitleHelper::X_AXIS_TITLE : TitleHelper::SECONDARY_X_AXIS_TITLE; + else if( nDimensionIndex==1 ) + eTitleType = nAxisIndex==0 ? TitleHelper::Y_AXIS_TITLE : TitleHelper::SECONDARY_Y_AXIS_TITLE; + else + eTitleType = TitleHelper::Z_AXIS_TITLE; + + std::unique_ptr< ReferenceSizeProvider > apRefSizeProvider( impl_createReferenceSizeProvider()); + xTitle = TitleHelper::createTitle( eTitleType, ObjectNameProvider::getTitleNameByType(eTitleType), getChartModel(), m_xCC, apRefSizeProvider.get() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertAxis() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_AXIS )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeAxisVisible( xAxis ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteAxis() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AXIS )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeAxisInvisible( xAxis ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMajorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteMajorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + AxisHelper::makeGridInvisible( xAxis->getGridProperties() ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_InsertMinorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Insert, SchResId( STR_OBJECT_GRID )), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & props : aSubGrids) + AxisHelper::makeGridVisible( props ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_DeleteMinorGrid() +{ + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId(STR_OBJECT_GRID)), + m_xUndoManager ); + + try + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() ) + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & props : aSubGrids) + AxisHelper::makeGridInvisible( props ); + aUndoGuard.commit(); + } + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Position.cxx b/chart2/source/controller/main/ChartController_Position.cxx new file mode 100644 index 000000000..dc8941587 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Position.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +static void lcl_getPositionAndSizeFromItemSet( const SfxItemSet& rItemSet, awt::Rectangle& rPosAndSize, const awt::Size& rOriginalSize ) +{ + tools::Long nPosX(0); + tools::Long nPosY(0); + tools::Long nSizX(0); + tools::Long nSizY(0); + + RectPoint eRP = RectPoint::LT; + + //read position + if (const SfxInt32Item* pPosXItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_X)) + nPosX = pPosXItem->GetValue(); + if (const SfxInt32Item* pPosYItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_POS_Y)) + nPosY = pPosYItem->GetValue(); + //read size + if (const SfxUInt32Item* pWidthItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_WIDTH)) + nSizX = pWidthItem->GetValue(); + if (const SfxUInt32Item* pHeightItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_HEIGHT)) + nSizY = pHeightItem->GetValue(); + if (const SfxUInt16Item* pSizeItem = rItemSet.GetItemIfSet(SID_ATTR_TRANSFORM_SIZE_POINT)) + eRP=static_cast(pSizeItem->GetValue()); + + switch( eRP ) + { + case RectPoint::LT: + break; + case RectPoint::MT: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + break; + case RectPoint::RT: + nPosX += rOriginalSize.Width - nSizX; + break; + case RectPoint::LM: + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::MM: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::RM: + nPosX += rOriginalSize.Width - nSizX; + nPosY += ( rOriginalSize.Height - nSizY ) / 2; + break; + case RectPoint::LB: + nPosY += rOriginalSize.Height - nSizY; + break; + case RectPoint::MB: + nPosX += ( rOriginalSize.Width - nSizX ) / 2; + nPosY += rOriginalSize.Height - nSizY; + break; + case RectPoint::RB: + nPosX += rOriginalSize.Width - nSizX; + nPosY += rOriginalSize.Height - nSizY; + break; + default: + break; + } + + rPosAndSize = awt::Rectangle(nPosX,nPosY,nSizX,nSizY); +} + +void ChartController::executeDispatch_PositionAndSize(const ::css::uno::Sequence< ::css::beans::PropertyValue >* pArgs) +{ + const OUString aCID( m_aSelection.getSelectedCID() ); + + if( aCID.isEmpty() ) + return; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); + + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::PosSize, + ObjectNameProvider::getName( eObjectType)), + m_xUndoManager ); + + try + { + SfxItemSet aItemSet = m_pDrawViewWrapper->getPositionAndSizeItemSetFromMarkedObject(); + const SfxItemSet* pOutItemSet = nullptr; + if (!pArgs) + { + //prepare and open dialog + SdrView* pSdrView = m_pDrawViewWrapper.get(); + bool bResizePossible = m_aSelection.isResizeableObjectSelected(); + + SolarMutexGuard aGuard; + SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr pDlg(pFact->CreateSchTransformTabDialog( + GetChartFrame(), &aItemSet, pSdrView, bResizePossible)); + + if( pDlg->Execute() == RET_OK ) + { + pOutItemSet = pDlg->GetOutputItemSet(); + if (pOutItemSet) + aItemSet.Put(*pOutItemSet);//overwrite old values with new values (-> all items are set) + } + } + else + { + const SfxItemPool* pPool = aItemSet.GetPool(); + if (!pPool) + return; + + for (const auto& aProp: *pArgs) + { + sal_Int32 nValue = 0; + aProp.Value >>= nValue; + if (aProp.Name == "TransformPosX") { + aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_X, nValue)); + } + else if (aProp.Name == "TransformPosY") { + aItemSet.Put(SfxInt32Item(SID_ATTR_TRANSFORM_POS_Y, nValue)); + } + else if (aProp.Name == "TransformWidth") { + aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_WIDTH, static_cast(nValue))); + } + else if (aProp.Name == "TransformHeight") { + aItemSet.Put(SfxUInt32Item(SID_ATTR_TRANSFORM_HEIGHT, static_cast(nValue))); + } + } + } + + if(pOutItemSet || pArgs) + { + awt::Rectangle aOldObjectRect; + ExplicitValueProvider* pProvider(comphelper::getFromUnoTunnel( m_xChartView )); + if( pProvider ) + aOldObjectRect = pProvider->getRectangleOfObject(aCID); + + awt::Rectangle aNewObjectRect; + lcl_getPositionAndSizeFromItemSet( aItemSet, aNewObjectRect, ToSize(aOldObjectRect) ); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + awt::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height ); + + bool bChanged = false; + if ( eObjectType == OBJECTTYPE_LEGEND ) + { + bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), false , true); + } + + bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID(), getChartModel() + , aNewObjectRect, aOldObjectRect, aPageRect ); + if( bMoved || bChanged ) + aUndoGuard.commit(); + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Properties.cxx b/chart2/source/controller/main/ChartController_Properties.cxx new file mode 100644 index 000000000..1b72833f9 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Properties.cxx @@ -0,0 +1,826 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace +{ + +wrapper::ItemConverter* createItemConverter( + const OUString & aObjectCID, const rtl::Reference<::chart::ChartModel>& xChartModel, + const uno::Reference& xContext, SdrModel& rDrawModel, + ExplicitValueProvider* pExplicitValueProvider, ReferenceSizeProvider const * pRefSizeProvider ) +{ + wrapper::ItemConverter* pItemConverter=nullptr; + + //get type of selected object + ObjectType eObjectType = ObjectIdentifier::getObjectType( aObjectCID ); + if( eObjectType==OBJECTTYPE_UNKNOWN ) + { + OSL_FAIL("unknown ObjectType"); + return nullptr; + } + + std::u16string_view aParticleID = ObjectIdentifier::getParticleID( aObjectCID ); + bool bAffectsMultipleObjects = aParticleID == u"ALLELEMENTS"; + if( !bAffectsMultipleObjects ) + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( aObjectCID, xChartModel ); + if(!xObjectProperties.is()) + return nullptr; + //create itemconverter for a single object + switch(eObjectType) + { + case OBJECTTYPE_PAGE: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + case OBJECTTYPE_TITLE: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::TitleItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + } + break; + case OBJECTTYPE_LEGEND: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::LegendItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + } + break; + case OBJECTTYPE_LEGEND_ENTRY: + break; + case OBJECTTYPE_DIAGRAM: + break; + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_DIAGRAM_FLOOR: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + case OBJECTTYPE_AXIS: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + // the second property set contains the property CoordinateOrigin + // nOriginIndex is the index of the corresponding index of the + // origin (x=0, y=1, z=2) + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + if( pExplicitValueProvider ) + pExplicitValueProvider->getExplicitValuesForAxis( + uno::Reference< XAxis >( xObjectProperties, uno::UNO_QUERY ), + aExplicitScale, aExplicitIncrement ); + + pItemConverter = new wrapper::AxisItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, + xChartModel, + &aExplicitScale, &aExplicitIncrement, + pRefSize.get() ); + } + break; + case OBJECTTYPE_AXIS_UNITLABEL: + break; + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + rtl::Reference xSeries = ObjectIdentifier::getDataSeriesForCID(aObjectCID, xChartModel); + + bool bDataSeries = eObjectType == OBJECTTYPE_DATA_LABELS; + + sal_Int32 nNumberFormat = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties ); + sal_Int32 nPercentNumberFormat = ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + xObjectProperties, xChartModel); + + pItemConverter = new wrapper::TextLabelItemConverter( + xChartModel, xObjectProperties, xSeries, + rDrawModel.GetItemPool(), pRefSize.get(), bDataSeries, + nNumberFormat, nPercentNumberFormat); + } + break; + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_DATA_POINT: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + wrapper::GraphicObjectType eMapTo = + wrapper::GraphicObjectType::FilledDataPoint; + + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ); + rtl::Reference< ChartType > xChartType = ChartModelHelper::getChartTypeOfSeries( xChartModel, xSeries ); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if( !ChartTypeHelper::isSupportingAreaProperties( xChartType, nDimensionCount ) ) + eMapTo = wrapper::GraphicObjectType::LineDataPoint; + + bool bDataSeries = eObjectType == OBJECTTYPE_DATA_SERIES; + + //special color for pie chart: + bool bUseSpecialFillColor = false; + sal_Int32 nSpecialFillColor =0; + sal_Int32 nPointIndex = -1; /*-1 for whole series*/ + if(!bDataSeries) + { + nPointIndex = o3tl::toInt32(aParticleID); + bool bVaryColorsByPoint = false; + if( xSeries.is() && + (xSeries->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint) && + bVaryColorsByPoint ) + { + if( !ColorPerPointHelper::hasPointOwnColor( xSeries, nPointIndex, xObjectProperties ) ) + { + bUseSpecialFillColor = true; + OSL_ASSERT( xDiagram.is()); + uno::Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme() ); + if( xColorScheme.is()) + nSpecialFillColor = xColorScheme->getColorByIndex( nPointIndex ); + } + } + } + sal_Int32 nNumberFormat=ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( xObjectProperties ); + sal_Int32 nPercentNumberFormat=ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + xObjectProperties, xChartModel); + + pItemConverter = new wrapper::DataPointItemConverter( xChartModel, xContext, + xObjectProperties, xSeries, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + eMapTo, pRefSize.get(), bDataSeries, bUseSpecialFillColor, nSpecialFillColor, true, + nNumberFormat, nPercentNumberFormat, nPointIndex ); + break; + } + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + case OBJECTTYPE_DATA_AVERAGE_LINE: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineProperties ); + break; + + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + pItemConverter = new wrapper::ErrorBarItemConverter( + xChartModel, xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + + case OBJECTTYPE_DATA_CURVE: + pItemConverter = new wrapper::RegressionCurveItemConverter( + xObjectProperties, + ObjectIdentifier::getDataSeriesForCID( aObjectCID, xChartModel ), + rDrawModel.GetItemPool(), rDrawModel, + xChartModel); + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset(new awt::Size(pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::RegressionEquationItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), rDrawModel, + xChartModel, + pRefSize.get()); + break; + } + case OBJECTTYPE_DATA_STOCK_RANGE: + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + case OBJECTTYPE_DATA_STOCK_GAIN: + pItemConverter = new wrapper::GraphicPropertyItemConverter( + xObjectProperties, rDrawModel.GetItemPool(), + rDrawModel, xChartModel, + wrapper::GraphicObjectType::LineAndFillProperties ); + break; + default: //OBJECTTYPE_UNKNOWN + break; + } + } + else + { + //create itemconverter for all objects of given type + switch(eObjectType) + { + case OBJECTTYPE_TITLE: + pItemConverter = new wrapper::AllTitleItemConverter( xChartModel, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + case OBJECTTYPE_AXIS: + { + std::unique_ptr pRefSize; + if (pRefSizeProvider) + pRefSize.reset( new awt::Size( pRefSizeProvider->getPageSize())); + + pItemConverter = new wrapper::AllAxisItemConverter( + xChartModel, rDrawModel.GetItemPool(), + rDrawModel, pRefSize.get()); + } + break; + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + pItemConverter = new wrapper::AllGridItemConverter( xChartModel, rDrawModel.GetItemPool(), + rDrawModel, xChartModel); + break; + default: //for this type it is not supported to change all elements at once + break; + } + + } + return pItemConverter; +} + +OUString lcl_getTitleCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartModel ) +{ + if( rDispatchCommand == "AllTitles") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_TITLE, u"ALLELEMENTS" ); + + TitleHelper::eTitleType nTitleType( TitleHelper::MAIN_TITLE ); + if( rDispatchCommand == "SubTitle" ) + nTitleType = TitleHelper::SUB_TITLE; + else if( rDispatchCommand == "XTitle" ) + nTitleType = TitleHelper::X_AXIS_TITLE; + else if( rDispatchCommand == "YTitle" ) + nTitleType = TitleHelper::Y_AXIS_TITLE; + else if( rDispatchCommand == "ZTitle" ) + nTitleType = TitleHelper::Z_AXIS_TITLE; + else if( rDispatchCommand == "SecondaryXTitle" ) + nTitleType = TitleHelper::SECONDARY_X_AXIS_TITLE; + else if( rDispatchCommand == "SecondaryYTitle" ) + nTitleType = TitleHelper::SECONDARY_Y_AXIS_TITLE; + + uno::Reference< XTitle > xTitle( TitleHelper::getTitle( nTitleType, xChartModel ) ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xTitle, xChartModel ); +} + +OUString lcl_getAxisCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( rDispatchCommand == "DiagramAxisAll") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_AXIS, u"ALLELEMENTS" ); + + sal_Int32 nDimensionIndex=0; + bool bMainAxis=true; + if( rDispatchCommand == "DiagramAxisX") + { + nDimensionIndex=0; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisY") + { + nDimensionIndex=1; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisZ") + { + nDimensionIndex=2; bMainAxis=true; + } + else if( rDispatchCommand == "DiagramAxisA") + { + nDimensionIndex=0; bMainAxis=false; + } + else if( rDispatchCommand == "DiagramAxisB") + { + nDimensionIndex=1; bMainAxis=false; + } + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartModel ); +} + +OUString lcl_getGridCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + + if( rDispatchCommand == "DiagramGridAll") + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_GRID, u"ALLELEMENTS" ); + + sal_Int32 nDimensionIndex=0; + bool bMainGrid=true; + + //x and y is swapped in the commands + + if( rDispatchCommand == "DiagramGridYMain") + { + nDimensionIndex=0; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridXMain") + { + nDimensionIndex=1; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridZMain") + { + nDimensionIndex=2; bMainGrid=true; + } + else if( rDispatchCommand == "DiagramGridYHelp") + { + nDimensionIndex=0; bMainGrid=false; + } + else if( rDispatchCommand == "DiagramGridXHelp") + { + nDimensionIndex=1; bMainGrid=false; + } + else if( rDispatchCommand == "DiagramGridZHelp") + { + nDimensionIndex=2; bMainGrid=false; + } + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, true/*bMainAxis*/, xDiagram ); + + sal_Int32 nSubGridIndex= bMainGrid ? -1 : 0; + OUString aCID( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartModel, nSubGridIndex ) ); + return aCID; +} + +OUString lcl_getErrorCIDForCommand( const ObjectType eDispatchType, const ObjectType &eSelectedType, const OUString &rSelectedCID) +{ + if( eSelectedType == eDispatchType ) + return rSelectedCID; + + return ObjectIdentifier::createClassifiedIdentifierWithParent( eDispatchType, u"", rSelectedCID ); +} + +OUString lcl_getObjectCIDForCommand( std::string_view rDispatchCommand, const rtl::Reference<::chart::ChartModel> & xChartDocument, const OUString& rSelectedCID ) +{ + ObjectType eObjectType = OBJECTTYPE_UNKNOWN; + + const ObjectType eSelectedType = ObjectIdentifier::getObjectType( rSelectedCID ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rSelectedCID, xChartDocument ); + + //legend + if( rDispatchCommand == "Legend" || rDispatchCommand == "FormatLegend" ) + { + eObjectType = OBJECTTYPE_LEGEND; + //@todo set particular aParticleID if we have more than one legend + } + //wall floor area + else if( rDispatchCommand == "DiagramWall" || rDispatchCommand == "FormatWall" ) + { + //OBJECTTYPE_DIAGRAM; + eObjectType = OBJECTTYPE_DIAGRAM_WALL; + //@todo set particular aParticleID if we have more than one diagram + } + else if( rDispatchCommand == "DiagramFloor" || rDispatchCommand == "FormatFloor" ) + { + eObjectType = OBJECTTYPE_DIAGRAM_FLOOR; + //@todo set particular aParticleID if we have more than one diagram + } + else if( rDispatchCommand == "DiagramArea" || rDispatchCommand == "FormatChartArea" ) + { + eObjectType = OBJECTTYPE_PAGE; + } + //title + else if( rDispatchCommand == "MainTitle" + || rDispatchCommand == "SubTitle" + || rDispatchCommand == "XTitle" + || rDispatchCommand == "YTitle" + || rDispatchCommand == "ZTitle" + || rDispatchCommand == "SecondaryXTitle" + || rDispatchCommand == "SecondaryYTitle" + || rDispatchCommand == "AllTitles" + ) + { + return lcl_getTitleCIDForCommand( rDispatchCommand, xChartDocument ); + } + //axis + else if( rDispatchCommand == "DiagramAxisX" + || rDispatchCommand == "DiagramAxisY" + || rDispatchCommand == "DiagramAxisZ" + || rDispatchCommand == "DiagramAxisA" + || rDispatchCommand == "DiagramAxisB" + || rDispatchCommand == "DiagramAxisAll" + ) + { + return lcl_getAxisCIDForCommand( rDispatchCommand, xChartDocument ); + } + //grid + else if( rDispatchCommand == "DiagramGridYMain" + || rDispatchCommand == "DiagramGridXMain" + || rDispatchCommand == "DiagramGridZMain" + || rDispatchCommand == "DiagramGridYHelp" + || rDispatchCommand == "DiagramGridXHelp" + || rDispatchCommand == "DiagramGridZHelp" + || rDispatchCommand == "DiagramGridAll" + ) + { + return lcl_getGridCIDForCommand( rDispatchCommand, xChartDocument ); + } + //data series + else if( rDispatchCommand == "FormatDataSeries" ) + { + if( eSelectedType == OBJECTTYPE_DATA_SERIES ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_SERIES, ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ) ); + } + //data point + else if( rDispatchCommand == "FormatDataPoint" ) + { + return rSelectedCID; + } + //data labels + else if( rDispatchCommand == "FormatDataLabels" ) + { + if( eSelectedType == OBJECTTYPE_DATA_LABELS ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABELS, u"", rSelectedCID ); + } + //data labels + else if( rDispatchCommand == "FormatDataLabel" ) + { + if( eSelectedType == OBJECTTYPE_DATA_LABEL ) + return rSelectedCID; + else + { + sal_Int32 nPointIndex = o3tl::toInt32(ObjectIdentifier::getParticleID( rSelectedCID )); + if( nPointIndex>=0 ) + { + OUString aSeriesParticle = ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ); + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + OUString aLabelsCID = ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ); + OUString aLabelCID_Stub = ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_LABEL, u"", aLabelsCID ); + + return ObjectIdentifier::createPointCID( aLabelCID_Stub, nPointIndex ); + } + } + } + //mean value line + else if( rDispatchCommand == "FormatMeanValue" ) + { + if( eSelectedType == OBJECTTYPE_DATA_AVERAGE_LINE ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getMeanValueLine( xSeries ) ), true ); + } + //trend line + else if( rDispatchCommand == "FormatTrendline" ) + { + if( eSelectedType == OBJECTTYPE_DATA_CURVE ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ), false ); + } + //trend line equation + else if( rDispatchCommand == "FormatTrendlineEquation" ) + { + if( eSelectedType == OBJECTTYPE_DATA_CURVE_EQUATION ) + return rSelectedCID; + else + return ObjectIdentifier::createDataCurveEquationCID( + ObjectIdentifier::getSeriesParticleFromCID( rSelectedCID ), + RegressionCurveHelper::getRegressionCurveIndex( xSeries, + RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ) ) ); + } + // y error bars + else if( rDispatchCommand == "FormatXErrorBars" ) + { + return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_X, eSelectedType, rSelectedCID ); + } + // y error bars + else if( rDispatchCommand == "FormatYErrorBars" ) + { + return lcl_getErrorCIDForCommand(OBJECTTYPE_DATA_ERRORS_Y, eSelectedType, rSelectedCID ); + } + // axis + else if( rDispatchCommand == "FormatAxis" ) + { + if( eSelectedType == OBJECTTYPE_AXIS ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForObject( xAxis , xChartDocument ); + } + } + // major grid + else if( rDispatchCommand == "FormatMajorGrid" ) + { + if( eSelectedType == OBJECTTYPE_GRID ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument ); + } + + } + // minor grid + else if( rDispatchCommand == "FormatMinorGrid" ) + { + if( eSelectedType == OBJECTTYPE_SUBGRID ) + return rSelectedCID; + else + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( rSelectedCID, xChartDocument ); + return ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDocument, 0 /*sub grid index*/ ); + } + } + // title + else if( rDispatchCommand == "FormatTitle" ) + { + if( eSelectedType == OBJECTTYPE_TITLE ) + return rSelectedCID; + } + // stock loss + else if( rDispatchCommand == "FormatStockLoss" ) + { + if( eSelectedType == OBJECTTYPE_DATA_STOCK_LOSS ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_LOSS, u""); + } + // stock gain + else if( rDispatchCommand == "FormatStockGain" ) + { + if( eSelectedType == OBJECTTYPE_DATA_STOCK_GAIN ) + return rSelectedCID; + else + return ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DATA_STOCK_GAIN, u"" ); + } + + return ObjectIdentifier::createClassifiedIdentifier( + eObjectType, + u"" ); // aParticleID +} + +} +// anonymous namespace + +void ChartController::executeDispatch_FormatObject(std::u16string_view rDispatchCommand) +{ + rtl::Reference<::chart::ChartModel> xChartDocument( getChartModel() ); + OString aCommand( OUStringToOString( rDispatchCommand, RTL_TEXTENCODING_ASCII_US ) ); + OUString rObjectCID = lcl_getObjectCIDForCommand( aCommand, xChartDocument, m_aSelection.getSelectedCID() ); + executeDlg_ObjectProperties( rObjectCID ); +} + +void ChartController::executeDispatch_ObjectProperties() +{ + executeDlg_ObjectProperties( m_aSelection.getSelectedCID() ); +} + +namespace +{ + +OUString lcl_getFormatCIDforSelectedCID( const OUString& rSelectedCID ) +{ + OUString aFormatCID(rSelectedCID); + + //get type of selected object + ObjectType eObjectType = ObjectIdentifier::getObjectType( aFormatCID ); + + // some legend entries are handled as if they were data series + if( eObjectType==OBJECTTYPE_LEGEND_ENTRY ) + { + std::u16string_view aParentParticle( ObjectIdentifier::getFullParentParticle( rSelectedCID ) ); + aFormatCID = ObjectIdentifier::createClassifiedIdentifierForParticle( aParentParticle ); + } + + // treat diagram as wall + if( eObjectType==OBJECTTYPE_DIAGRAM ) + aFormatCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ); + + return aFormatCID; +} + +}//end anonymous namespace + +void ChartController::executeDlg_ObjectProperties( const OUString& rSelectedObjectCID ) +{ + OUString aObjectCID = lcl_getFormatCIDforSelectedCID( rSelectedObjectCID ); + + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Format, + ObjectNameProvider::getName( ObjectIdentifier::getObjectType( aObjectCID ))), + m_xUndoManager ); + + bool bSuccess = ChartController::executeDlg_ObjectProperties_withoutUndoGuard( aObjectCID, false ); + if( bSuccess ) + aUndoGuard.commit(); +} + +bool ChartController::executeDlg_ObjectProperties_withoutUndoGuard( + const OUString& rObjectCID, bool bSuccessOnUnchanged ) +{ + //return true if the properties were changed successfully + bool bRet = false; + if( rObjectCID.isEmpty() ) + { + return bRet; + } + try + { + //get type of object + ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID ); + if( eObjectType==OBJECTTYPE_UNKNOWN ) + { + return bRet; + } + if( eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR ) + { + if( !DiagramHelper::isSupportingFloorAndWall( getFirstDiagram() ) ) + return bRet; + } + + //convert properties to ItemSet + + std::unique_ptr pRefSizeProv(impl_createReferenceSizeProvider()); + + std::unique_ptr pItemConverter( + createItemConverter( rObjectCID, getChartModel(), m_xCC, + m_pDrawModelWrapper->getSdrModel(), + comphelper::getFromUnoTunnel(m_xChartView), + pRefSizeProv.get())); + + if (!pItemConverter) + return bRet; + + SfxItemSet aItemSet = pItemConverter->CreateEmptyItemSet(); + + if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X || eObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + aItemSet.Put(SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE, eObjectType == OBJECTTYPE_DATA_ERRORS_Y )); + + pItemConverter->FillItemSet(aItemSet); + + //prepare dialog + ObjectPropertiesDialogParameter aDialogParameter( rObjectCID ); + aDialogParameter.init( getChartModel() ); + ViewElementListProvider aViewElementListProvider( m_pDrawModelWrapper.get() ); + + SolarMutexGuard aGuard; + SchAttribTabDlg aDlg( + GetChartFrame(), &aItemSet, &aDialogParameter, + &aViewElementListProvider, + getChartModel() ); + + if(aDialogParameter.HasSymbolProperties()) + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( rObjectCID, getChartModel() ); + wrapper::DataPointItemConverter aSymbolItemConverter( getChartModel(), m_xCC + , xObjectProperties, ObjectIdentifier::getDataSeriesForCID( rObjectCID, getChartModel() ) + , m_pDrawModelWrapper->getSdrModel().GetItemPool() + , m_pDrawModelWrapper->getSdrModel() + , getChartModel() + , wrapper::GraphicObjectType::FilledDataPoint ); + + SfxItemSet aSymbolShapeProperties(aSymbolItemConverter.CreateEmptyItemSet() ); + aSymbolItemConverter.FillItemSet( aSymbolShapeProperties ); + + sal_Int32 const nStandardSymbol=0;//@todo get from somewhere + std::unique_ptr pAutoSymbolGraphic(new Graphic( aViewElementListProvider.GetSymbolGraphic( nStandardSymbol, &aSymbolShapeProperties ) )); + // note: the dialog takes the ownership of pSymbolShapeProperties and pAutoSymbolGraphic + aDlg.setSymbolInformation( std::move(aSymbolShapeProperties), std::move(pAutoSymbolGraphic) ); + } + if( aDialogParameter.HasStatisticProperties() ) + { + aDlg.SetAxisMinorStepWidthForErrorBarDecimals( + InsertErrorBarsDialog::getAxisMinorStepWidthForErrorBarDecimals( getChartModel(), m_xChartView, rObjectCID ) ); + } + + //open the dialog + if (aDlg.run() == RET_OK || (bSuccessOnUnchanged && aDlg.DialogWasClosedWithOK())) + { + const SfxItemSet* pOutItemSet = aDlg.GetOutputItemSet(); + if(pOutItemSet) + { + ControllerLockGuardUNO aCLGuard( getChartModel()); + (void)pItemConverter->ApplyItemSet(*pOutItemSet); //model should be changed now + bRet = true; + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + return bRet; +} + +void ChartController::executeDispatch_View3D() +{ + try + { + UndoLiveUpdateGuard aUndoGuard( + SchResId( STR_ACTION_EDIT_3D_VIEW ), + m_xUndoManager ); + + //open dialog + SolarMutexGuard aSolarGuard; + View3DDialog aDlg(GetChartFrame(), getChartModel()); + if (aDlg.run() == RET_OK) + aUndoGuard.commit(); + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_TextEdit.cxx b/chart2/source/controller/main/ChartController_TextEdit.cxx new file mode 100644 index 000000000..8d56429e3 --- /dev/null +++ b/chart2/source/controller/main/ChartController_TextEdit.cxx @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include +#include +#include +#if !ENABLE_WASM_STRIP_ACCESSIBILITY +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +void ChartController::executeDispatch_EditText( const Point* pMousePixel ) +{ + StartTextEdit( pMousePixel ); +} + +void ChartController::StartTextEdit( const Point* pMousePixel ) +{ + //the first marked object will be edited + + SolarMutexGuard aGuard; + SdrObject* pTextObj = m_pDrawViewWrapper->getTextEditObject(); + if(!pTextObj) + return; + + OSL_PRECOND(!m_pTextActionUndoGuard, + "ChartController::StartTextEdit: already have a TextUndoGuard!?"); + m_pTextActionUndoGuard.reset( new UndoGuard( + SchResId( STR_ACTION_EDIT_TEXT ), m_xUndoManager ) ); + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + + //#i77362 change notification for changes on additional shapes are missing + uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY ); + if( xChartViewProps.is() ) + xChartViewProps->setPropertyValue( "SdrViewIsInEditMode", uno::Any(true) ); + + auto pChartWindow(GetChartWindow()); + + bool bEdit = m_pDrawViewWrapper->SdrBeginTextEdit( pTextObj + , m_pDrawViewWrapper->GetPageView() + , pChartWindow + , false //bIsNewObj + , pOutliner + , nullptr //pOutlinerView + , true //bDontDeleteOutliner + , true //bOnlyOneView + ); + if(!bEdit) + return; + + m_pDrawViewWrapper->SetEditMode(); + + // #i12587# support for shapes in chart + if ( pMousePixel ) + { + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if ( pOutlinerView ) + { + MouseEvent aEditEvt( *pMousePixel, 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 ); + pOutlinerView->MouseButtonDown( aEditEvt ); + pOutlinerView->MouseButtonUp( aEditEvt ); + } + } + + if (pChartWindow) + { + //we invalidate the outliner region because the outliner has some + //paint problems (some characters are painted twice a little bit shifted) + pChartWindow->Invalidate( m_pDrawViewWrapper->GetMarkedObjBoundRect() ); + } +} + +bool ChartController::EndTextEdit() +{ + m_pDrawViewWrapper->SdrEndTextEdit(); + + //#i77362 change notification for changes on additional shapes are missing + uno::Reference< beans::XPropertySet > xChartViewProps( m_xChartView, uno::UNO_QUERY ); + if( xChartViewProps.is() ) + xChartViewProps->setPropertyValue( "SdrViewIsInEditMode", uno::Any(false) ); + + SdrObject* pTextObject = m_pDrawViewWrapper->getTextEditObject(); + if(!pTextObject) + return false; + + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + OutlinerParaObject* pParaObj = pTextObject->GetOutlinerParaObject(); + if( !pParaObj || !pOutliner ) + return true; + + pOutliner->SetText( *pParaObj ); + + OUString aString = pOutliner->GetText( + pOutliner->GetParagraph( 0 ), + pOutliner->GetParagraphCount() ); + + OUString aObjectCID = m_aSelection.getSelectedCID(); + if ( !aObjectCID.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet = + ObjectIdentifier::getObjectPropertySet( aObjectCID, getChartModel() ); + + // lock controllers till end of block + ControllerLockGuardUNO aCLGuard( getChartModel() ); + + TitleHelper::setCompleteString( aString, uno::Reference< + css::chart2::XTitle >::query( xPropSet ), m_xCC ); + + OSL_ENSURE(m_pTextActionUndoGuard, "ChartController::EndTextEdit: no TextUndoGuard!"); + if (m_pTextActionUndoGuard) + m_pTextActionUndoGuard->commit(); + } + m_pTextActionUndoGuard.reset(); + return true; +} + +void ChartController::executeDispatch_InsertSpecialCharacter() +{ + SolarMutexGuard aGuard; + if( !m_pDrawViewWrapper) + { + OSL_ENSURE( m_pDrawViewWrapper, "No DrawViewWrapper for ChartController" ); + return; + } + if( !m_pDrawViewWrapper->IsTextEdit() ) + StartTextEdit(); + + SvxAbstractDialogFactory * pFact = SvxAbstractDialogFactory::Create(); + + SfxAllItemSet aSet( m_pDrawModelWrapper->GetItemPool() ); + aSet.Put( SfxBoolItem( FN_PARAM_1, false ) ); + + //set fixed current font + aSet.Put( SfxBoolItem( FN_PARAM_2, true ) ); //maybe not necessary in future + + vcl::Font aCurFont = m_pDrawViewWrapper->getOutliner()->GetRefDevice()->GetFont(); + aSet.Put( SvxFontItem( aCurFont.GetFamilyType(), aCurFont.GetFamilyName(), aCurFont.GetStyleName(), aCurFont.GetPitch(), aCurFont.GetCharSet(), SID_ATTR_CHAR_FONT ) ); + + ScopedVclPtr pDlg(pFact->CreateCharMapDialog(GetChartFrame(), aSet, nullptr)); + if( pDlg->Execute() != RET_OK ) + return; + + const SfxItemSet* pSet = pDlg->GetOutputItemSet(); + OUString aString; + if (pSet) + if (const SfxStringItem* pCharMapItem = pSet->GetItemIfSet(SID_CHARMAP)) + aString = pCharMapItem->GetValue(); + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + SdrOutliner* pOutliner = m_pDrawViewWrapper->getOutliner(); + + if(!pOutliner || !pOutlinerView) + return; + + // insert string to outliner + + // prevent flicker + pOutlinerView->HideCursor(); + pOutliner->SetUpdateLayout(false); + + // delete current selection by inserting empty String, so current + // attributes become unique (sel. has to be erased anyway) + pOutlinerView->InsertText(OUString()); + + pOutlinerView->InsertText(aString, true); + + ESelection aSel = pOutlinerView->GetSelection(); + aSel.nStartPara = aSel.nEndPara; + aSel.nStartPos = aSel.nEndPos; + pOutlinerView->SetSelection(aSel); + + // show changes + pOutliner->SetUpdateLayout(true); + pOutlinerView->ShowCursor(); +} + +uno::Reference< css::accessibility::XAccessibleContext > + ChartController::impl_createAccessibleTextContext() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + uno::Reference< css::accessibility::XAccessibleContext > xResult( + new AccessibleTextHelper( m_pDrawViewWrapper.get() )); + + return xResult; +#else + return uno::Reference< css::accessibility::XAccessibleContext >(); +#endif +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Tools.cxx b/chart2/source/controller/main/ChartController_Tools.cxx new file mode 100644 index 000000000..40da1941e --- /dev/null +++ b/chart2/source/controller/main/ChartController_Tools.cxx @@ -0,0 +1,1107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include +#include +#include +#include "ChartTransferable.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "ShapeController.hxx" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +namespace +{ + +bool lcl_deleteDataSeries( + const OUString & rCID, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< document::XUndoManager > & xUndoManager ) +{ + bool bResult = false; + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( rCID, xModel ); + if( xSeries.is() && xModel.is()) + { + rtl::Reference< ::chart::ChartType > xChartType = + DataSeriesHelper::getChartTypeOfSeries( xSeries, xModel->getFirstChartDiagram()); + if( xChartType.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_DATASERIES )), + xUndoManager ); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + rtl::Reference< Axis > xAxis = DiagramHelper::getAttachedAxis( xSeries, xDiagram ); + + DataSeriesHelper::deleteSeries( xSeries, xChartType ); + + AxisHelper::hideAxisIfNoDataIsAttached( xAxis, xDiagram ); + + bResult = true; + aUndoGuard.commit(); + } + } + return bResult; +} + +bool lcl_deleteDataCurve( + const OUString & rCID, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< document::XUndoManager > & xUndoManager ) +{ + bool bResult = false; + + uno::Reference< beans::XPropertySet > xProperties( + ObjectIdentifier::getObjectPropertySet( rCID, xModel)); + + uno::Reference< chart2::XRegressionCurve > xRegressionCurve( xProperties, uno::UNO_QUERY ); + + if( xRegressionCurve.is()) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( + ObjectIdentifier::getObjectPropertySet( + OUString(ObjectIdentifier::getFullParentParticle( rCID )), xModel), uno::UNO_QUERY ); + + if( xRegressionCurveContainer.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE )), + xUndoManager ); + + xRegressionCurveContainer->removeRegressionCurve( xRegressionCurve ); + + bResult = true; + aUndoGuard.commit(); + } + } + return bResult; +} + +} // anonymous namespace + +std::unique_ptr ChartController::impl_createReferenceSizeProvider() +{ + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + + return std::make_unique(aPageSize, getChartModel()); +} + +void ChartController::impl_adaptDataSeriesAutoResize() +{ + std::unique_ptr pRefSizeProvider(impl_createReferenceSizeProvider()); + if (pRefSizeProvider) + pRefSizeProvider->setValuesAtAllDataSeries(); +} + +void ChartController::executeDispatch_NewArrangement() +{ + // remove manual positions at titles, legend and the diagram, remove manual + // size at the diagram + + try + { + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + if( xDiagram.is()) + { + UndoGuard aUndoGuard( + SchResId( STR_ACTION_REARRANGE_CHART ), + m_xUndoManager ); + ControllerLockGuardUNO aCtlLockGuard( xModel ); + + // diagram + xDiagram->setPropertyToDefault( "RelativeSize"); + xDiagram->setPropertyToDefault( "RelativePosition"); + xDiagram->setPropertyToDefault( "PosSizeExcludeAxes"); + + // 3d rotation + ThreeDHelper::set3DSettingsToDefault( xDiagram ); + + // legend + Reference< beans::XPropertyState > xLegendState( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendState.is()) + { + xLegendState->setPropertyToDefault( "RelativePosition"); + xLegendState->setPropertyToDefault( "RelativeSize"); + xLegendState->setPropertyToDefault( "AnchorPosition"); + } + + // titles + for( sal_Int32 eType = TitleHelper::TITLE_BEGIN; + eType < TitleHelper::NORMAL_TITLE_END; + ++eType ) + { + Reference< beans::XPropertyState > xTitleState( + TitleHelper::getTitle( + static_cast< TitleHelper::eTitleType >( eType ), xModel ), uno::UNO_QUERY ); + if( xTitleState.is()) + xTitleState->setPropertyToDefault( "RelativePosition"); + } + + // regression curve equations + std::vector< rtl::Reference< RegressionCurveModel > > aRegressionCurves = + RegressionCurveHelper::getAllRegressionCurvesNotMeanValueLine( xDiagram ); + + // reset equation position + for( const auto& xCurve : aRegressionCurves ) + RegressionCurveHelper::resetEquationPosition( xCurve ); + + aUndoGuard.commit(); + } + } + catch( const uno::RuntimeException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartController::executeDispatch_ScaleText() +{ + SolarMutexGuard aSolarGuard; + UndoGuard aUndoGuard( + SchResId( STR_ACTION_SCALE_TEXT ), + m_xUndoManager ); + ControllerLockGuardUNO aCtlLockGuard( getChartModel() ); + + std::unique_ptr pRefSizeProv(impl_createReferenceSizeProvider()); + OSL_ASSERT(pRefSizeProv); + if (pRefSizeProv) + pRefSizeProv->toggleAutoResizeState(); + + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_Paste() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( !pChartWindow ) + return; + + Graphic aGraphic; + // paste location: center of window + Point aPos = pChartWindow->PixelToLogic( tools::Rectangle( {}, pChartWindow->GetSizePixel()).Center()); + + // handle different formats + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pChartWindow )); + if( aDataHelper.GetTransferable().is()) + { + if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) ) + { + tools::SvRef xStm; + if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) ) + { + xStm->Seek( 0 ); + Reference< io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) ); + + std::unique_ptr< SdrModel > spModel( + new SdrModel()); + + if ( SvxDrawingLayerImport( spModel.get(), xInputStream ) ) + { + impl_PasteShapes( spModel.get() ); + } + } + } + else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) ) + { + // graphic exchange format (graphic manager bitmap format?) + tools::SvRef xStm; + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm )) + { + TypeSerializer aSerializer(*xStm); + aSerializer.readGraphic(aGraphic); + } + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE )) + { + // meta file + GDIMetaFile aMetafile; + if( aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMetafile )) + aGraphic = Graphic( aMetafile ); + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP )) + { + // bitmap (non-graphic-manager) + BitmapEx aBmpEx; + if( aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx )) + aGraphic = Graphic( aBmpEx ); + } + else if( aDataHelper.HasFormat( SotClipboardFormatId::STRING )) + { + OUString aString; + if( aDataHelper.GetString( SotClipboardFormatId::STRING, aString ) && m_pDrawModelWrapper ) + { + if( m_pDrawViewWrapper ) + { + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if( pOutlinerView )//in case of edit mode insert into edited string + pOutlinerView->InsertText( aString ); + else + { + impl_PasteStringAsTextShape( aString, awt::Point( 0, 0 ) ); + } + } + } + } + } + + if( aGraphic.GetType() != GraphicType::NONE ) + { + Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic()); + if( xGraphic.is()) + impl_PasteGraphic( xGraphic, aPos ); + } +} + +// note: aPosition is ignored for now. The object is always pasted centered to +// the page +void ChartController::impl_PasteGraphic( + uno::Reference< graphic::XGraphic > const & xGraphic, + const ::Point & /* aPosition */ ) +{ + DBG_TESTSOLARMUTEX(); + // note: the XPropertySet of the model is the old API. Also the property + // "AdditionalShapes" that is used there. + rtl::Reference< ChartModel > xModel = getChartModel(); + DrawModelWrapper * pDrawModelWrapper( GetDrawModelWrapper()); + if( ! (xGraphic.is() && xModel.is())) + return; + rtl::Reference xGraphicShape = new SvxGraphicObject(nullptr); + xGraphicShape->setShapeKind(SdrObjKind::Graphic); + + uno::Reference< drawing::XShapes > xPage = pDrawModelWrapper->getMainDrawPage(); + if( xPage.is()) + { + xPage->add( xGraphicShape ); + //need to change the model state manually + xModel->setModified( true ); + //select new shape + m_aSelection.setSelection( xGraphicShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + } + xGraphicShape->SvxShape::setPropertyValue( "Graphic", uno::Any( xGraphic )); + + awt::Size aGraphicSize( 1000, 1000 ); + auto pChartWindow(GetChartWindow()); + // first try size in 100th mm, then pixel size + if( ! ( xGraphicShape->SvxShape::getPropertyValue( "Size100thMM") >>= aGraphicSize ) && + ( ( xGraphicShape->SvxShape::getPropertyValue( "SizePixel") >>= aGraphicSize ) && pChartWindow )) + { + ::Size aVCLSize( pChartWindow->PixelToLogic( Size( aGraphicSize.Width, aGraphicSize.Height ))); + aGraphicSize.Width = aVCLSize.getWidth(); + aGraphicSize.Height = aVCLSize.getHeight(); + } + xGraphicShape->setSize( aGraphicSize ); + xGraphicShape->setPosition( awt::Point( 0, 0 ) ); +} + +void ChartController::impl_PasteShapes( SdrModel* pModel ) +{ + DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() ); + if ( !(pDrawModelWrapper && m_pDrawViewWrapper) ) + return; + + Reference< drawing::XDrawPage > xDestPage( pDrawModelWrapper->getMainDrawPage() ); + SdrPage* pDestPage = GetSdrPageFromXDrawPage( xDestPage ); + if ( !pDestPage ) + return; + + Reference< drawing::XShape > xSelShape; + m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) ); + sal_uInt16 nCount = pModel->GetPageCount(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const SdrPage* pPage = pModel->GetPage( i ); + SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pObj(aIter.Next()); + // Clone to new SdrModel + SdrObject* pNewObj(pObj ? pObj->CloneSdrObject(pDrawModelWrapper->getSdrModel()) : nullptr); + + if ( pNewObj ) + { + // set position + Reference< drawing::XShape > xShape( pNewObj->getUnoShape(), uno::UNO_QUERY ); + if ( xShape.is() ) + { + xShape->setPosition( awt::Point( 0, 0 ) ); + } + + pDestPage->InsertObject( pNewObj ); + m_pDrawViewWrapper->AddUndo( std::make_unique( *pNewObj ) ); + xSelShape = xShape; + } + } + } + + rtl::Reference< ChartModel > xModifiable = getChartModel(); + if ( xModifiable.is() ) + { + xModifiable->setModified( true ); + } + + // select last inserted shape + m_aSelection.setSelection( xSelShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + + m_pDrawViewWrapper->EndUndo(); + + impl_switchDiagramPositioningToExcludingPositioning(); +} + +void ChartController::impl_PasteStringAsTextShape( const OUString& rString, const awt::Point& rPosition ) +{ + DrawModelWrapper* pDrawModelWrapper( GetDrawModelWrapper() ); + if ( !(pDrawModelWrapper && m_pDrawViewWrapper) ) + return; + + const Reference< drawing::XDrawPage >& xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + OSL_ASSERT( xDrawPage.is() ); + + if ( !xDrawPage ) + return; + + try + { + rtl::Reference xTextShape = new SvxShapeText(nullptr); + xTextShape->setShapeKind(SdrObjKind::Text); + xDrawPage->add( xTextShape ); + + xTextShape->setString( rString ); + + float fCharHeight = 10.0; + xTextShape->SvxShape::setPropertyValue( "TextAutoGrowHeight", uno::Any( true ) ); + xTextShape->SvxShape::setPropertyValue( "TextAutoGrowWidth", uno::Any( true ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeight", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeightAsian", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "CharHeightComplex", uno::Any( fCharHeight ) ); + xTextShape->SvxShape::setPropertyValue( "TextVerticalAdjust", uno::Any( drawing::TextVerticalAdjust_CENTER ) ); + xTextShape->SvxShape::setPropertyValue( "TextHorizontalAdjust", uno::Any( drawing::TextHorizontalAdjust_CENTER ) ); + xTextShape->SvxShape::setPropertyValue( "CharFontName", uno::Any( OUString("Albany") ) ); + + xTextShape->setPosition( rPosition ); + + m_aSelection.setSelection( xTextShape ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + + SdrObject* pObj = DrawViewWrapper::getSdrObject( xTextShape ); + if ( pObj ) + { + m_pDrawViewWrapper->BegUndo( SvxResId( RID_SVX_3D_UNDO_EXCHANGE_PASTE ) ); + m_pDrawViewWrapper->AddUndo( std::make_unique( *pObj ) ); + m_pDrawViewWrapper->EndUndo(); + + impl_switchDiagramPositioningToExcludingPositioning(); + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartController::executeDispatch_Copy() +{ + SolarMutexGuard aSolarGuard; + if (!m_pDrawViewWrapper) + return; + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if (pOutlinerView) + pOutlinerView->Copy(); + else + { + SdrObject* pSelectedObj = nullptr; + ObjectIdentifier aSelOID(m_aSelection.getSelectedOID()); + + if (aSelOID.isAutoGeneratedObject()) + pSelectedObj = m_pDrawModelWrapper->getNamedSdrObject( aSelOID.getObjectCID() ); + else if (aSelOID.isAdditionalShape()) + pSelectedObj = DrawViewWrapper::getSdrObject( aSelOID.getAdditionalShape() ); + + if (pSelectedObj) + { + Reference xClipboard(GetChartWindow()->GetClipboard()); + if (xClipboard.is()) + { + Reference< datatransfer::XTransferable > xTransferable( + new ChartTransferable(m_pDrawModelWrapper->getSdrModel(), + pSelectedObj, aSelOID.isAdditionalShape())); + xClipboard->setContents(xTransferable, Reference< datatransfer::clipboard::XClipboardOwner >()); + } + } + } +} + +void ChartController::executeDispatch_Cut() +{ + executeDispatch_Copy(); + executeDispatch_Delete(); +} + +bool ChartController::isObjectDeleteable( const uno::Any& rSelection ) +{ + ObjectIdentifier aSelOID( rSelection ); + if ( aSelOID.isAutoGeneratedObject() ) + { + const OUString& aSelObjCID( aSelOID.getObjectCID() ); + ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID )); + + switch(aObjectType) + { + case OBJECTTYPE_TITLE: + case OBJECTTYPE_LEGEND: + case OBJECTTYPE_DATA_SERIES: + case OBJECTTYPE_LEGEND_ENTRY: + case OBJECTTYPE_DATA_CURVE_EQUATION: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_AXIS: + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + return true; + default: + break; + } + } + else if ( aSelOID.isAdditionalShape() ) + { + return true; + } + + return false; +} + +bool ChartController::isShapeContext() const +{ + return m_aSelection.isAdditionalShapeSelected() || + ( m_pDrawViewWrapper && m_pDrawViewWrapper->AreObjectsMarked() && + ( m_pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) ); +} + +void ChartController::impl_ClearSelection() +{ + if( m_aSelection.hasSelection()) + { + m_aSelection.clearSelection(); + impl_notifySelectionChangeListeners(); + } +} + +bool ChartController::executeDispatch_Delete() +{ + bool bReturn = false; + + // remove the selected object + OUString aCID( m_aSelection.getSelectedCID() ); + if( !aCID.isEmpty() ) + { + if( !isObjectDeleteable( uno::Any( aCID ) ) ) + return false; + + //remove chart object + rtl::Reference< ChartModel > xChartDoc = getChartModel(); + if( !xChartDoc.is() ) + return false; + + ObjectType aObjectType( ObjectIdentifier::getObjectType( aCID )); + switch( aObjectType ) + { + case OBJECTTYPE_TITLE: + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_TITLE )), + m_xUndoManager ); + TitleHelper::removeTitle( + ObjectIdentifier::getTitleTypeForCID( aCID ), getChartModel() ); + bReturn = true; + aUndoGuard.commit(); + break; + } + case OBJECTTYPE_LEGEND: + { + rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram()); + if( xDiagram.is()) + { + uno::Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendProp.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_LEGEND )), + m_xUndoManager ); + xLegendProp->setPropertyValue( "Show", uno::Any( false )); + bReturn = true; + aUndoGuard.commit(); + } + } + break; + } + + case OBJECTTYPE_DATA_SERIES: + bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager ); + break; + + case OBJECTTYPE_LEGEND_ENTRY: + { + ObjectType eParentObjectType = ObjectIdentifier::getObjectType( + ObjectIdentifier::getFullParentParticle( aCID )); + if( eParentObjectType == OBJECTTYPE_DATA_SERIES ) + { + bReturn = lcl_deleteDataSeries( aCID, getChartModel(), m_xUndoManager ); + } + else if( eParentObjectType == OBJECTTYPE_DATA_CURVE ) + { + sal_Int32 nEndPos = aCID.lastIndexOf(':'); + OUString aParentCID = aCID.copy(0, nEndPos); + + bReturn = lcl_deleteDataCurve(aParentCID, getChartModel(), m_xUndoManager ); + } + else if( eParentObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + { + executeDispatch_DeleteMeanValue(); + bReturn = true; + } + break; + } + + case OBJECTTYPE_DATA_AVERAGE_LINE: + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( + ObjectIdentifier::getObjectPropertySet( + OUString(ObjectIdentifier::getFullParentParticle( aCID )), getChartModel()), uno::UNO_QUERY ); + if( xRegCurveCnt.is()) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_AVERAGE_LINE )), + m_xUndoManager ); + RegressionCurveHelper::removeMeanValueLine( xRegCurveCnt ); + bReturn = true; + aUndoGuard.commit(); + } + } + break; + + case OBJECTTYPE_DATA_CURVE: + { + bReturn = lcl_deleteDataCurve( aCID, getChartModel(), m_xUndoManager ); + } + break; + + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + uno::Reference< beans::XPropertySet > xEqProp( + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel())); + + if( xEqProp.is()) + { + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId( STR_OBJECT_CURVE_EQUATION )), + m_xUndoManager ); + { + ControllerLockGuardUNO aCtlLockGuard( xModel ); + xEqProp->setPropertyValue( "ShowEquation", uno::Any( false )); + xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") )); + xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x)") )); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false )); + } + bReturn = true; + aUndoGuard.commit(); + } + } + break; + + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + { + uno::Reference< beans::XPropertySet > xErrorBarProp( + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() )); + if( xErrorBarProp.is()) + { + TranslateId pId; + + if ( aObjectType == OBJECTTYPE_DATA_ERRORS_X ) + pId = STR_OBJECT_ERROR_BARS_X; + else if ( aObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + pId = STR_OBJECT_ERROR_BARS_Y; + else + pId = STR_OBJECT_ERROR_BARS_Z; + + rtl::Reference<::chart::ChartModel> xModel( getChartModel() ); + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, SchResId(pId)), + m_xUndoManager); + { + ControllerLockGuardUNO aCtlLockGuard( xModel ); + xErrorBarProp->setPropertyValue( + "ErrorBarStyle", + uno::Any( css::chart::ErrorBarStyle::NONE )); + } + bReturn = true; + aUndoGuard.commit(); + } + break; + } + + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_LABEL: + { + uno::Reference< beans::XPropertySet > xObjectProperties = + ObjectIdentifier::getObjectPropertySet( aCID, getChartModel() ); + if( xObjectProperties.is() ) + { + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::Delete, + SchResId( aObjectType == OBJECTTYPE_DATA_LABEL ? STR_OBJECT_LABEL : STR_OBJECT_DATALABELS )), + m_xUndoManager ); + chart2::DataPointLabel aLabel; + xObjectProperties->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel; + aLabel.ShowNumber = false; + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + aLabel.ShowLegendSymbol = false; + aLabel.ShowCustomLabel = false; + aLabel.ShowSeriesName = false; + if( aObjectType == OBJECTTYPE_DATA_LABELS ) + { + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( aCID, getChartModel() ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_LABEL, uno::Any(aLabel) ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any() ); + } + else + { + xObjectProperties->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + xObjectProperties->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + } + bReturn = true; + aUndoGuard.commit(); + } + break; + } + case OBJECTTYPE_AXIS: + { + executeDispatch_DeleteAxis(); + bReturn = true; + break; + } + case OBJECTTYPE_GRID: + { + executeDispatch_DeleteMajorGrid(); + bReturn = true; + break; + } + case OBJECTTYPE_SUBGRID: + { + executeDispatch_DeleteMinorGrid(); + bReturn = true; + break; + } + + default: + { + break; + } + } + } + else + { + //remove additional shape + impl_ClearSelection(); + { + SolarMutexGuard aSolarGuard; + if ( m_pDrawViewWrapper ) + { + m_pDrawViewWrapper->DeleteMarked(); + bReturn = true; + } + } + } + return bReturn; +} + +void ChartController::executeDispatch_ToggleLegend() +{ + rtl::Reference< ChartModel > xModel = getChartModel(); + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_LEGEND ), m_xUndoManager ); + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*xModel); + bool bChanged = false; + if( xLegendProp.is()) + { + try + { + bool bShow = false; + if( xLegendProp->getPropertyValue( "Show") >>= bShow ) + { + xLegendProp->setPropertyValue( "Show", uno::Any( ! bShow )); + bChanged = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + xLegendProp = LegendHelper::getLegend(*xModel, m_xCC, true); + if( xLegendProp.is()) + bChanged = true; + } + + if( bChanged ) + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ToggleGridHorizontal() +{ + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_GRID_HORZ ), m_xUndoManager ); + rtl::Reference< Diagram > xDiagram( getFirstDiagram() ); + if( !xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 1; + sal_Int32 nCooSysIndex = 0; + + bool bHasMajorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram ); + bool bHasMinorYGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram ); + + if( bHasMajorYGrid ) + { + if ( bHasMinorYGrid ) + { + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + } + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_ToggleGridVertical() +{ + UndoGuard aUndoGuard( + SchResId( STR_ACTION_TOGGLE_GRID_VERTICAL ), m_xUndoManager ); + rtl::Reference< Diagram > xDiagram( getFirstDiagram() ); + if( !xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + sal_Int32 nCooSysIndex = 0; + + bool bHasMajorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true, xDiagram ); + bool bHasMinorXGrid = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false, xDiagram ); + if( bHasMajorXGrid ) + { + if (bHasMinorXGrid) + { + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + AxisHelper::hideGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, false, xDiagram ); + } + } + else + { + AxisHelper::showGrid( nDimensionIndex, nCooSysIndex, true, xDiagram ); + } + + aUndoGuard.commit(); +} + +void ChartController::executeDispatch_FillColor(sal_uInt32 nColor) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "FillColor", uno::Any( nColor ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_FillGradient(OUString sJSONGradient) +{ + XGradient aXGradient = XGradient::fromJSON(sJSONGradient); + css::awt::Gradient aGradient = aXGradient.toGradientUNO(); + + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + if( xPropSet.is() ) + { + OUString aPrefferedName = OUString::number(static_cast(aXGradient.GetStartColor())) + + OUString::number(static_cast(aXGradient.GetEndColor())) + + OUString::number(static_cast(aXGradient.GetAngle().get())); + + OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(css::uno::Any(aGradient), + xChartModel, + aPrefferedName); + + xPropSet->setPropertyValue("FillGradientName", css::uno::Any(aNewName)); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::executeDispatch_LineColor(sal_uInt32 nColor) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (xDiagram.is()) + xPropSet.set(xDiagram->getWall()); + } + + if( xPropSet.is() ) + xPropSet->setPropertyValue( "LineColor", css::uno::Any( Color(ColorTransparency, nColor) ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_LineWidth(sal_uInt32 nWidth) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPropSet( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (xDiagram.is()) + xPropSet.set(xDiagram->getWall()); + } + + if( xPropSet.is() ) + xPropSet->setPropertyValue( "LineWidth", css::uno::Any( nWidth ) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "chart2" ); + } +} + +void ChartController::executeDispatch_LOKSetTextSelection(int nType, int nX, int nY) +{ + if (!m_pDrawViewWrapper) + return; + + if (!m_pDrawViewWrapper->IsTextEdit()) + return; + + OutlinerView* pOutlinerView = m_pDrawViewWrapper->GetTextEditOutlinerView(); + if (!pOutlinerView) + return; + + EditView& rEditView = pOutlinerView->GetEditView(); + Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY)); + switch (nType) + { + case LOK_SETTEXTSELECTION_START: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false); + break; + case LOK_SETTEXTSELECTION_END: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false); + break; + case LOK_SETTEXTSELECTION_RESET: + rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true); + break; + default: + assert(false); + break; + } +} + +void ChartController::executeDispatch_LOKPieSegmentDragging( int nOffset ) +{ + try + { + OUString aCID( m_aSelection.getSelectedCID() ); + rtl::Reference<::chart::ChartModel> xChartModel = getChartModel(); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( aCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "Offset", uno::Any( nOffset / 100.0 ) ); + } + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartController::impl_ShapeControllerDispatch( const util::URL& rURL, const Sequence< beans::PropertyValue >& rArgs ) +{ + Reference< frame::XDispatch > xDispatch( m_aDispatchContainer.getShapeController() ); + if ( xDispatch.is() ) + { + xDispatch->dispatch( rURL, rArgs ); + } +} + +void ChartController::impl_switchDiagramPositioningToExcludingPositioning() +{ + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + ActionDescriptionProvider::ActionType::PosSize, + ObjectNameProvider::getName( OBJECTTYPE_DIAGRAM)), + m_xUndoManager ); + if (DiagramHelper::switchDiagramPositioningToExcludingPositioning(*getChartModel(), true, true)) + aUndoGuard.commit(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartController_Window.cxx b/chart2/source/controller/main/ChartController_Window.cxx new file mode 100644 index 000000000..c50749c42 --- /dev/null +++ b/chart2/source/controller/main/ChartController_Window.cxx @@ -0,0 +1,2103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UndoGuard.hxx" +#include +#include +#include +#include "DragMethod_PieSegment.hxx" +#include "DragMethod_RotateDiagram.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DrawCommandDispatch.hxx" +#include +#include "ControllerCommandDispatch.hxx" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DRGPIX 2 // Drag MinMove in Pixel + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +namespace +{ +bool lcl_GrowAndShiftLogic( + RelativePosition & rInOutRelPos, + RelativeSize & rInOutRelSize, + const awt::Size & rRefSize, + double fGrowLogicX, + double fGrowLogicY ) +{ + if( rRefSize.Width == 0 || + rRefSize.Height == 0 ) + return false; + + double fRelativeGrowX = fGrowLogicX / rRefSize.Width; + double fRelativeGrowY = fGrowLogicY / rRefSize.Height; + + return ::chart::RelativePositionHelper::centerGrow( + rInOutRelPos, rInOutRelSize, + fRelativeGrowX, fRelativeGrowY ); +} + +bool lcl_MoveObjectLogic( + RelativePosition & rInOutRelPos, + RelativeSize const & rObjectSize, + const awt::Size & rRefSize, + double fShiftLogicX, + double fShiftLogicY ) +{ + if( rRefSize.Width == 0 || + rRefSize.Height == 0 ) + return false; + + double fRelativeShiftX = fShiftLogicX / rRefSize.Width; + double fRelativeShiftY = fShiftLogicY / rRefSize.Height; + + return ::chart::RelativePositionHelper::moveObject( + rInOutRelPos, rObjectSize, + fRelativeShiftX, fRelativeShiftY ); +} + +void lcl_insertMenuCommand( + const uno::Reference< awt::XPopupMenu > & xMenu, + sal_Int16 nId, const OUString & rCommand ) +{ + xMenu->insertItem( nId, "", 0, -1 ); + xMenu->setCommand( nId, rCommand ); +} + +OUString lcl_getFormatCommandForObjectCID( std::u16string_view rCID ) +{ + OUString aDispatchCommand( ".uno:FormatSelection" ); + + ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID ); + + switch(eObjectType) + { + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + aDispatchCommand = ".uno:FormatWall"; + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + aDispatchCommand = ".uno:FormatFloor"; + break; + case OBJECTTYPE_PAGE: + aDispatchCommand = ".uno:FormatChartArea"; + break; + case OBJECTTYPE_LEGEND: + aDispatchCommand = ".uno:FormatLegend"; + break; + case OBJECTTYPE_TITLE: + aDispatchCommand = ".uno:FormatTitle"; + break; + case OBJECTTYPE_LEGEND_ENTRY: + aDispatchCommand = ".uno:FormatDataSeries"; + break; + case OBJECTTYPE_AXIS: + case OBJECTTYPE_AXIS_UNITLABEL: + aDispatchCommand = ".uno:FormatAxis"; + break; + case OBJECTTYPE_GRID: + aDispatchCommand = ".uno:FormatMajorGrid"; + break; + case OBJECTTYPE_SUBGRID: + aDispatchCommand = ".uno:FormatMinorGrid"; + break; + case OBJECTTYPE_DATA_LABELS: + aDispatchCommand = ".uno:FormatDataLabels"; + break; + case OBJECTTYPE_DATA_SERIES: + aDispatchCommand = ".uno:FormatDataSeries"; + break; + case OBJECTTYPE_DATA_LABEL: + aDispatchCommand = ".uno:FormatDataLabel"; + break; + case OBJECTTYPE_DATA_POINT: + aDispatchCommand = ".uno:FormatDataPoint"; + break; + case OBJECTTYPE_DATA_AVERAGE_LINE: + aDispatchCommand = ".uno:FormatMeanValue"; + break; + case OBJECTTYPE_DATA_ERRORS_X: + aDispatchCommand = ".uno:FormatXErrorBars"; + break; + case OBJECTTYPE_DATA_ERRORS_Y: + aDispatchCommand = ".uno:FormatYErrorBars"; + break; + case OBJECTTYPE_DATA_ERRORS_Z: + aDispatchCommand = ".uno:FormatZErrorBars"; + break; + case OBJECTTYPE_DATA_CURVE: + aDispatchCommand = ".uno:FormatTrendline"; + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + aDispatchCommand = ".uno:FormatTrendlineEquation"; + break; + case OBJECTTYPE_DATA_STOCK_RANGE: + aDispatchCommand = ".uno:FormatSelection"; + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + aDispatchCommand = ".uno:FormatStockLoss"; + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + aDispatchCommand = ".uno:FormatStockGain"; + break; + default: //OBJECTTYPE_UNKNOWN + break; + } + return aDispatchCommand; +} + +} // anonymous namespace + +// awt::XWindow +void SAL_CALL ChartController::setPosSize( + sal_Int32 X, + sal_Int32 Y, + sal_Int32 Width, + sal_Int32 Height, + sal_Int16 Flags ) +{ + SolarMutexGuard aGuard; + uno::Reference xWindow = m_xViewWindow; + auto pChartWindow(GetChartWindow()); + + if(!(xWindow.is() && pChartWindow)) + return; + + Size aLogicSize = pChartWindow->PixelToLogic( Size( Width, Height ), MapMode( MapUnit::Map100thMM ) ); + + //todo: for standalone chart: detect whether we are standalone + //change map mode to fit new size + awt::Size aModelPageSize = ChartModelHelper::getPageSize( getChartModel() ); + sal_Int32 nScaleXNumerator = aLogicSize.Width(); + sal_Int32 nScaleXDenominator = aModelPageSize.Width; + sal_Int32 nScaleYNumerator = aLogicSize.Height(); + sal_Int32 nScaleYDenominator = aModelPageSize.Height; + MapMode aNewMapMode( + MapUnit::Map100thMM, + Point(0,0), + Fraction(nScaleXNumerator, nScaleXDenominator), + Fraction(nScaleYNumerator, nScaleYDenominator) ); + pChartWindow->SetMapMode(aNewMapMode); + pChartWindow->setPosSizePixel( X, Y, Width, Height, static_cast(Flags) ); + + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + uno::Reference< beans::XPropertySet > xProp( m_xChartView, uno::UNO_QUERY ); + if( xProp.is() ) + { + auto aZoomFactors(::comphelper::InitPropertySequence({ + { "ScaleXNumerator", uno::Any( nScaleXNumerator ) }, + { "ScaleXDenominator", uno::Any( nScaleXDenominator ) }, + { "ScaleYNumerator", uno::Any( nScaleYNumerator ) }, + { "ScaleYDenominator", uno::Any( nScaleYDenominator ) } + })); + xProp->setPropertyValue( "ZoomFactors", uno::Any( aZoomFactors )); + } + + //a correct work area is at least necessary for correct values in the position and size dialog and for dragging area + if(m_pDrawViewWrapper) + { + tools::Rectangle aRect(Point(0,0), pChartWindow->GetOutDev()->GetOutputSize()); + m_pDrawViewWrapper->SetWorkArea( aRect ); + } + pChartWindow->Invalidate(); +} + +awt::Rectangle SAL_CALL ChartController::getPosSize() +{ + //@todo + awt::Rectangle aRet(0, 0, 0, 0); + + uno::Reference xWindow = m_xViewWindow; + if(xWindow.is()) + aRet = xWindow->getPosSize(); + + return aRet; +} + +void SAL_CALL ChartController::setVisible( sal_Bool Visible ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setVisible( Visible ); +} + +void SAL_CALL ChartController::setEnable( sal_Bool Enable ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setEnable( Enable ); +} + +void SAL_CALL ChartController::setFocus() +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->setFocus(); +} + +void SAL_CALL ChartController::addWindowListener( + const uno::Reference< awt::XWindowListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addWindowListener( xListener ); +} + +void SAL_CALL ChartController::removeWindowListener( + const uno::Reference< awt::XWindowListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeWindowListener( xListener ); +} + +void SAL_CALL ChartController::addFocusListener( + const uno::Reference< awt::XFocusListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addFocusListener( xListener ); +} + +void SAL_CALL ChartController::removeFocusListener( + const uno::Reference< awt::XFocusListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeFocusListener( xListener ); +} + +void SAL_CALL ChartController::addKeyListener( + const uno::Reference< awt::XKeyListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addKeyListener( xListener ); +} + +void SAL_CALL ChartController::removeKeyListener( + const uno::Reference< awt::XKeyListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeKeyListener( xListener ); +} + +void SAL_CALL ChartController::addMouseListener( + const uno::Reference< awt::XMouseListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addMouseListener( xListener ); +} + +void SAL_CALL ChartController::removeMouseListener( + const uno::Reference< awt::XMouseListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeMouseListener( xListener ); +} + +void SAL_CALL ChartController::addMouseMotionListener( + const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addMouseMotionListener( xListener ); +} + +void SAL_CALL ChartController::removeMouseMotionListener( + const uno::Reference< awt::XMouseMotionListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removeMouseMotionListener( xListener ); +} + +void SAL_CALL ChartController::addPaintListener( + const uno::Reference< awt::XPaintListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->addPaintListener( xListener ); +} + +void SAL_CALL ChartController::removePaintListener( + const uno::Reference< awt::XPaintListener >& xListener ) +{ + //@todo + uno::Reference xWindow = m_xViewWindow; + + if(xWindow.is()) + xWindow->removePaintListener( xListener ); +} + +// impl vcl window controller methods +void ChartController::PrePaint() +{ + // forward VCLs PrePaint window event to DrawingLayer + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + + if (pDrawViewWrapper) + { + pDrawViewWrapper->PrePaint(); + } +} + +void ChartController::execute_Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + try + { + rtl::Reference xModel(getChartModel()); + //OSL_ENSURE( xModel.is(), "ChartController::execute_Paint: have no model to paint"); + if (!xModel.is()) + return; + + //better performance for big data + uno::Reference xProp(m_xChartView, uno::UNO_QUERY); + if (xProp.is()) + { + awt::Size aResolution(1000, 1000); + { + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if (pChartWindow) + { + aResolution.Width = pChartWindow->GetSizePixel().Width(); + aResolution.Height = pChartWindow->GetSizePixel().Height(); + } + } + xProp->setPropertyValue( "Resolution", uno::Any( aResolution )); + } + + uno::Reference< util::XUpdatable > xUpdatable( m_xChartView, uno::UNO_QUERY ); + if (xUpdatable.is()) + xUpdatable->update(); + + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if (pDrawViewWrapper) + pDrawViewWrapper->CompleteRedraw(&rRenderContext, vcl::Region(rRect)); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch( ... ) + { + } +} + +static bool isDoubleClick( const MouseEvent& rMEvt ) +{ + return rMEvt.GetClicks() == 2 && rMEvt.IsLeft() && + !rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift(); +} + +void ChartController::startDoubleClickWaiting() +{ + SolarMutexGuard aGuard; + + m_bWaitingForDoubleClick = true; + + sal_uInt64 nDblClkTime = 500; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + const MouseSettings& rMSettings = pChartWindow->GetSettings().GetMouseSettings(); + nDblClkTime = rMSettings.GetDoubleClickTime(); + } + m_aDoubleClickTimer.SetTimeout( nDblClkTime ); + m_aDoubleClickTimer.Start(); +} + +void ChartController::stopDoubleClickWaiting() +{ + m_aDoubleClickTimer.Stop(); + m_bWaitingForDoubleClick = false; +} + +IMPL_LINK_NOARG(ChartController, DoubleClickWaitingHdl, Timer *, void) +{ + m_bWaitingForDoubleClick = false; + + if( m_bWaitingForMouseUp || !m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() ) + return; + + impl_selectObjectAndNotiy(); + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if( pChartWindow ) + { + vcl::Window::PointerState aPointerState( pChartWindow->GetPointerState() ); + MouseEvent aMouseEvent( + aPointerState.maPos, + 1/*nClicks*/, + MouseEventModifiers::NONE, + static_cast< sal_uInt16 >( aPointerState.mnState )/*nButtons*/, + 0/*nModifier*/ ); + impl_SetMousePointer( aMouseEvent ); + } +} + +void ChartController::execute_MouseButtonDown( const MouseEvent& rMEvt ) +{ + SolarMutexGuard aGuard; + + m_bWaitingForMouseUp = true; + m_bFieldButtonDown = false; + + if( isDoubleClick(rMEvt) ) + stopDoubleClickWaiting(); + else + startDoubleClickWaiting(); + + m_aSelection.remindSelectionBeforeMouseDown(); + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper ) + return; + + Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel()); + + // Check if button was clicked + SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos); + if (pObject) + { + OUString aCID = pObject->GetName(); + if (aCID.startsWith("FieldButton")) + { + m_bFieldButtonDown = true; + return; // Don't take any action if button was clicked + } + } + + if ( rMEvt.GetButtons() == MOUSE_LEFT ) + { + pChartWindow->GrabFocus(); + pChartWindow->CaptureMouse(); + } + + if( pDrawViewWrapper->IsTextEdit() ) + { + SdrViewEvent aVEvt; + if ( pDrawViewWrapper->IsTextEditHit( aMPos ) || + // #i12587# support for shapes in chart + ( rMEvt.IsRight() && pDrawViewWrapper->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt ) == SdrHitKind::MarkedObject ) ) + { + pDrawViewWrapper->MouseButtonDown(rMEvt, pChartWindow->GetOutDev()); + return; + } + else + { + EndTextEdit(); + } + } + + //abort running action + if( pDrawViewWrapper->IsAction() ) + { + if( rMEvt.IsRight() ) + pDrawViewWrapper->BckAction(); + return; + } + + if( isDoubleClick(rMEvt) ) //do not change selection if double click + return;//double click is handled further in mousebutton up + + SdrHdl* pHitSelectionHdl = nullptr; + //switch from move to resize if handle is hit on a resizable object + if( m_aSelection.isResizeableObjectSelected() ) + pHitSelectionHdl = pDrawViewWrapper->PickHandle( aMPos ); + //only change selection if no selection handles are hit + if( !pHitSelectionHdl ) + { + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && + ( !pDrawViewWrapper->IsMarkedHit( aMPos ) || !m_aSelection.isDragableObjectSelected() ) ) + { + if ( m_aSelection.hasSelection() ) + { + m_aSelection.clearSelection(); + } + if ( !pDrawViewWrapper->IsAction() ) + { + if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Caption ) + { + Size aCaptionSize( 2268, 1134 ); + pDrawViewWrapper->BegCreateCaptionObj( aMPos, aCaptionSize ); + } + else + { + pDrawViewWrapper->BegCreateObj( aMPos); + } + SdrObject* pObj = pDrawViewWrapper->GetCreateObj(); + DrawCommandDispatch* pDrawCommandDispatch = m_aDispatchContainer.getDrawCommandDispatch(); + if ( pObj && m_pDrawModelWrapper && pDrawCommandDispatch ) + { + SfxItemSet aSet( m_pDrawModelWrapper->GetItemPool() ); + pDrawCommandDispatch->setAttributes( pObj ); + pDrawCommandDispatch->setLineEnds( aSet ); + pObj->SetMergedItemSet( aSet ); + } + } + impl_SetMousePointer( rMEvt ); + return; + } + + m_aSelection.adaptSelectionToNewPos( + aMPos, + pDrawViewWrapper, + rMEvt.IsRight(), + m_bWaitingForDoubleClick ); + + if( !m_aSelection.isRotateableObjectSelected( getChartModel() ) ) + { + m_eDragMode = SdrDragMode::Move; + pDrawViewWrapper->SetDragMode(m_eDragMode); + } + + m_aSelection.applySelection(pDrawViewWrapper); + } + if( m_aSelection.isDragableObjectSelected() + && !rMEvt.IsRight() ) + { + //start drag + sal_uInt16 nDrgLog = static_cast(pChartWindow->PixelToLogic(Size(DRGPIX,0)).Width()); + SdrDragMethod* pDragMethod = nullptr; + + //change selection to 3D scene if rotate mode + SdrDragMode eDragMode = pDrawViewWrapper->GetDragMode(); + if( eDragMode==SdrDragMode::Rotate ) + { + E3dScene* pScene = SelectionHelper::getSceneToRotate( pDrawViewWrapper->getNamedSdrObject( m_aSelection.getSelectedCID() ) ); + if( pScene ) + { + DragMethod_RotateDiagram::RotationDirection eRotationDirection(DragMethod_RotateDiagram::ROTATIONDIRECTION_FREE); + if(pHitSelectionHdl) + { + SdrHdlKind eKind = pHitSelectionHdl->GetKind(); + if( eKind==SdrHdlKind::Upper || eKind==SdrHdlKind::Lower ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_X; + else if( eKind==SdrHdlKind::Left || eKind==SdrHdlKind::Right ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Y; + else if( eKind==SdrHdlKind::UpperLeft || eKind==SdrHdlKind::UpperRight || eKind==SdrHdlKind::LowerLeft || eKind==SdrHdlKind::LowerRight ) + eRotationDirection = DragMethod_RotateDiagram::ROTATIONDIRECTION_Z; + } + pDragMethod = new DragMethod_RotateDiagram( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel(), eRotationDirection ); + } + } + else + { + std::u16string_view aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) ); + if( aDragMethodServiceName == ObjectIdentifier::getPieSegmentDragMethodServiceName() ) + pDragMethod = new DragMethod_PieSegment( *pDrawViewWrapper, m_aSelection.getSelectedCID(), getChartModel() ); + } + pDrawViewWrapper->SdrView::BegDragObj(aMPos, nullptr, pHitSelectionHdl, nDrgLog, pDragMethod); + } + + impl_SetMousePointer( rMEvt ); +} + +void ChartController::execute_MouseMove( const MouseEvent& rMEvt ) +{ + SolarMutexGuard aGuard; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper) + return; + + if( m_pDrawViewWrapper->IsTextEdit() ) + { + if( m_pDrawViewWrapper->MouseMove(rMEvt,pChartWindow->GetOutDev()) ) + return; + } + + if(pDrawViewWrapper->IsAction()) + { + pDrawViewWrapper->MovAction( pChartWindow->PixelToLogic( rMEvt.GetPosPixel() ) ); + } + + impl_SetMousePointer( rMEvt ); +} + +void ChartController::execute_MouseButtonUp( const MouseEvent& rMEvt ) +{ + ControllerLockGuardUNO aCLGuard( getChartModel() ); + bool bMouseUpWithoutMouseDown = !m_bWaitingForMouseUp; + m_bWaitingForMouseUp = false; + bool bNotifySelectionChange = false; + { + SolarMutexGuard aGuard; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if(!pChartWindow || !pDrawViewWrapper) + return; + + Point aMPos = pChartWindow->PixelToLogic(rMEvt.GetPosPixel()); + + // Check if button was clicked + if (m_bFieldButtonDown) + { + m_bFieldButtonDown = false; + SdrObject* pObject = pDrawViewWrapper->getHitObject(aMPos); + if (pObject) + { + OUString aCID = pObject->GetName(); + if (aCID.startsWith("FieldButton")) + { + sendPopupRequest(aCID, pObject->GetCurrentBoundRect()); + return; + } + } + } + + if(pDrawViewWrapper->IsTextEdit()) + { + if( pDrawViewWrapper->MouseButtonUp(rMEvt,pChartWindow->GetOutDev()) ) + return; + } + + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && pDrawViewWrapper->IsCreateObj() ) + { + pDrawViewWrapper->EndCreateObj( SdrCreateCmd::ForceEnd ); + { + HiddenUndoContext aUndoContext( m_xUndoManager ); + // don't want the positioning Undo action to appear in the UI + impl_switchDiagramPositioningToExcludingPositioning(); + } + if ( pDrawViewWrapper->AreObjectsMarked() ) + { + if ( pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::Text ) + { + executeDispatch_EditText(); + } + else + { + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if ( pObj ) + { + uno::Reference< drawing::XShape > xShape( pObj->getUnoShape(), uno::UNO_QUERY ); + if ( xShape.is() ) + { + m_aSelection.setSelection( xShape ); + m_aSelection.applySelection( pDrawViewWrapper ); + } + } + } + } + else + { + m_aSelection.adaptSelectionToNewPos( aMPos, pDrawViewWrapper, rMEvt.IsRight(), m_bWaitingForDoubleClick ); + m_aSelection.applySelection( pDrawViewWrapper ); + setDrawMode( CHARTDRAW_SELECT ); + } + } + else if ( pDrawViewWrapper->IsDragObj() ) + { + bool bDraggingDone = false; + SdrDragMethod* pDragMethod = pDrawViewWrapper->SdrView::GetDragMethod(); + bool bIsMoveOnly = pDragMethod && pDragMethod->getMoveOnly(); + DragMethod_Base* pChartDragMethod = dynamic_cast< DragMethod_Base* >(pDragMethod); + if( pChartDragMethod ) + { + UndoGuard aUndoGuard( pChartDragMethod->getUndoDescription(), + m_xUndoManager ); + + if( pDrawViewWrapper->EndDragObj() ) + { + bDraggingDone = true; + aUndoGuard.commit(); + } + } + + if( !bDraggingDone && pDrawViewWrapper->EndDragObj() ) + { + try + { + //end move or size + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if( pObj ) + { + tools::Rectangle aObjectRect = pObj->GetSnapRect(); + tools::Rectangle aOldObjectRect = pObj->GetLastBoundRect(); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + tools::Rectangle aPageRect( 0,0,aPageSize.Width,aPageSize.Height ); + + const E3dObject* pE3dObject(dynamic_cast< const E3dObject*>(pObj)); + if(nullptr != pE3dObject) + { + E3dScene* pScene(pE3dObject->getRootE3dSceneFromE3dObject()); + if(nullptr != pScene) + { + aObjectRect = pScene->GetSnapRect(); + } + } + + ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move); + if( !bIsMoveOnly && m_aSelection.isResizeableObjectSelected() ) + eActionType = ActionDescriptionProvider::ActionType::Resize; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + + UndoGuard aUndoGuard( + ActionDescriptionProvider::createDescription( eActionType, ObjectNameProvider::getName( eObjectType)), + m_xUndoManager ); + + bool bChanged = false; + rtl::Reference< ChartModel > xModel = getChartModel(); + if ( eObjectType == OBJECTTYPE_LEGEND ) + bChanged = DiagramHelper::switchDiagramPositioningToExcludingPositioning( *xModel, false , true ); + + bool bMoved = PositionAndSizeHelper::moveObject( m_aSelection.getSelectedCID() + , xModel + , awt::Rectangle(aObjectRect.Left(),aObjectRect.Top(),aObjectRect.getWidth(),aObjectRect.getHeight()) + , awt::Rectangle(aOldObjectRect.Left(), aOldObjectRect.Top(), 0, 0) + , awt::Rectangle(aPageRect.Left(),aPageRect.Top(),aPageRect.getWidth(),aPageRect.getHeight()) ); + + if( bMoved || bChanged ) + { + bDraggingDone = true; + aUndoGuard.commit(); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //all wanted model changes will take effect + //and all unwanted view modifications are cleaned + } + + if( !bDraggingDone ) //mouse wasn't moved while dragging + { + bool bClickedTwiceOnDragableObject = SelectionHelper::isDragableObjectHitTwice( aMPos, m_aSelection.getSelectedCID(), *pDrawViewWrapper ); + bool bIsRotateable = m_aSelection.isRotateableObjectSelected( getChartModel() ); + + //toggle between move and rotate + if( bIsRotateable && bClickedTwiceOnDragableObject && m_eDragMode==SdrDragMode::Move ) + m_eDragMode=SdrDragMode::Rotate; + else + m_eDragMode=SdrDragMode::Move; + + pDrawViewWrapper->SetDragMode(m_eDragMode); + + if( !m_bWaitingForDoubleClick && m_aSelection.maybeSwitchSelectionAfterSingleClickWasEnsured() ) + { + impl_selectObjectAndNotiy(); + } + } + else + m_aSelection.resetPossibleSelectionAfterSingleClickWasEnsured(); + } + + //@todo ForcePointer(&rMEvt); + pChartWindow->ReleaseMouse(); + + // In tiled rendering drag mode could be not yet over on the call + // that should handle the double-click, so better to perform this check + // always. + if( isDoubleClick(rMEvt) && !bMouseUpWithoutMouseDown /*#i106966#*/ ) + { + Point aMousePixel = rMEvt.GetPosPixel(); + execute_DoubleClick( &aMousePixel ); + } + + if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() ) + bNotifySelectionChange = true; + } + + impl_SetMousePointer( rMEvt ); + + if(bNotifySelectionChange) + impl_notifySelectionChangeListeners(); +} + +void ChartController::execute_DoubleClick( const Point* pMousePixel ) +{ + const SfxViewShell* pViewShell = SfxViewShell::Current(); + bool isMobilePhone = pViewShell && pViewShell->isLOKMobilePhone(); + if (isMobilePhone) + return; + + bool bEditText = false; + if ( m_aSelection.hasSelection() ) + { + OUString aCID( m_aSelection.getSelectedCID() ); + if ( !aCID.isEmpty() ) + { + ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); + if ( eObjectType == OBJECTTYPE_TITLE ) + { + bEditText = true; + } + } + else + { + // #i12587# support for shapes in chart + SdrObject* pObj = DrawViewWrapper::getSdrObject( m_aSelection.getSelectedAdditionalShape() ); + if ( dynamic_cast< const SdrTextObj* >(pObj) != nullptr ) + { + bEditText = true; + } + } + } + + if ( bEditText ) + { + executeDispatch_EditText( pMousePixel ); + } + else + { + executeDispatch_ObjectProperties(); + } +} + +void ChartController::execute_Resize() +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + if(pChartWindow) + pChartWindow->Invalidate(); +} + +void ChartController::execute_Command( const CommandEvent& rCEvt ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + bool bIsAction = false; + { + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if(!pChartWindow || !pDrawViewWrapper) + return; + bIsAction = m_pDrawViewWrapper->IsAction(); + } + + // pop-up menu + if(rCEvt.GetCommand() == CommandEventId::ContextMenu && !bIsAction) + { + { + if(pChartWindow) + pChartWindow->ReleaseMouse(); + } + + if( m_aSelection.isSelectionDifferentFromBeforeMouseDown() ) + impl_notifySelectionChangeListeners(); + + rtl::Reference< VCLXPopupMenu > xPopupMenu = new VCLXPopupMenu(); + + Point aPos( rCEvt.GetMousePosPixel() ); + if( !rCEvt.IsMouseEvent() ) + { + if(pChartWindow) + aPos = pChartWindow->GetPointerState().maPos; + } + + OUString aMenuName; + if ( isShapeContext() ) + // #i12587# support for shapes in chart + aMenuName = m_pDrawViewWrapper->IsTextEdit() ? std::u16string_view( u"drawtext" ) : std::u16string_view( u"draw" ); + else + { + // todo: the context menu should be specified by an xml file in uiconfig + sal_Int16 nUniqueId = 1; + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Cut" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Copy" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:Paste" ); + xPopupMenu->insertSeparator( -1 ); + + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + rtl::Reference< Diagram > xDiagram = getFirstDiagram(); + + OUString aFormatCommand( lcl_getFormatCommandForObjectCID( m_aSelection.getSelectedCID() ) ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, aFormatCommand ); + + //some commands for dataseries and points: + + if( eObjectType == OBJECTTYPE_DATA_SERIES || eObjectType == OBJECTTYPE_DATA_POINT ) + { + bool bIsPoint = ( eObjectType == OBJECTTYPE_DATA_POINT ); + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( m_aSelection.getSelectedCID(), getChartModel() ); + rtl::Reference< RegressionCurveModel > xTrendline = RegressionCurveHelper::getFirstCurveNotMeanValueLine( xSeries ); + bool bHasEquation = RegressionCurveHelper::hasEquation( xTrendline ); + rtl::Reference< RegressionCurveModel > xMeanValue = RegressionCurveHelper::getMeanValueLine( xSeries ); + bool bHasYErrorBars = StatisticsHelper::hasErrorBars( xSeries ); + bool bHasXErrorBars = StatisticsHelper::hasErrorBars( xSeries, false ); + bool bHasDataLabelsAtSeries = DataSeriesHelper::hasDataLabelsAtSeries( xSeries ); + bool bHasDataLabelsAtPoints = DataSeriesHelper::hasDataLabelsAtPoints( xSeries ); + bool bHasDataLabelAtPoint = false; + sal_Int32 nPointIndex = -1; + if( bIsPoint ) + { + nPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( m_aSelection.getSelectedCID() ); + bHasDataLabelAtPoint = DataSeriesHelper::hasDataLabelAtPoint( xSeries, nPointIndex ); + } + bool bSelectedPointIsFormatted = false; + bool bHasFormattedDataPointsOtherThanSelected = false; + + if( xSeries.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + if( aAttributedDataPointIndexList.hasElements() ) + { + if( bIsPoint ) + { + auto aIt = std::find( std::as_const(aAttributedDataPointIndexList).begin(), std::as_const(aAttributedDataPointIndexList).end(), nPointIndex ); + if( aIt != std::as_const(aAttributedDataPointIndexList).end()) + bSelectedPointIsFormatted = true; + else + bHasFormattedDataPointsOtherThanSelected = true; + } + else + bHasFormattedDataPointsOtherThanSelected = true; + } + } + } + + if( bIsPoint ) + { + if( bHasDataLabelAtPoint ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabel" ); + if( !bHasDataLabelAtPoint ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabel" ); + else + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabel" ); + if( bSelectedPointIsFormatted ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetDataPoint" ); + + xPopupMenu->insertSeparator( -1 ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataSeries" ); + } + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ) ); + if( xChartType->getChartType() == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + { + try + { + bool bJapaneseStyle = false; + xChartType->getPropertyValue( "Japanese" ) >>= bJapaneseStyle; + + if( bJapaneseStyle ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( bHasDataLabelsAtSeries ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatDataLabels" ); + if( bHasEquation ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" ); + if( xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMeanValue" ); + if( bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatXErrorBars" ); + if( bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatYErrorBars" ); + + xPopupMenu->insertSeparator( -1 ); + + if( !bHasDataLabelsAtSeries ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertDataLabels" ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendline" ); + + if( !xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMeanValue" ); + if( !bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertXErrorBars" ); + if( !bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertYErrorBars" ); + if( bHasDataLabelsAtSeries || ( bHasDataLabelsAtPoints && bHasFormattedDataPointsOtherThanSelected ) ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteDataLabels" ); + if( bHasEquation ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" ); + if( xMeanValue.is() ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMeanValue" ); + if( bHasXErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteXErrorBars" ); + if( bHasYErrorBars ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteYErrorBars" ); + + if( bHasFormattedDataPointsOtherThanSelected ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:ResetAllDataPoints" ); + + xPopupMenu->insertSeparator( -1 ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId, ".uno:ArrangeRow" ); + rtl::Reference< VCLXPopupMenu > xArrangePopupMenu = new VCLXPopupMenu(); + sal_Int16 nSubId = nUniqueId + 1; + lcl_insertMenuCommand( xArrangePopupMenu, nSubId++, ".uno:Forward" ); + lcl_insertMenuCommand( xArrangePopupMenu, nSubId, ".uno:Backward" ); + xPopupMenu->setPopupMenu( nUniqueId, xArrangePopupMenu ); + nUniqueId = nSubId; + ++nUniqueId; + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendline" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTrendlineEquationAndR2" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteTrendlineEquation" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" ); + } + else if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) + { + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertR2Value" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteR2Value" ); + } + + //some commands for axes: and grids + + else if( eObjectType == OBJECTTYPE_AXIS || eObjectType == OBJECTTYPE_GRID || eObjectType == OBJECTTYPE_SUBGRID ) + { + rtl::Reference< Axis > xAxis = ObjectIdentifier::getAxisForCID( m_aSelection.getSelectedCID(), getChartModel() ); + if( xAxis.is() && xDiagram.is() ) + { + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); + bool bIsSecondaryAxis = nAxisIndex!=0; + bool bIsAxisVisible = AxisHelper::isAxisVisible( xAxis ); + bool bIsMajorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, true /*bMainGrid*/, xDiagram ); + bool bIsMinorGridVisible = AxisHelper::isGridShown( nDimensionIndex, nCooSysIndex, false /*bMainGrid*/, xDiagram ); + bool bHasTitle = !TitleHelper::getCompleteString( xAxis->getTitleObject() ).isEmpty(); + + if( eObjectType != OBJECTTYPE_AXIS && bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatAxis" ); + if( eObjectType != OBJECTTYPE_GRID && bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMajorGrid" ); + if( eObjectType != OBJECTTYPE_SUBGRID && bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatMinorGrid" ); + + xPopupMenu->insertSeparator( -1 ); + + if( eObjectType != OBJECTTYPE_AXIS && !bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxis" ); + if( eObjectType != OBJECTTYPE_GRID && !bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMajorGrid" ); + if( eObjectType != OBJECTTYPE_SUBGRID && !bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertMinorGrid" ); + if( !bHasTitle ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertAxisTitle" ); + + if( bIsAxisVisible ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteAxis" ); + if( bIsMajorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMajorGrid" ); + if( bIsMinorGridVisible && !bIsSecondaryAxis ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteMinorGrid" ); + } + } + + if( eObjectType == OBJECTTYPE_DATA_STOCK_LOSS ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockGain" ); + else if( eObjectType == OBJECTTYPE_DATA_STOCK_GAIN ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:FormatStockLoss" ); + + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:TransformDialog" ); + + if( eObjectType == OBJECTTYPE_PAGE || eObjectType == OBJECTTYPE_DIAGRAM + || eObjectType == OBJECTTYPE_DIAGRAM_WALL + || eObjectType == OBJECTTYPE_DIAGRAM_FLOOR + || eObjectType == OBJECTTYPE_UNKNOWN ) + { + if( eObjectType != OBJECTTYPE_UNKNOWN ) + xPopupMenu->insertSeparator( -1 ); + bool bHasLegend = LegendHelper::hasLegend( xDiagram ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertTitles" ); + if( !bHasLegend ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertLegend" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:InsertRemoveAxes" ); + if( bHasLegend ) + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DeleteLegend" ); + } + + xPopupMenu->insertSeparator( -1 ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramType" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DataRanges" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:DiagramData" ); + lcl_insertMenuCommand( xPopupMenu, nUniqueId++, ".uno:View3D" ); + } + + css::uno::Sequence< css::uno::Any > aArgs{ + css::uno::Any(comphelper::makePropertyValue( "IsContextMenu", true )), + css::uno::Any(comphelper::makePropertyValue( "Frame", m_xFrame )), + css::uno::Any(comphelper::makePropertyValue( "Value", aMenuName )) + }; + + css::uno::Reference< css::frame::XPopupMenuController > xPopupController( + m_xCC->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, m_xCC ), css::uno::UNO_QUERY ); + + if ( !xPopupController.is() || !xPopupMenu.is() ) + return; + + xPopupController->setPopupMenu( xPopupMenu ); + + if (comphelper::LibreOfficeKit::isActive()) + { + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + { + ControllerCommandDispatch* pCommandDispatch = dynamic_cast(m_aDispatchContainer.getChartDispatcher().get()); + if (pCommandDispatch) + { + for (int nPos = 0, nCount = xPopupMenu->getItemCount(); nPos < nCount; ++nPos) + { + auto nItemId = xPopupMenu->getItemId(nPos); + OUString aCommandURL = xPopupMenu->getCommand(nItemId); + if (!pCommandDispatch->commandAvailable(aCommandURL)) + xPopupMenu->enableItem(nItemId, false); + } + } + + boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xPopupMenu); + boost::property_tree::ptree aRoot; + aRoot.add_child("menu", aMenu); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aRoot, true); + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str()); + } + } + else + { + xPopupMenu->execute( css::uno::Reference< css::awt::XWindowPeer >( m_xFrame->getContainerWindow(), css::uno::UNO_QUERY ), + css::awt::Rectangle( aPos.X(), aPos.Y(), 0, 0 ), + css::awt::PopupMenuDirection::EXECUTE_DEFAULT ); + } + + css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + } + else if( ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::ExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput ) || + ( rCEvt.GetCommand() == CommandEventId::InputContextChange ) ) + { + //#i84417# enable editing with IME + m_pDrawViewWrapper->Command( rCEvt, pChartWindow ); + } +} + +bool ChartController::execute_KeyInput( const KeyEvent& rKEvt ) +{ + SolarMutexGuard aGuard; + bool bReturn=false; + + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + auto pChartWindow(GetChartWindow()); + if (!pChartWindow || !pDrawViewWrapper) + return bReturn; + + // handle accelerators + if (!m_apAccelExecute && m_xFrame.is() && m_xCC.is()) + { + m_apAccelExecute = ::svt::AcceleratorExecute::createAcceleratorHelper(); + OSL_ASSERT(m_apAccelExecute); + if (m_apAccelExecute) + m_apAccelExecute->init( m_xCC, m_xFrame ); + } + + vcl::KeyCode aKeyCode( rKEvt.GetKeyCode()); + sal_uInt16 nCode = aKeyCode.GetCode(); + bool bAlternate = aKeyCode.IsMod2(); + bool bCtrl = aKeyCode.IsMod1(); + + if (m_apAccelExecute) + bReturn = m_apAccelExecute->execute( aKeyCode ); + if( bReturn ) + return bReturn; + + { + if( pDrawViewWrapper->IsTextEdit() ) + { + if( pDrawViewWrapper->KeyInput(rKEvt, pChartWindow) ) + { + bReturn = true; + if( nCode == KEY_ESCAPE ) + { + EndTextEdit(); + } + } + } + } + + // keyboard accessibility + ObjectType eObjectType = ObjectIdentifier::getObjectType( m_aSelection.getSelectedCID() ); + if( ! bReturn ) + { + // Navigation (Tab/F3/Home/End) + rtl::Reference<::chart::ChartModel> xChartDoc( getChartModel() ); + ObjectKeyNavigation aObjNav( m_aSelection.getSelectedOID(), xChartDoc, comphelper::getFromUnoTunnel( m_xChartView )); + awt::KeyEvent aKeyEvent( ::svt::AcceleratorExecute::st_VCLKey2AWTKey( aKeyCode )); + bReturn = aObjNav.handleKeyEvent( aKeyEvent ); + if( bReturn ) + { + const ObjectIdentifier& aNewOID = aObjNav.getCurrentSelection(); + uno::Any aNewSelection; + if ( aNewOID.isValid() && !ObjectHierarchy::isRootNode( aNewOID ) ) + { + aNewSelection = aNewOID.getAny(); + } + if ( m_eDragMode == SdrDragMode::Rotate && !SelectionHelper::isRotateableObject( aNewOID.getObjectCID(), getChartModel() ) ) + { + m_eDragMode = SdrDragMode::Move; + } + bReturn = select( aNewSelection ); + } + } + + // Position and Size (+/-/arrow-keys) or pie segment dragging + if( ! bReturn ) + { + // pie segment dragging + // note: could also be done for data series + if( eObjectType == OBJECTTYPE_DATA_POINT && + ObjectIdentifier::getDragMethodServiceName( m_aSelection.getSelectedCID() ) == + ObjectIdentifier::getPieSegmentDragMethodServiceName()) + { + bool bDrag = false; + bool bDragInside = false; + if( nCode == KEY_ADD || + nCode == KEY_SUBTRACT ) + { + bDrag = true; + bDragInside = ( nCode == KEY_SUBTRACT ); + } + else if( + nCode == KEY_LEFT || + nCode == KEY_RIGHT || + nCode == KEY_UP || + nCode == KEY_DOWN ) + { + bDrag = true; + std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aSelection.getSelectedCID() )); + sal_Int32 nOffsetPercentDummy( 0 ); + awt::Point aMinimumPosition( 0, 0 ); + awt::Point aMaximumPosition( 0, 0 ); + ObjectIdentifier::parsePieSegmentDragParameterString( + aParameter, nOffsetPercentDummy, aMinimumPosition, aMaximumPosition ); + aMaximumPosition.Y -= aMinimumPosition.Y; + aMaximumPosition.X -= aMinimumPosition.X; + + bDragInside = + (nCode == KEY_RIGHT && (aMaximumPosition.X < 0)) || + (nCode == KEY_LEFT && (aMaximumPosition.X > 0)) || + (nCode == KEY_DOWN && (aMaximumPosition.Y < 0)) || + (nCode == KEY_UP && (aMaximumPosition.Y > 0)); + } + + if( bDrag ) + { + double fAmount = bAlternate ? 0.01 : 0.05; + if( bDragInside ) + fAmount *= -1.0; + + bReturn = impl_DragDataPoint( m_aSelection.getSelectedCID(), fAmount ); + } + } + else + { + // size + if( nCode == KEY_ADD || + nCode == KEY_SUBTRACT ) + { + if( eObjectType == OBJECTTYPE_DIAGRAM ) + { + // default 1 mm in each direction + double fGrowAmountX = 200.0; + double fGrowAmountY = 200.0; + if (bAlternate) + { + // together with Alt-key: 1 px in each direction + Size aPixelSize = pChartWindow->PixelToLogic( Size( 2, 2 )); + fGrowAmountX = static_cast< double >( aPixelSize.Width()); + fGrowAmountY = static_cast< double >( aPixelSize.Height()); + } + if( nCode == KEY_SUBTRACT ) + { + fGrowAmountX = -fGrowAmountX; + fGrowAmountY = -fGrowAmountY; + } + bReturn = impl_moveOrResizeObject( + m_aSelection.getSelectedCID(), CENTERED_RESIZE_OBJECT, fGrowAmountX, fGrowAmountY ); + } + } + // position + else if( nCode == KEY_LEFT || + nCode == KEY_RIGHT || + nCode == KEY_UP || + nCode == KEY_DOWN ) + { + if( m_aSelection.isDragableObjectSelected() ) + { + // default 1 mm + double fShiftAmountX = 100.0; + double fShiftAmountY = 100.0; + if (bAlternate) + { + // together with Alt-key: 1 px + Size aPixelSize = pChartWindow->PixelToLogic( Size( 1, 1 )); + fShiftAmountX = static_cast< double >( aPixelSize.Width()); + fShiftAmountY = static_cast< double >( aPixelSize.Height()); + } + switch( nCode ) + { + case KEY_LEFT: + fShiftAmountX = -fShiftAmountX; + fShiftAmountY = 0.0; + break; + case KEY_RIGHT: + fShiftAmountY = 0.0; + break; + case KEY_UP: + fShiftAmountX = 0.0; + fShiftAmountY = -fShiftAmountY; + break; + case KEY_DOWN: + fShiftAmountX = 0.0; + break; + } + if( !m_aSelection.getSelectedCID().isEmpty() ) + { + //move chart objects + if (eObjectType == OBJECTTYPE_DATA_LABEL) + { + SdrObject* pObj = pDrawViewWrapper->getSelectedObject(); + if (pObj) + { + tools::Rectangle aRect = pObj->GetSnapRect(); + awt::Size aPageSize(ChartModelHelper::getPageSize(getChartModel())); + if ((fShiftAmountX > 0.0 && (aRect.Right() + fShiftAmountX > aPageSize.Width)) || + (fShiftAmountX < 0.0 && (aRect.Left() + fShiftAmountX < 0)) || + (fShiftAmountY > 0.0 && (aRect.Bottom() + fShiftAmountY > aPageSize.Height)) || + (fShiftAmountY < 0.0 && (aRect.Top() + fShiftAmountY < 0))) + bReturn = false; + else + bReturn = PositionAndSizeHelper::moveObject( + m_aSelection.getSelectedCID(), getChartModel(), + awt::Rectangle(aRect.Left() + fShiftAmountX, aRect.Top() + fShiftAmountY, aRect.getWidth(), aRect.getHeight()), + awt::Rectangle(aRect.Left(), aRect.Top(), 0, 0), + awt::Rectangle(0, 0, aPageSize.Width, aPageSize.Height)); + } + } + else + bReturn = impl_moveOrResizeObject( + m_aSelection.getSelectedCID(), MOVE_OBJECT, fShiftAmountX, fShiftAmountY ); + } + else + { + //move additional shapes + uno::Reference< drawing::XShape > xShape( m_aSelection.getSelectedAdditionalShape() ); + if( xShape.is() ) + { + awt::Point aPos( xShape->getPosition() ); + awt::Size aSize( xShape->getSize() ); + awt::Size aPageSize( ChartModelHelper::getPageSize( getChartModel() ) ); + aPos.X = static_cast< tools::Long >( static_cast< double >( aPos.X ) + fShiftAmountX ); + aPos.Y = static_cast< tools::Long >( static_cast< double >( aPos.Y ) + fShiftAmountY ); + if( aPos.X + aSize.Width > aPageSize.Width ) + aPos.X = aPageSize.Width - aSize.Width; + if( aPos.X < 0 ) + aPos.X = 0; + if( aPos.Y + aSize.Height > aPageSize.Height ) + aPos.Y = aPageSize.Height - aSize.Height; + if( aPos.Y < 0 ) + aPos.Y = 0; + + xShape->setPosition( aPos ); + } + } + } + } + } + } + + // dumping the shape + if( !bReturn && bCtrl && nCode == KEY_F12) + { + rtl::Reference< ChartModel > xChartModel = getChartModel(); + if(xChartModel.is()) + { + OUString aDump = xChartModel->dump(); + SAL_WARN("chart2", aDump); + } + } + + // text edit + if( ! bReturn && + nCode == KEY_F2 ) + { + if( eObjectType == OBJECTTYPE_TITLE ) + { + executeDispatch_EditText(); + bReturn = true; + } + } + + // deactivate inplace mode (this code should be unnecessary, but + // unfortunately is not) + if( ! bReturn && + nCode == KEY_ESCAPE ) + { + uno::Reference< frame::XDispatchHelper > xDispatchHelper( frame::DispatchHelper::create(m_xCC) ); + uno::Sequence< beans::PropertyValue > aArgs; + xDispatchHelper->executeDispatch( + uno::Reference< frame::XDispatchProvider >( m_xFrame, uno::UNO_QUERY ), + ".uno:TerminateInplaceActivation", + "_parent", + frame::FrameSearchFlag::PARENT, + aArgs ); + bReturn = true; + } + + if( ! bReturn && + (nCode == KEY_DELETE || nCode == KEY_BACKSPACE )) + { + bReturn = executeDispatch_Delete(); + if( ! bReturn ) + { + std::unique_ptr xInfoBox(Application::CreateMessageDialog(pChartWindow->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SchResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + } + + return bReturn; +} + +bool ChartController::requestQuickHelp( + ::Point aAtLogicPosition, + bool bIsBalloonHelp, + OUString & rOutQuickHelpText, + awt::Rectangle & rOutEqualRect ) +{ + rtl::Reference<::chart::ChartModel> xChartModel; + if( m_aModel.is()) + xChartModel = getChartModel(); + if( !xChartModel.is()) + return false; + + // help text + OUString aCID; + if( m_pDrawViewWrapper ) + { + aCID = SelectionHelper::getHitObjectCID( + aAtLogicPosition, *m_pDrawViewWrapper ); + } + bool bResult( !aCID.isEmpty()); + + if( bResult ) + { + // get help text + rOutQuickHelpText = ObjectNameProvider::getHelpText( aCID, xChartModel, bIsBalloonHelp /* bVerbose */ ); + + // set rectangle + ExplicitValueProvider * pValueProvider( + comphelper::getFromUnoTunnel( m_xChartView )); + if( pValueProvider ) + rOutEqualRect = pValueProvider->getRectangleOfObject( aCID, true ); + } + + return bResult; +} + +// XSelectionSupplier (optional interface) +sal_Bool SAL_CALL ChartController::select( const uno::Any& rSelection ) +{ + bool bSuccess = false; + + if ( rSelection.hasValue() ) + { + const uno::Type& rType = rSelection.getValueType(); + if ( rType == cppu::UnoType< OUString >::get() ) + { + OUString aNewCID; + if ( ( rSelection >>= aNewCID ) && m_aSelection.setSelection( aNewCID ) ) + { + bSuccess = true; + } + } + else if ( rType == cppu::UnoType::get() ) + { + uno::Reference< drawing::XShape > xShape; + if ( ( rSelection >>= xShape ) && m_aSelection.setSelection( xShape ) ) + { + bSuccess = true; + } + } + } + else + { + if ( m_aSelection.hasSelection() ) + { + m_aSelection.clearSelection(); + bSuccess = true; + } + } + + if ( bSuccess ) + { + SolarMutexGuard aGuard; + if ( m_pDrawViewWrapper && m_pDrawViewWrapper->IsTextEdit() ) + { + EndTextEdit(); + } + impl_selectObjectAndNotiy(); + auto pChartWindow(GetChartWindow()); + if ( pChartWindow ) + { + pChartWindow->Invalidate(); + } + return true; + } + + return false; +} + +uno::Any SAL_CALL ChartController::getSelection() +{ + uno::Any aReturn; + if ( m_aSelection.hasSelection() ) + { + OUString aCID( m_aSelection.getSelectedCID() ); + if ( !aCID.isEmpty() ) + { + aReturn <<= aCID; + } + else + { + // #i12587# support for shapes in chart + aReturn <<= m_aSelection.getSelectedAdditionalShape(); + } + } + return aReturn; +} + +void SAL_CALL ChartController::addSelectionChangeListener( const uno::Reference & xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() )//@todo? allow adding of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--add listener + m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType::get(), xListener ); +} + +void SAL_CALL ChartController::removeSelectionChangeListener( const uno::Reference & xListener ) +{ + SolarMutexGuard aGuard; + if( impl_isDisposedOrSuspended() ) //@todo? allow removing of listeners in suspend mode? + return; //behave passive if already disposed or suspended + + //--remove listener + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType::get(), xListener ); +} + +void ChartController::impl_notifySelectionChangeListeners() +{ + ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer + .getContainer( cppu::UnoType::get() ); + if( pIC ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupplier(this); + lang::EventObject aEvent( xSelectionSupplier ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< view::XSelectionChangeListener* >( aIt.next() )->selectionChanged( aEvent ); + } + } +} + +void ChartController::impl_selectObjectAndNotiy() +{ + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pDrawViewWrapper.get(); + if( pDrawViewWrapper ) + { + pDrawViewWrapper->SetDragMode( m_eDragMode ); + m_aSelection.applySelection( m_pDrawViewWrapper.get() ); + } + } + impl_notifySelectionChangeListeners(); +} + +bool ChartController::impl_moveOrResizeObject( + const OUString & rCID, + eMoveOrResizeType eType, + double fAmountLogicX, + double fAmountLogicY ) +{ + bool bResult = false; + bool bNeedResize = ( eType == CENTERED_RESIZE_OBJECT ); + + rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() ); + uno::Reference< beans::XPropertySet > xObjProp( + ObjectIdentifier::getObjectPropertySet( rCID, xChartModel )); + if( xObjProp.is()) + { + awt::Size aRefSize = ChartModelHelper::getPageSize( xChartModel ); + + chart2::RelativePosition aRelPos; + chart2::RelativeSize aRelSize; + bool bDeterminePos = !(xObjProp->getPropertyValue( "RelativePosition") >>= aRelPos); + bool bDetermineSize = !bNeedResize || !(xObjProp->getPropertyValue( "RelativeSize") >>= aRelSize); + + if( ( bDeterminePos || bDetermineSize ) && + ( aRefSize.Width > 0 && aRefSize.Height > 0 ) ) + { + ExplicitValueProvider * pValueProvider( + comphelper::getFromUnoTunnel( m_xChartView )); + if( pValueProvider ) + { + awt::Rectangle aRect( pValueProvider->getRectangleOfObject( rCID )); + double fWidth = static_cast< double >( aRefSize.Width ); + double fHeight = static_cast< double >( aRefSize.Height ); + if( bDetermineSize ) + { + aRelSize.Primary = static_cast< double >( aRect.Width ) / fWidth; + aRelSize.Secondary = static_cast< double >( aRect.Height ) / fHeight; + } + if( bDeterminePos ) + { + if( bNeedResize && aRelSize.Primary > 0.0 && aRelSize.Secondary > 0.0 ) + { + aRelPos.Primary = (static_cast< double >( aRect.X ) / fWidth) + + (aRelSize.Primary / 2.0); + aRelPos.Secondary = (static_cast< double >( aRect.Y ) / fHeight) + + (aRelSize.Secondary / 2.0); + aRelPos.Anchor = drawing::Alignment_CENTER; + } + else + { + aRelPos.Primary = static_cast< double >( aRect.X ) / fWidth; + aRelPos.Secondary = static_cast< double >( aRect.Y ) / fHeight; + aRelPos.Anchor = drawing::Alignment_TOP_LEFT; + } + } + } + } + + if( eType == CENTERED_RESIZE_OBJECT ) + bResult = lcl_GrowAndShiftLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY ); + else if( eType == MOVE_OBJECT ) + bResult = lcl_MoveObjectLogic( aRelPos, aRelSize, aRefSize, fAmountLogicX, fAmountLogicY ); + + if( bResult ) + { + ActionDescriptionProvider::ActionType eActionType(ActionDescriptionProvider::ActionType::Move); + if( bNeedResize ) + eActionType = ActionDescriptionProvider::ActionType::Resize; + + ObjectType eObjectType = ObjectIdentifier::getObjectType( rCID ); + UndoGuard aUndoGuard( ActionDescriptionProvider::createDescription( + eActionType, ObjectNameProvider::getName( eObjectType )), m_xUndoManager ); + { + ControllerLockGuardUNO aCLGuard( xChartModel ); + xObjProp->setPropertyValue( "RelativePosition", uno::Any( aRelPos )); + if( bNeedResize || (eObjectType == OBJECTTYPE_DIAGRAM) )//Also set an explicit size at the diagram when an explicit position is set + xObjProp->setPropertyValue( "RelativeSize", uno::Any( aRelSize )); + } + aUndoGuard.commit(); + } + } + return bResult; +} + +bool ChartController::impl_DragDataPoint( const OUString & rCID, double fAdditionalOffset ) +{ + bool bResult = false; + if( fAdditionalOffset < -1.0 || fAdditionalOffset > 1.0 || fAdditionalOffset == 0.0 ) + return bResult; + + sal_Int32 nDataPointIndex = ObjectIdentifier::getIndexFromParticleOrCID( rCID ); + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID( rCID, getChartModel() ); + if( xSeries.is()) + { + try + { + uno::Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex( nDataPointIndex )); + double fOffset = 0.0; + if( xPointProp.is() && + (xPointProp->getPropertyValue( "Offset" ) >>= fOffset ) && + (( fAdditionalOffset > 0.0 && fOffset < 1.0 ) || (fOffset > 0.0)) ) + { + fOffset += fAdditionalOffset; + if( fOffset > 1.0 ) + fOffset = 1.0; + else if( fOffset < 0.0 ) + fOffset = 0.0; + xPointProp->setPropertyValue( "Offset", uno::Any( fOffset )); + bResult = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +void ChartController::impl_SetMousePointer( const MouseEvent & rEvent ) +{ + SolarMutexGuard aGuard; + auto pChartWindow(GetChartWindow()); + + if (!m_pDrawViewWrapper || !pChartWindow) + return; + + Point aMousePos( pChartWindow->PixelToLogic( rEvent.GetPosPixel())); + sal_uInt16 nModifier = rEvent.GetModifier(); + bool bLeftDown = rEvent.IsLeft(); + + // Check if object is for field button and set the normal arrow pointer in this case + SdrObject* pObject = m_pDrawViewWrapper->getHitObject(aMousePos); + if (pObject && pObject->GetName().startsWith("FieldButton")) + { + pChartWindow->SetPointer(PointerStyle::Arrow); + return; + } + + if ( m_pDrawViewWrapper->IsTextEdit() ) + { + if( m_pDrawViewWrapper->IsTextEditHit( aMousePos ) ) + { + pChartWindow->SetPointer( m_pDrawViewWrapper->GetPreferredPointer( + aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown ) ); + return; + } + } + else if( m_pDrawViewWrapper->IsAction() ) + { + return;//don't change pointer during running action + } + + SdrHdl* pHitSelectionHdl = nullptr; + if( m_aSelection.isResizeableObjectSelected() ) + pHitSelectionHdl = m_pDrawViewWrapper->PickHandle( aMousePos ); + + if( pHitSelectionHdl ) + { + PointerStyle aPointer = m_pDrawViewWrapper->GetPreferredPointer( + aMousePos, pChartWindow->GetOutDev(), nModifier, bLeftDown ); + bool bForceArrowPointer = false; + + ObjectIdentifier aOID( m_aSelection.getSelectedOID() ); + + switch( aPointer) + { + case PointerStyle::NSize: + case PointerStyle::SSize: + case PointerStyle::WSize: + case PointerStyle::ESize: + case PointerStyle::NWSize: + case PointerStyle::NESize: + case PointerStyle::SWSize: + case PointerStyle::SESize: + if( ! m_aSelection.isResizeableObjectSelected() ) + bForceArrowPointer = true; + break; + case PointerStyle::Move: + if ( !aOID.isDragableObject() ) + bForceArrowPointer = true; + break; + case PointerStyle::MovePoint: + case PointerStyle::MoveBezierWeight: + // there is no point-editing in a chart + // the PointerStyle::MoveBezierWeight appears in 3d data points + bForceArrowPointer = true; + break; + default: + break; + } + + if( bForceArrowPointer ) + pChartWindow->SetPointer( PointerStyle::Arrow ); + else + pChartWindow->SetPointer( aPointer ); + + return; + } + + // #i12587# support for shapes in chart + if ( m_eDrawMode == CHARTDRAW_INSERT && + ( !m_pDrawViewWrapper->IsMarkedHit( aMousePos ) || !m_aSelection.isDragableObjectSelected() ) ) + { + PointerStyle ePointerStyle = PointerStyle::DrawRect; + SdrObjKind eKind = m_pDrawViewWrapper->GetCurrentObjIdentifier(); + switch ( eKind ) + { + case SdrObjKind::Line: + { + ePointerStyle = PointerStyle::DrawLine; + } + break; + case SdrObjKind::Rectangle: + case SdrObjKind::CustomShape: + { + ePointerStyle = PointerStyle::DrawRect; + } + break; + case SdrObjKind::CircleOrEllipse: + { + ePointerStyle = PointerStyle::DrawEllipse; + } + break; + case SdrObjKind::FreehandLine: + { + ePointerStyle = PointerStyle::DrawPolygon; + } + break; + case SdrObjKind::Text: + { + ePointerStyle = PointerStyle::DrawText; + } + break; + case SdrObjKind::Caption: + { + ePointerStyle = PointerStyle::DrawCaption; + } + break; + default: + { + ePointerStyle = PointerStyle::DrawRect; + } + break; + } + pChartWindow->SetPointer( ePointerStyle ); + return; + } + + OUString aHitObjectCID( + SelectionHelper::getHitObjectCID( + aMousePos, *m_pDrawViewWrapper, true /*bGetDiagramInsteadOf_Wall*/ )); + + if( m_pDrawViewWrapper->IsTextEdit() ) + { + if( aHitObjectCID == m_aSelection.getSelectedCID() ) + { + pChartWindow->SetPointer( PointerStyle::Arrow ); + return; + } + } + + if( aHitObjectCID.isEmpty() ) + { + //additional shape was hit + pChartWindow->SetPointer( PointerStyle::Move ); + } + else if( ObjectIdentifier::isDragableObject( aHitObjectCID ) ) + { + if( (m_eDragMode == SdrDragMode::Rotate) + && SelectionHelper::isRotateableObject( aHitObjectCID + , getChartModel() ) ) + pChartWindow->SetPointer( PointerStyle::Rotate ); + else + { + ObjectType eHitObjectType = ObjectIdentifier::getObjectType( aHitObjectCID ); + if( eHitObjectType == OBJECTTYPE_DATA_POINT ) + { + if( !ObjectIdentifier::areSiblings(aHitObjectCID,m_aSelection.getSelectedCID()) + && !ObjectIdentifier::areIdenticalObjects(aHitObjectCID,m_aSelection.getSelectedCID()) ) + { + pChartWindow->SetPointer( PointerStyle::Arrow ); + return; + } + } + pChartWindow->SetPointer( PointerStyle::Move ); + } + } + else + pChartWindow->SetPointer( PointerStyle::Arrow ); +} + +css::uno::Reference const & ChartController::getChartView() const +{ + return m_xChartView; +} + +void ChartController::sendPopupRequest(OUString const & rCID, tools::Rectangle aRectangle) +{ + ChartModel* pChartModel = m_aModel->getModel().get(); + if (!pChartModel) + return; + + uno::Reference xPivotTableDataProvider; + xPivotTableDataProvider.set(pChartModel->getDataProvider(), uno::UNO_QUERY); + if (!xPivotTableDataProvider.is()) + return; + + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + + css::uno::Reference xPopupRequest = pChartModel->getPopupRequest(); + PopupRequest* pPopupRequest = dynamic_cast(xPopupRequest.get()); + if (!pPopupRequest) + return; + + // Get dimension index from CID + sal_Int32 nStartPos = rCID.lastIndexOf('.'); + nStartPos++; + sal_Int32 nEndPos = rCID.getLength(); + std::u16string_view sDimensionIndex = rCID.subView(nStartPos, nEndPos - nStartPos); + sal_Int32 nDimensionIndex = o3tl::toInt32(sDimensionIndex); + + awt::Rectangle xRectangle { + sal_Int32(aRectangle.Left()), + sal_Int32(aRectangle.Top()), + sal_Int32(aRectangle.GetWidth()), + sal_Int32(aRectangle.GetHeight()) + }; + + uno::Sequence aCallbackData = comphelper::InitPropertySequence( + { + {"Rectangle", uno::Any(xRectangle)}, + {"DimensionIndex", uno::Any(sal_Int32(nDimensionIndex))}, + {"PivotTableName", uno::Any(sPivotTableName)}, + }); + + pPopupRequest->getCallback()->notify(uno::Any(aCallbackData)); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartDropTargetHelper.cxx b/chart2/source/controller/main/ChartDropTargetHelper.cxx new file mode 100644 index 000000000..b1dfc35d4 --- /dev/null +++ b/chart2/source/controller/main/ChartDropTargetHelper.cxx @@ -0,0 +1,177 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartDropTargetHelper.hxx" +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +std::vector< OUString > lcl_getStringsFromByteSequence( + const Sequence< sal_Int8 > & aByteSequence ) +{ + std::vector< OUString > aResult; + const sal_Int32 nLength = aByteSequence.getLength(); + const char * pBytes( reinterpret_cast< const char* >( aByteSequence.getConstArray())); + sal_Int32 nStartPos = 0; + for( sal_Int32 nPos=0; nPos& rxDropTarget, + const rtl::Reference<::chart::ChartModel> & xChartDocument ) : + DropTargetHelper( rxDropTarget ), + m_xChartDocument( xChartDocument ) +{} + +ChartDropTargetHelper::~ChartDropTargetHelper() +{} + +bool ChartDropTargetHelper::satisfiesPrerequisites() const +{ + return ( m_xChartDocument.is() && + ! m_xChartDocument->hasInternalDataProvider()); +} + +sal_Int8 ChartDropTargetHelper::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + if( ( rEvt.mnAction == DND_ACTION_COPY || + rEvt.mnAction == DND_ACTION_MOVE ) && + satisfiesPrerequisites() && + IsDropFormatSupported( SotClipboardFormatId::LINK ) ) + { + // @todo: check if the data is suitable. Is this possible without XTransferable? + nResult = rEvt.mnAction; + } + + return nResult; +} + +sal_Int8 ChartDropTargetHelper::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + if( ( rEvt.mnAction == DND_ACTION_COPY || + rEvt.mnAction == DND_ACTION_MOVE ) && + rEvt.maDropEvent.Transferable.is() && + satisfiesPrerequisites()) + { + TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable ); + if( aDataHelper.HasFormat( SotClipboardFormatId::LINK )) + { + Sequence aBytes = aDataHelper.GetSequence(SotClipboardFormatId::LINK, OUString()); + if (aBytes.hasElements()) + { + std::vector< OUString > aStrings( lcl_getStringsFromByteSequence( aBytes )); + if( aStrings.size() >= 3 && aStrings[0] == "soffice" ) + { + OUString aRangeString( aStrings[2] ); + if( m_xChartDocument.is()) + { + Reference< frame::XModel > xParentModel( m_xChartDocument->getParent(), uno::UNO_QUERY ); + if( xParentModel.is() && + m_xChartDocument.is()) + { + // @todo: get the title somehow and compare it to + // aDocName if successful (the document is the + // parent) + rtl::Reference< Diagram > xDiagram = m_xChartDocument->getFirstChartDiagram(); + Reference< chart2::data::XDataProvider > xDataProvider( m_xChartDocument->getDataProvider()); + if( xDataProvider.is() && xDiagram.is() && + DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument )) + { + rtl::Reference< DataSource > xDataSource1 = + DataSourceHelper::pressUsedDataIntoRectangularFormat( m_xChartDocument ); + Sequence< beans::PropertyValue > aArguments( + xDataProvider->detectArguments( xDataSource1 )); + + OUString aOldRange; + beans::PropertyValue * pCellRange = nullptr; + for( sal_Int32 i=0; i>= aOldRange; + break; + } + } + if( pCellRange ) + { + // copy means add ranges, move means replace + if( rEvt.mnAction == DND_ACTION_COPY ) + { + // @todo: using implicit knowledge that ranges can be + // merged with ";". This should be done more general + pCellRange->Value <<= aOldRange + ";" + aRangeString; + } + // move means replace range + else + { + pCellRange->Value <<= aRangeString; + } + + Reference< chart2::data::XDataSource > xDataSource2 = + xDataProvider->createDataSource( aArguments ); + xDiagram->setDiagramData( xDataSource2, aArguments ); + + // always return copy state to avoid deletion of the dragged range + nResult = DND_ACTION_COPY; + } + } + } + } + } + } + } + } + return nResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartDropTargetHelper.hxx b/chart2/source/controller/main/ChartDropTargetHelper.hxx new file mode 100644 index 000000000..4955d6eae --- /dev/null +++ b/chart2/source/controller/main/ChartDropTargetHelper.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + } +} + +namespace chart +{ +class ChartModel; + +class ChartDropTargetHelper : public DropTargetHelper +{ +public: + ChartDropTargetHelper() = delete; + explicit ChartDropTargetHelper( + const css::uno::Reference< css::datatransfer::dnd::XDropTarget >& rxDropTarget, + const rtl::Reference<::chart::ChartModel> & xChartDocument ); + virtual ~ChartDropTargetHelper() override; + +protected: + + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override; + +private: + bool satisfiesPrerequisites() const; + + rtl::Reference<::chart::ChartModel> m_xChartDocument; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartFrameloader.cxx b/chart2/source/controller/main/ChartFrameloader.cxx new file mode 100644 index 000000000..0ba17d338 --- /dev/null +++ b/chart2/source/controller/main/ChartFrameloader.cxx @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartFrameloader.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; + +ChartFrameLoader::ChartFrameLoader( + uno::Reference const & xContext) + : m_bCancelRequired( false ) +{ + m_xCC = xContext; + m_oCancelFinished.reset(); +} + +ChartFrameLoader::~ChartFrameLoader() +{ +} + +bool ChartFrameLoader::impl_checkCancel() +{ + if(m_bCancelRequired) + { + m_oCancelFinished.set(); + return true; + } + return false; +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartFrameLoader::getImplementationName() +{ + return CHART_FRAMELOADER_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartFrameLoader::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartFrameLoader::getSupportedServiceNames() +{ + return { CHART_FRAMELOADER_SERVICE_NAME }; +} + +// frame::XFrameLoader + +sal_Bool SAL_CALL ChartFrameLoader::load( const uno::Sequence< beans::PropertyValue >& rMediaDescriptor, const uno::Reference& xFrame ) +{ + //@todo ? need to add as terminate listener to desktop? + + uno::Reference< frame::XModel > xModel; + bool bHaveLoadedModel = false; + + utl::MediaDescriptor aMediaDescriptor(rMediaDescriptor); + { + utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_MODEL)); + if( aIt != aMediaDescriptor.end()) + { + xModel.set( (*aIt).second.get< uno::Reference< frame::XModel > >()); + bHaveLoadedModel = true; + } + } + + //create and initialize the model + if( ! xModel.is()) + { + //@todo?? load mechanism to cancel during loading of document + xModel = new ChartModel(m_xCC); + + if( impl_checkCancel() ) + return false; + } + + //create the controller(+XWindow) + rtl::Reference< ChartController > xController = new ChartController(m_xCC); + + //!!!it is a special characteristic of the example application + //that the controller simultaneously provides the XWindow controller functionality + uno::Reference< awt::XWindow > xComponentWindow = xController; + + if( impl_checkCancel() ) + return false; + + //connect frame, controller and model one to each other: + if(xModel.is()) + { + xModel->connectController(xController); + xModel->setCurrentController(xController); + xController->attachModel(xModel); + if(xFrame.is()) + xFrame->setComponent(xComponentWindow,xController); + //creates the view and menu + //for correct menu creation the initialized component must be already set into the frame + xController->attachFrame(xFrame); + } + + // call initNew() or load() at XLoadable + if(bHaveLoadedModel) + return true; + + try + { + utl::MediaDescriptor::const_iterator aIt( aMediaDescriptor.find( utl::MediaDescriptor::PROP_URL)); + if( aIt != aMediaDescriptor.end()) + { + OUString aURL( (*aIt).second.get< OUString >()); + if( aURL.startsWith( "private:factory/schart" ) ) + { + // create new file + uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW ); + xLoadable->initNew(); + } + else + { + // use the URL as BaseURL, similar to what SfxBaseModel effectively does + if (!aURL.isEmpty()) + { + aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL] <<= aURL; + } + aMediaDescriptor.addInputStream(); + uno::Sequence< beans::PropertyValue > aCompleteMediaDescriptor; + aMediaDescriptor >> aCompleteMediaDescriptor; + apphelper::MediaDescriptorHelper aMDHelper( aCompleteMediaDescriptor ); + + // load file + // @todo: replace: aMediaDescriptorHelper.getReducedForModel() + uno::Reference< frame::XLoadable > xLoadable( xModel, uno::UNO_QUERY_THROW ); + xLoadable->load( aCompleteMediaDescriptor ); + + //resize standalone files to get correct size: + if( aMDHelper.ISSET_FilterName && aMDHelper.FilterName == "StarChart 5.0" ) + { + awt::Rectangle aRect( xComponentWindow->getPosSize() ); + xComponentWindow->setPosSize( aRect.X, aRect.Y, aRect.Width, aRect.Height, 0 ); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return true; +} + +void SAL_CALL ChartFrameLoader::cancel() +{ + m_oCancelFinished.reset(); + m_bCancelRequired = true; + m_oCancelFinished.wait(); + m_bCancelRequired = false; +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartFrameLoader_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::ChartFrameLoader(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartFrameloader.hxx b/chart2/source/controller/main/ChartFrameloader.hxx new file mode 100644 index 000000000..99f0ffd06 --- /dev/null +++ b/chart2/source/controller/main/ChartFrameloader.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +class ChartFrameLoader : public ::cppu::WeakImplHelper< + css::frame::XSynchronousFrameLoader + , css::lang::XServiceInfo + > +{ +private: + css::uno::Reference< css::uno::XComponentContext> m_xCC; + bool m_bCancelRequired; + ::osl::Condition m_oCancelFinished; + +private: + bool impl_checkCancel(); + +public: + ChartFrameLoader() = delete; + + explicit ChartFrameLoader(css::uno::Reference< css::uno::XComponentContext > const & xContext); + virtual ~ChartFrameLoader() override; + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // css::frame::XFrameLoader + + virtual sal_Bool SAL_CALL + load( const css::uno::Sequence< css::beans::PropertyValue >& rMediaDescriptor + ,const css::uno::Reference< css::frame::XFrame >& xFrame ) override; + + virtual void SAL_CALL + cancel() override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartModelClone.cxx b/chart2/source/controller/main/ChartModelClone.cxx new file mode 100644 index 000000000..d84945274 --- /dev/null +++ b/chart2/source/controller/main/ChartModelClone.cxx @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartModelClone.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chart +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::util::XCloneable; + using ::com::sun::star::chart2::XChartDocument; + using ::com::sun::star::chart2::XInternalDataProvider; + using ::com::sun::star::chart2::XAnyDescriptionAccess; + using ::com::sun::star::view::XSelectionSupplier; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::chart2::XTitled; + using ::com::sun::star::util::XModifiable; + using ::com::sun::star::chart2::data::XDataSource; + using ::com::sun::star::chart2::data::XLabeledDataSequence; + + // = helper + namespace + { + rtl::Reference<::chart::ChartModel> lcl_cloneModel( const rtl::Reference<::chart::ChartModel> & xModel ) + { + try + { + return new ChartModel(*xModel); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; + } + + } + + // = ChartModelClone + ChartModelClone::ChartModelClone( const rtl::Reference<::chart::ChartModel>& i_model, const ModelFacet i_facet ) + { + m_xModelClone = lcl_cloneModel( i_model ); + + try + { + if ( i_facet == E_MODEL_WITH_DATA ) + { + ENSURE_OR_THROW( m_xModelClone && m_xModelClone->hasInternalDataProvider(), "invalid chart model" ); + + const Reference< XCloneable > xCloneable( m_xModelClone->getDataProvider(), UNO_QUERY_THROW ); + m_xDataClone.set( xCloneable->createClone(), UNO_QUERY_THROW ); + } + + if ( i_facet == E_MODEL_WITH_SELECTION ) + { + const Reference< XSelectionSupplier > xSelSupp( m_xModelClone->getCurrentController(), UNO_QUERY_THROW ); + m_aSelection = xSelSupp->getSelection(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + ChartModelClone::~ChartModelClone() + { + if ( !impl_isDisposed() ) + dispose(); + } + + void ChartModelClone::dispose() + { + if ( impl_isDisposed() ) + return; + + m_xModelClone.clear(); + m_xDataClone.clear(); + m_aSelection.clear(); + } + + ModelFacet ChartModelClone::getFacet() const + { + if ( m_aSelection.hasValue() ) + return E_MODEL_WITH_SELECTION; + if ( m_xDataClone.is() ) + return E_MODEL_WITH_DATA; + return E_MODEL; + } + + void ChartModelClone::applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const + { + applyModelContentToModel( i_model, m_xModelClone, m_xDataClone ); + + if ( m_aSelection.hasValue() ) + { + try + { + Reference< XSelectionSupplier > xCurrentSelectionSuppl( i_model->getCurrentController(), UNO_QUERY_THROW ); + xCurrentSelectionSuppl->select( m_aSelection ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + + namespace + { + void ImplApplyDataToModel( const Reference< XModel >& i_model, const Reference< XInternalDataProvider > & i_data ) + { + Reference< XChartDocument > xDoc( i_model, UNO_QUERY ); + OSL_ASSERT( xDoc.is() && xDoc->hasInternalDataProvider() ); + + // copy data from stored internal data provider + if( xDoc.is() && xDoc->hasInternalDataProvider()) + { + Reference< XAnyDescriptionAccess > xCurrentData( xDoc->getDataProvider(), UNO_QUERY ); + Reference< XAnyDescriptionAccess > xSavedData( i_data, UNO_QUERY ); + if ( xCurrentData.is() && xSavedData.is() ) + { + xCurrentData->setData( xSavedData->getData() ); + xCurrentData->setAnyRowDescriptions( xSavedData->getAnyRowDescriptions()); + xCurrentData->setAnyColumnDescriptions( xSavedData->getAnyColumnDescriptions()); + } + } + } + } + + void ChartModelClone::applyModelContentToModel( const rtl::Reference<::chart::ChartModel>& i_model, + const rtl::Reference<::chart::ChartModel>& i_modelToCopyFrom, + const Reference< XInternalDataProvider >& i_data ) + { + ENSURE_OR_RETURN_VOID( i_model.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" ); + ENSURE_OR_RETURN_VOID( i_modelToCopyFrom.is(), "ChartModelElement::applyModelContentToModel: invalid source model!" ); + try + { + // locked controllers of destination + ControllerLockGuardUNO aLockedControllers( i_model ); + + // propagate the correct flag for plotting of hidden values to the data provider and all used sequences + ChartModelHelper::setIncludeHiddenCells(ChartModelHelper::isIncludeHiddenCells( i_modelToCopyFrom ), *i_model); + + // diagram + i_model->setFirstDiagram( i_modelToCopyFrom->getFirstDiagram() ); + + // main title + i_model->setTitleObject( i_modelToCopyFrom->getTitleObject() ); + + // page background + ::comphelper::copyProperties( + i_modelToCopyFrom->getPageBackground(), + i_model->getPageBackground() ); + + // apply data (not applied in standard Undo) + if ( i_data.is() ) + ImplApplyDataToModel( i_model, i_data ); + + // register all sequences at the internal data provider to get adapted + // indexes when columns are added/removed + if ( i_model->hasInternalDataProvider() ) + { + Reference< XInternalDataProvider > xNewDataProvider( i_model->getDataProvider(), UNO_QUERY ); + rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( *i_model ); + if ( xUsedData.is() && xNewDataProvider.is() ) + { + const Sequence< Reference< XLabeledDataSequence > > aData( xUsedData->getDataSequences() ); + for( Reference< XLabeledDataSequence > const & labeledDataSeq : aData ) + { + xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getValues() ); + xNewDataProvider->registerDataSequenceForChanges( labeledDataSeq->getLabel() ); + } + } + } + + // restore modify status + if ( !i_modelToCopyFrom->isModified() ) + { + i_model->setModified( false ); + } + // \-- locked controllers of destination + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartModelClone.hxx b/chart2/source/controller/main/ChartModelClone.hxx new file mode 100644 index 000000000..41cf7fc10 --- /dev/null +++ b/chart2/source/controller/main/ChartModelClone.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace com::sun::star::chart2 { class XInternalDataProvider; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + + enum ModelFacet + { + E_MODEL, + E_MODEL_WITH_DATA, + E_MODEL_WITH_SELECTION + }; + + class ChartModelClone + { + public: + ChartModelClone( + const rtl::Reference<::chart::ChartModel>& i_model, + const ModelFacet i_facet + ); + + ~ChartModelClone(); + + ChartModelClone(const ChartModelClone&) = delete; + const ChartModelClone& operator=(const ChartModelClone&) = delete; + + ModelFacet getFacet() const; + + void applyToModel( const rtl::Reference<::chart::ChartModel>& i_model ) const; + + static void applyModelContentToModel( + const rtl::Reference<::chart::ChartModel> & i_model, + const rtl::Reference<::chart::ChartModel> & i_modelToCopyFrom, + const css::uno::Reference< css::chart2::XInternalDataProvider > & i_data ); + + void dispose(); + + private: + bool impl_isDisposed() const { return !m_xModelClone.is(); } + + private: + rtl::Reference<::chart::ChartModel> m_xModelClone; + css::uno::Reference< css::chart2::XInternalDataProvider > m_xDataClone; + css::uno::Any m_aSelection; + }; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartTransferable.cxx b/chart2/source/controller/main/ChartTransferable.cxx new file mode 100644 index 000000000..322e73be3 --- /dev/null +++ b/chart2/source/controller/main/ChartTransferable.cxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "ChartTransferable.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr sal_uInt32 CHARTTRANSFER_OBJECTTYPE_DRAWMODEL = 1; + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +ChartTransferable::ChartTransferable( + SdrModel& rSdrModel, + SdrObject* pSelectedObj, + bool bDrawing) +: m_pMarkedObjModel( nullptr ) + ,m_bDrawing( bDrawing ) +{ + std::unique_ptr pExchgView(std::make_unique( rSdrModel )); + SdrPageView* pPv = pExchgView->ShowSdrPage( rSdrModel.GetPage( 0 )); + if( pSelectedObj ) + pExchgView->MarkObj( pSelectedObj, pPv ); + else + pExchgView->MarkAllObj( pPv ); + Graphic aGraphic( pExchgView->GetMarkedObjMetaFile(true)); + m_xMetaFileGraphic.set( aGraphic.GetXGraphic()); + if ( m_bDrawing ) + { + m_pMarkedObjModel = pExchgView->CreateMarkedObjModel().release(); + } +} + +ChartTransferable::~ChartTransferable() +{} + +void ChartTransferable::AddSupportedFormats() +{ + if ( m_bDrawing ) + { + AddFormat( SotClipboardFormatId::DRAWING ); + } + AddFormat( SotClipboardFormatId::GDIMETAFILE ); + AddFormat( SotClipboardFormatId::PNG ); + AddFormat( SotClipboardFormatId::BITMAP ); +} + +bool ChartTransferable::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) +{ + SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor ); + bool bResult = false; + + if( HasFormat( nFormat )) + { + if ( nFormat == SotClipboardFormatId::DRAWING ) + { + bResult = SetObject( m_pMarkedObjModel, CHARTTRANSFER_OBJECTTYPE_DRAWMODEL, rFlavor ); + } + else if ( nFormat == SotClipboardFormatId::GDIMETAFILE ) + { + Graphic aGraphic( m_xMetaFileGraphic ); + bResult = SetGDIMetaFile( aGraphic.GetGDIMetaFile() ); + } + else if( nFormat == SotClipboardFormatId::BITMAP ) + { + Graphic aGraphic( m_xMetaFileGraphic ); + bResult = SetBitmapEx( aGraphic.GetBitmapEx(), rFlavor ); + } + } + + return bResult; +} + +bool ChartTransferable::WriteObject( tools::SvRef& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, + const datatransfer::DataFlavor& /* rFlavor */ ) +{ + // called from SetObject, put data into stream + + bool bRet = false; + switch ( nUserObjectId ) + { + case CHARTTRANSFER_OBJECTTYPE_DRAWMODEL: + { + SdrModel* pMarkedObjModel = static_cast< SdrModel* >( pUserObject ); + if ( pMarkedObjModel ) + { + rxOStm->SetBufferSize( 0xff00 ); + + // for the changed pool defaults from drawing layer pool set those + // attributes as hard attributes to preserve them for saving + const SfxItemPool& rItemPool = pMarkedObjModel->GetItemPool(); + const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem( EE_CHAR_FONTHEIGHT ); + sal_uInt16 nCount = pMarkedObjModel->GetPageCount(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + const SdrPage* pPage = pMarkedObjModel->GetPage( i ); + SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups ); + while ( aIter.IsMore() ) + { + SdrObject* pObj = aIter.Next(); + const SvxFontHeightItem& rItem = pObj->GetMergedItem( EE_CHAR_FONTHEIGHT ); + if ( rItem.GetHeight() == rDefaultFontHeight.GetHeight() ) + { + pObj->SetMergedItem( rDefaultFontHeight ); + } + } + } + + Reference< io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) ); + SvxDrawingLayerExport( pMarkedObjModel, xDocOut ); + + bRet = ( rxOStm->GetError() == ERRCODE_NONE ); + } + } + break; + default: + { + OSL_FAIL( "ChartTransferable::WriteObject: unknown object id" ); + } + break; + } + return bRet; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartTransferable.hxx b/chart2/source/controller/main/ChartTransferable.hxx new file mode 100644 index 000000000..34567dceb --- /dev/null +++ b/chart2/source/controller/main/ChartTransferable.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace com::sun::star { + namespace graphic { + class XGraphic; + } +} + +class SdrModel; +class SdrObject; + +namespace chart +{ + +class ChartTransferable : public TransferableHelper +{ +public: + explicit ChartTransferable( + SdrModel& rSdrModel, + SdrObject* pSelectedObj, + bool bDrawing ); + virtual ~ChartTransferable() override; + +protected: + + // implementation of TransferableHelper methods + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + virtual bool WriteObject( tools::SvRef& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, + const css::datatransfer::DataFlavor& rFlavor ) override; + +private: + css::uno::Reference< css::graphic::XGraphic > m_xMetaFileGraphic; + SdrModel* m_pMarkedObjModel; + bool m_bDrawing; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ChartWindow.cxx b/chart2/source/controller/main/ChartWindow.cxx new file mode 100644 index 000000000..3085f65da --- /dev/null +++ b/chart2/source/controller/main/ChartWindow.cxx @@ -0,0 +1,403 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +::tools::Rectangle lcl_AWTRectToVCLRect( const css::awt::Rectangle & rAWTRect ) +{ + ::tools::Rectangle aResult(rAWTRect.X, rAWTRect.Y); + aResult.setWidth( rAWTRect.Width ); + aResult.setHeight( rAWTRect.Height ); + return aResult; +} +} // anonymous namespace + +namespace chart +{ + +ChartWindow::ChartWindow( ChartController* pController, vcl::Window* pParent, WinBits nStyle ) + : Window(pParent, nStyle) + , m_pWindowController( pController ) + , m_bInPaint(false) + , m_pViewShellWindow( nullptr ) +{ + set_id("chart_window"); + SetHelpId( HID_SCH_WIN_DOCUMENT ); + SetMapMode( MapMode(MapUnit::Map100thMM) ); + adjustHighContrastMode(); + // chart does not depend on exact pixel painting => enable antialiased drawing + GetOutDev()->SetAntialiasing( AntialiasingFlags::Enable | GetOutDev()->GetAntialiasing() ); + EnableRTL( false ); + if( pParent ) + pParent->EnableRTL( false );// #i96215# necessary for a correct position of the context menu in rtl mode +} + +ChartWindow::~ChartWindow() +{ + disposeOnce(); +} + +void ChartWindow::dispose() +{ + m_pWindowController = nullptr; + m_pViewShellWindow.clear(); + vcl::Window::dispose(); +} + +void ChartWindow::PrePaint(vcl::RenderContext& ) +{ + // forward VCLs PrePaint window event to DrawingLayer + if (m_pWindowController) + { + m_pWindowController->PrePaint(); + } +} + +void ChartWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + if (comphelper::LibreOfficeKit::isActive() && !rRenderContext.IsVirtual()) + return; + + m_bInPaint = true; + if (m_pWindowController) + { + m_pWindowController->execute_Paint(rRenderContext, rRect); + } + else + { + Window::Paint(rRenderContext, rRect); + } + m_bInPaint = false; +} + +void ChartWindow::MouseButtonDown(const MouseEvent& rMEvt) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseButtonDown(rMEvt); + else + Window::MouseButtonDown(rMEvt); +} + +void ChartWindow::MouseMove( const MouseEvent& rMEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseMove( rMEvt ); + else + Window::MouseMove( rMEvt ); +} + +void ChartWindow::Tracking( const TrackingEvent& rTEvt ) +{ + if( !m_pWindowController ) + Window::Tracking( rTEvt ); +} + +void ChartWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_MouseButtonUp( rMEvt ); + else + Window::MouseButtonUp( rMEvt ); +} + +void ChartWindow::Resize() +{ + if( m_pWindowController ) + m_pWindowController->execute_Resize(); + else + Window::Resize(); +} + +void ChartWindow::Activate() +{ + if( !m_pWindowController ) + Window::Activate(); +} +void ChartWindow::Deactivate() +{ + if( !m_pWindowController ) + Window::Deactivate(); +} +void ChartWindow::GetFocus() +{ + if( !m_pWindowController ) + Window::GetFocus(); +} +void ChartWindow::LoseFocus() +{ + if( !m_pWindowController ) + Window::LoseFocus(); +} + +void ChartWindow::Command( const CommandEvent& rCEvt ) +{ + if( m_pWindowController ) + m_pWindowController->execute_Command( rCEvt ); + else + Window::Command( rCEvt ); +} + +void ChartWindow::KeyInput( const KeyEvent& rKEvt ) +{ + if( m_pWindowController ) + { + if( !m_pWindowController->execute_KeyInput(rKEvt) ) + Window::KeyInput(rKEvt); + } + else + Window::KeyInput( rKEvt ); +} + +uno::Reference< css::accessibility::XAccessible > ChartWindow::CreateAccessible() +{ +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if( m_pWindowController ) + return m_pWindowController->CreateAccessible(); + else + return Window::CreateAccessible(); +#else + return uno::Reference< css::accessibility::XAccessible >(); +#endif +} + +void ChartWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + vcl::Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + adjustHighContrastMode(); + } +} + +void ChartWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + bool bHelpHandled = false; + if( ( rHEvt.GetMode() & HelpEventMode::QUICK ) && + m_pWindowController ) + { + Point aLogicHitPos = PixelToLogic( GetPointerPosPixel()); + OUString aQuickHelpText; + awt::Rectangle aHelpRect; + bool bIsBalloonHelp( Help::IsBalloonHelpEnabled() ); + bHelpHandled = m_pWindowController->requestQuickHelp( aLogicHitPos, bIsBalloonHelp, aQuickHelpText, aHelpRect ); + + if( bHelpHandled ) + { + tools::Rectangle aPixelRect(LogicToPixel(lcl_AWTRectToVCLRect(aHelpRect))); + tools::Rectangle aScreenRect(OutputToScreenPixel(aPixelRect.TopLeft()), + OutputToScreenPixel(aPixelRect.BottomRight())); + + if( bIsBalloonHelp ) + Help::ShowBalloon(this, rHEvt.GetMousePosPixel(), aScreenRect, aQuickHelpText); + else + Help::ShowQuickHelp(this, aScreenRect, aQuickHelpText); + } + } + + if( !bHelpHandled ) + vcl::Window::RequestHelp( rHEvt ); +} + +void ChartWindow::LogicMouseButtonDown(const MouseEvent& rEvent) +{ + MouseButtonDown(rEvent); +} + +void ChartWindow::LogicMouseButtonUp(const MouseEvent& rEvent) +{ + MouseButtonUp(rEvent); +} + +void ChartWindow::LogicMouseMove(const MouseEvent& rEvent) +{ + MouseMove(rEvent); +} + +void ChartWindow::adjustHighContrastMode() +{ + static const DrawModeFlags nContrastMode = + DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill | + DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient; + + bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode(); + GetOutDev()->SetDrawMode( bUseContrast ? nContrastMode : DrawModeFlags::Default ); +} + +void ChartWindow::ForceInvalidate() +{ + vcl::Window::Invalidate(); +} +void ChartWindow::Invalidate( InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( nFlags ); +} +void ChartWindow::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( rRect, nFlags ); +} +void ChartWindow::Invalidate( const vcl::Region& rRegion, InvalidateFlags nFlags ) +{ + if( m_bInPaint ) // #i101928# superfluous paint calls while entering and editing charts" + return; + vcl::Window::Invalidate( rRegion, nFlags ); +} + +void ChartWindow::LogicInvalidate(const tools::Rectangle* pRectangle) +{ + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + if ( nullptr == pCurrentShell ) + return; + tools::Rectangle aResultRectangle; + if (!pRectangle) + { + // we have to invalidate the whole chart area not the whole document + aResultRectangle = GetBoundingBox(); + } + else + { + tools::Rectangle aRectangle(*pRectangle); + // When dragging shapes the map mode is disabled. + if (IsMapModeEnabled()) + { + if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + { + aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip); + } + } + else + { + aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip)); + } + + vcl::Window* pEditWin = GetParentEditWin(); + if (pEditWin) + { + MapMode aCWMapMode = GetMapMode(); + constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip); + const auto& scaleX = aCWMapMode.GetScaleX(); + const auto& scaleY = aCWMapMode.GetScaleY(); + const auto nXNum = p.first * scaleX.GetDenominator(); + const auto nXDen = p.second * scaleX.GetNumerator(); + const auto nYNum = p.first * scaleY.GetDenominator(); + const auto nYDen = p.second * scaleY.GetNumerator(); + + if (!IsMapModeEnabled()) + { + aRectangle = aRectangle.scale(scaleX.GetDenominator(), scaleX.GetNumerator(), + scaleY.GetDenominator(), scaleY.GetNumerator()); + } + + Point aOffset = this->GetOffsetPixelFrom(*pEditWin).scale(nXNum, nXDen, nYNum, nYDen); + + aRectangle = tools::Rectangle(aRectangle.TopLeft() + aOffset, aRectangle.GetSize()); + } + + aResultRectangle = aRectangle; + } + SfxLokHelper::notifyInvalidation(pCurrentShell, &aResultRectangle); +} + +FactoryFunction ChartWindow::GetUITestFactory() const +{ + return ChartWindowUIObject::create; +} + +ChartController* ChartWindow::GetController() +{ + return m_pWindowController; +} + +vcl::Window* ChartWindow::GetParentEditWin() +{ + if (m_pViewShellWindow) + return m_pViewShellWindow.get(); + + // So, you are thinking, why do not invoke pCurrentShell->GetWindow() ? + // Because in Impress the parent edit win is not view shell window. + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + if( pCurrentShell ) + { + SfxInPlaceClient* pIPClient = pCurrentShell->GetIPClient(); + if (pIPClient) + { + vcl::Window* pRootWin = pIPClient->GetEditWin(); + if(pRootWin && pRootWin->IsAncestorOf(*this)) + { + m_pViewShellWindow = pRootWin; + return m_pViewShellWindow.get(); + } + } + } + return nullptr; +} + +tools::Rectangle ChartWindow::GetBoundingBox() +{ + tools::Rectangle aBBox; + + vcl::Window* pRootWin = GetParentEditWin(); + if (pRootWin) + { + // In all cases, the following code fragment + // returns the chart bounding box in twips. + MapMode aCWMapMode = GetMapMode(); + constexpr auto p = o3tl::getConversionMulDiv(o3tl::Length::px, o3tl::Length::twip); + const auto& scaleX = aCWMapMode.GetScaleX(); + const auto& scaleY = aCWMapMode.GetScaleY(); + const auto nXNum = p.first * scaleX.GetDenominator(); + const auto nXDen = p.second * scaleX.GetNumerator(); + const auto nYNum = p.first * scaleY.GetDenominator(); + const auto nYDen = p.second * scaleY.GetNumerator(); + + Point aOffset = GetOffsetPixelFrom(*pRootWin); + aOffset.setX( o3tl::convert(aOffset.X(), nXNum, nXDen) ); + aOffset.setY( o3tl::convert(aOffset.Y(), nYNum, nYDen) ); + Size aSize = GetSizePixel(); + aSize.setWidth( o3tl::convert(aSize.Width(), nXNum, nXDen) ); + aSize.setHeight( o3tl::convert(aSize.Height(), nYNum, nYDen) ); + aBBox = tools::Rectangle(aOffset, aSize); + } + return aBBox; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatch.cxx b/chart2/source/controller/main/CommandDispatch.cxx new file mode 100644 index 000000000..9a16fbb73 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatch.cxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "CommandDispatch.hxx" +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +CommandDispatch::CommandDispatch( + const Reference< uno::XComponentContext > & xContext ) : + impl::CommandDispatch_Base( m_aMutex ), + m_xContext( xContext ) +{ +} + +CommandDispatch::~CommandDispatch() +{} + +void CommandDispatch::initialize() +{} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL CommandDispatch::disposing() +{ + Reference< uno::XInterface > xEventSource(static_cast< cppu::OWeakObject* >( this )); + for( auto& rElement : m_aListeners ) + { + if( rElement.second ) + { + rElement.second->disposeAndClear( xEventSource ); + rElement.second.reset(); + } + } + m_aListeners.clear(); +} + +// ____ XDispatch ____ +void SAL_CALL CommandDispatch::dispatch( const util::URL& /* URL */, const Sequence< beans::PropertyValue >& /* Arguments */ ) +{} + +void SAL_CALL CommandDispatch::addStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL ) +{ + tListenerMap::iterator aIt( m_aListeners.find( URL.Complete )); + if( aIt == m_aListeners.end()) + { + aIt = m_aListeners.insert( + m_aListeners.begin(), + tListenerMap::value_type( URL.Complete, new ::comphelper::OInterfaceContainerHelper3( m_aMutex ))); + } + OSL_ASSERT( aIt != m_aListeners.end()); + + aIt->second->addInterface( Control ); + fireStatusEvent( URL.Complete, Control ); +} + +void SAL_CALL CommandDispatch::removeStatusListener( const Reference< frame::XStatusListener >& Control, const util::URL& URL ) +{ + tListenerMap::iterator aIt( m_aListeners.find( URL.Complete )); + if( aIt != m_aListeners.end()) + (*aIt).second->removeInterface( Control ); +} + +// ____ XModifyListener ____ +void SAL_CALL CommandDispatch::modified( const lang::EventObject& /* aEvent */ ) +{ + fireAllStatusEvents( nullptr ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL CommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{} + +void CommandDispatch::fireAllStatusEvents( + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) +{ + fireStatusEvent( OUString(), xSingleListener ); +} + +void CommandDispatch::fireStatusEventForURL( + const OUString & rURL, + const uno::Any & rState, + bool bEnabled, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */) +{ + // prepare event to send + util::URL aURL; + aURL.Complete = rURL; + if( !m_xURLTransformer.is()) + { + m_xURLTransformer.set( util::URLTransformer::create(m_xContext) ); + } + m_xURLTransformer->parseStrict( aURL ); + + frame::FeatureStateEvent aEventToSend( + static_cast< cppu::OWeakObject* >( this ), // Source + aURL, // FeatureURL + OUString(), // FeatureDescriptor + bEnabled, // IsEnabled + false, // Requery + rState // State + ); + + // send event either to single listener or all registered ones + if( xSingleListener.is()) + xSingleListener->statusChanged( aEventToSend ); + else + { + tListenerMap::iterator aIt( m_aListeners.find( aURL.Complete )); + if( aIt != m_aListeners.end()) + { + if( aIt->second ) + { + ::comphelper::OInterfaceIteratorHelper3 aIntfIt( *((*aIt).second) ); + + while( aIntfIt.hasMoreElements()) + { + try + { + aIntfIt.next()->statusChanged( aEventToSend ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatch.hxx b/chart2/source/controller/main/CommandDispatch.hxx new file mode 100644 index 000000000..16e0b5ab7 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatch.hxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XURLTransformer; } + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::frame::XDispatch, + css::util::XModifyListener > + CommandDispatch_Base; +} + +/** This is the base class for an XDispatch. + */ +class CommandDispatch : + public cppu::BaseMutex, + public impl::CommandDispatch_Base +{ +public: + explicit CommandDispatch( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + virtual ~CommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize(); + +protected: + /** sends a status event for a specific command to all registered listeners + or only the one given when set. + + This method should be overridden. The implementation should call + fireStatusEventForURL and pass the xSingleListener argument to this + method unchanged. + + @param rURL + If empty, all available status events must be fired, otherwise only + the one for the given command. + + @param xSingleListener + If set, the event is only sent to this listener rather than to all + registered ones. Whenever a listener adds itself, this method is + called with this parameter set to give an initial state. + */ + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) = 0; + + /** calls fireStatusEvent( OUString, xSingleListener ) + */ + void fireAllStatusEvents( + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + /** sends a status event for a specific command to all registered listeners + or only the one given when set. + + @param xSingleListener + If set, the event is only sent to this listener rather than to all + registered ones. Whenever a listener adds itself, this method is + called with this parameter set to give an initial state. + */ + void fireStatusEventForURL( + const OUString & rURL, + const css::uno::Any & rState, + bool bEnabled, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + virtual void SAL_CALL addStatusListener( + const css::uno::Reference< css::frame::XStatusListener >& Control, + const css::util::URL& URL ) override; + virtual void SAL_CALL removeStatusListener( + const css::uno::Reference< css::frame::XStatusListener >& Control, + const css::util::URL& URL ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + +private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::util::XURLTransformer > m_xURLTransformer; + + typedef std::map< OUString, std::unique_ptr<::comphelper::OInterfaceContainerHelper3> > + tListenerMap; + + tListenerMap m_aListeners; + +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/CommandDispatchContainer.cxx b/chart2/source/controller/main/CommandDispatchContainer.cxx new file mode 100644 index 000000000..d42936ce7 --- /dev/null +++ b/chart2/source/controller/main/CommandDispatchContainer.cxx @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "UndoCommandDispatch.hxx" +#include "StatusBarCommandDispatch.hxx" +#include +#include "DrawCommandDispatch.hxx" +#include "ShapeController.hxx" +#include + +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +CommandDispatchContainer::CommandDispatchContainer( + const Reference< uno::XComponentContext > & xContext ) + :m_xContext( xContext ) + ,m_pDrawCommandDispatch( nullptr ) + ,m_pShapeController( nullptr ) +{ +} + +void CommandDispatchContainer::setModel( + const rtl::Reference<::chart::ChartModel> & xModel ) +{ + // remove all existing dispatcher that base on the old model + m_aCachedDispatches.clear(); + DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches ); + m_aToBeDisposedDispatches.clear(); + m_xModel = xModel.get(); +} + +void CommandDispatchContainer::setChartDispatch( + const Reference< frame::XDispatch >& rChartDispatch, + o3tl::sorted_vector< OUString > && rChartCommands ) +{ + OSL_ENSURE(rChartDispatch.is(),"Invalid fall back dispatcher!"); + m_xChartDispatcher.set( rChartDispatch ); + m_aChartCommands = std::move(rChartCommands); + m_aToBeDisposedDispatches.push_back( m_xChartDispatcher ); +} + +Reference< frame::XDispatch > CommandDispatchContainer::getDispatchForURL( + const util::URL & rURL ) +{ + static const o3tl::sorted_vector< OUString > s_aContainerDocumentCommands { + "AddDirect", "NewDoc", "Open", + "Save", "SaveAs", "SendMail", + "EditDoc", "ExportDirectToPDF", "PrintDefault"}; + + Reference< frame::XDispatch > xResult; + tDispatchMap::const_iterator aIt( m_aCachedDispatches.find( rURL.Complete )); + if( aIt != m_aCachedDispatches.end()) + { + xResult.set( (*aIt).second ); + } + else + { + rtl::Reference< ::chart::ChartModel > xModel( m_xModel ); + + if( xModel.is() && ( rURL.Path == "Undo" || rURL.Path == "Redo" || + rURL.Path == "GetUndoStrings" || rURL.Path == "GetRedoStrings" ) ) + { + rtl::Reference pDispatch = new UndoCommandDispatch( m_xContext, xModel ); + xResult.set( pDispatch ); + pDispatch->initialize(); + m_aCachedDispatches[ ".uno:Undo" ].set( xResult ); + m_aCachedDispatches[ ".uno:Redo" ].set( xResult ); + m_aCachedDispatches[ ".uno:GetUndoStrings" ].set( xResult ); + m_aCachedDispatches[ ".uno:GetRedoStrings" ].set( xResult ); + m_aToBeDisposedDispatches.push_back( xResult ); + } + else if( xModel.is() && ( rURL.Path == "Context" || rURL.Path == "ModifiedStatus" ) ) + { + Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), uno::UNO_QUERY ); + rtl::Reference pDispatch = new StatusBarCommandDispatch( m_xContext, xModel, xSelSupp ); + xResult.set( pDispatch ); + pDispatch->initialize(); + m_aCachedDispatches[ ".uno:Context" ].set( xResult ); + m_aCachedDispatches[ ".uno:ModifiedStatus" ].set( xResult ); + m_aToBeDisposedDispatches.push_back( xResult ); + } + else if( xModel.is() && + (s_aContainerDocumentCommands.find( rURL.Path ) != s_aContainerDocumentCommands.end()) ) + { + xResult.set( getContainerDispatchForURL( xModel->getCurrentController(), rURL )); + // ToDo: can those dispatches be cached? + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + else if( m_xChartDispatcher.is() && + (m_aChartCommands.find( rURL.Path ) != m_aChartCommands.end()) ) + { + xResult.set( m_xChartDispatcher ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + // #i12587# support for shapes in chart + // Note, that the chart dispatcher must be queried first, because + // the chart dispatcher is the default dispatcher for all context + // sensitive commands. + else if ( m_pDrawCommandDispatch && m_pDrawCommandDispatch->isFeatureSupported( rURL.Complete ) ) + { + xResult.set( m_pDrawCommandDispatch ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + else if ( m_pShapeController && m_pShapeController->isFeatureSupported( rURL.Complete ) ) + { + xResult.set( m_pShapeController ); + m_aCachedDispatches[ rURL.Complete ].set( xResult ); + } + } + + return xResult; +} + +Sequence< Reference< frame::XDispatch > > CommandDispatchContainer::getDispatchesForURLs( + const Sequence< frame::DispatchDescriptor > & aDescriptors ) +{ + sal_Int32 nCount = aDescriptors.getLength(); + uno::Sequence< uno::Reference< frame::XDispatch > > aRet( nCount ); + auto aRetRange = asNonConstRange(aRet); + + for( sal_Int32 nPos = 0; nPos < nCount; ++nPos ) + { + if ( aDescriptors[ nPos ].FrameName == "_self" ) + aRetRange[ nPos ] = getDispatchForURL( aDescriptors[ nPos ].FeatureURL ); + } + return aRet; +} + +void CommandDispatchContainer::DisposeAndClear() +{ + m_aCachedDispatches.clear(); + DisposeHelper::DisposeAllElements( m_aToBeDisposedDispatches ); + m_aToBeDisposedDispatches.clear(); + m_xChartDispatcher.clear(); + m_aChartCommands.clear(); + m_pDrawCommandDispatch = nullptr; + m_pShapeController = nullptr; +} + +Reference< frame::XDispatch > CommandDispatchContainer::getContainerDispatchForURL( + const Reference< frame::XController > & xChartController, + const util::URL & rURL ) +{ + Reference< frame::XDispatch > xResult; + if( xChartController.is()) + { + Reference< frame::XFrame > xFrame( xChartController->getFrame()); + if( xFrame.is()) + { + Reference< frame::XDispatchProvider > xDispProv( xFrame->getCreator(), uno::UNO_QUERY ); + if( xDispProv.is()) + xResult.set( xDispProv->queryDispatch( rURL, "_self", 0 )); + } + } + return xResult; +} + +void CommandDispatchContainer::setDrawCommandDispatch( DrawCommandDispatch* pDispatch ) +{ + m_pDrawCommandDispatch = pDispatch; + m_aToBeDisposedDispatches.emplace_back( pDispatch ); +} + +void CommandDispatchContainer::setShapeController( ShapeController* pController ) +{ + m_pShapeController = pController; + m_aToBeDisposedDispatches.emplace_back( pController ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ConfigurationAccess.cxx b/chart2/source/controller/main/ConfigurationAccess.cxx new file mode 100644 index 000000000..f6dfecc60 --- /dev/null +++ b/chart2/source/controller/main/ConfigurationAccess.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ +bool lcl_IsMetric() +{ + SvtSysLocale aSysLocale; + MeasurementSystem eSys = aSysLocale.GetLocaleData().getMeasurementSystemEnum(); + + return ( eSys == MeasurementSystem::Metric ); +} + +class CalcConfigItem : public ::utl::ConfigItem +{ +private: + virtual void ImplCommit() override; + +public: + CalcConfigItem(); + + FieldUnit getFieldUnit(); + virtual void Notify( const uno::Sequence& aPropertyNames) override; +}; + +}//end anonymous namespace + +CalcConfigItem::CalcConfigItem() + : ConfigItem( "Office.Calc/Layout" ) +{ +} + +void CalcConfigItem::ImplCommit() {} +void CalcConfigItem::Notify( const uno::Sequence& ) {} + +FieldUnit CalcConfigItem::getFieldUnit() +{ + FieldUnit eResult( FieldUnit::CM ); + + uno::Sequence< OUString > aNames; + if( lcl_IsMetric() ) + aNames = { "Other/MeasureUnit/Metric" }; + else + aNames = { "Other/MeasureUnit/NonMetric" }; + + uno::Sequence< uno::Any > aResult( GetProperties( aNames )); + sal_Int32 nValue = 0; + if( aResult[ 0 ] >>= nValue ) + eResult = static_cast< FieldUnit >( nValue ); + + return eResult; +} + +namespace ConfigurationAccess +{ + FieldUnit getFieldUnit() + { + //a CalcConfigItem Singleton + static CalcConfigItem SINGLETON; + FieldUnit aUnit( SINGLETON.getFieldUnit() ); + return aUnit; + } +} //namespace ConfigurationAccess + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ControllerCommandDispatch.cxx b/chart2/source/controller/main/ControllerCommandDispatch.cxx new file mode 100644 index 000000000..e5035b4f0 --- /dev/null +++ b/chart2/source/controller/main/ControllerCommandDispatch.cxx @@ -0,0 +1,826 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ControllerCommandDispatch.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ShapeController.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +// only needed until #i68864# is fixed +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +bool lcl_isStatusBarVisible( const Reference< frame::XController > & xController ) +{ + bool bIsStatusBarVisible = false; + // Status-Bar visible, workaround: this should not be necessary. @todo: + // remove when Issue #i68864# is fixed + if( xController.is()) + { + Reference< beans::XPropertySet > xPropSet( xController->getFrame(), uno::UNO_QUERY ); + if( xPropSet.is() ) + { + uno::Reference< css::frame::XLayoutManager > xLayoutManager; + xPropSet->getPropertyValue( "LayoutManager" ) >>= xLayoutManager; + if ( xLayoutManager.is() ) + bIsStatusBarVisible = xLayoutManager->isElementVisible( "private:resource/statusbar/statusbar" ); + } + } + return bIsStatusBarVisible; +} + +} // anonymous namespace + +namespace chart +{ + +namespace impl +{ + +/// Constants for moving the series. +namespace { + bool const MOVE_SERIES_FORWARD = true; + bool const MOVE_SERIES_BACKWARD = false; +} + +/** Represents the current state of the controller (needed for issue 63017). + + You can set the state by calling update(). After this call the state is + preserved in this class until the next call to update(). + + This is useful, not to say necessary, for enabling and disabling of menu + entries (e.g. format>arrangement). As the status requests are sent very + frequently it would be impossible, from a performance point of view, to + query the current status every time directly at the model. So this class + serves as a cache for the state. +*/ +struct ControllerState +{ + ControllerState(); + + void update( const Reference< frame::XController > & xController, + const rtl::Reference<::chart::ChartModel> & xModel ); + + // -- State variables ------- + bool bHasSelectedObject; + bool bIsPositionableObject; + bool bIsTextObject; + bool bIsDeleteableObjectSelected; + bool bIsFormateableObjectSelected; + + // May the selected series be moved forward or backward (cf + // format>arrangement). + bool bMayMoveSeriesForward; + bool bMayMoveSeriesBackward; + + // trendlines + bool bMayAddMenuTrendline; + bool bMayAddTrendline; + bool bMayAddTrendlineEquation; + bool bMayAddR2Value; + bool bMayAddMeanValue; + bool bMayAddXErrorBars; + bool bMayAddYErrorBars; + + bool bMayDeleteTrendline; + bool bMayDeleteTrendlineEquation; + bool bMayDeleteR2Value; + bool bMayDeleteMeanValue; + bool bMayDeleteXErrorBars; + bool bMayDeleteYErrorBars; + + bool bMayFormatTrendline; + bool bMayFormatTrendlineEquation; + bool bMayFormatMeanValue; + bool bMayFormatXErrorBars; + bool bMayFormatYErrorBars; +}; + +ControllerState::ControllerState() : + bHasSelectedObject( false ), + bIsPositionableObject( false ), + bIsTextObject(false), + bIsDeleteableObjectSelected(false), + bIsFormateableObjectSelected(false), + bMayMoveSeriesForward( false ), + bMayMoveSeriesBackward( false ), + bMayAddMenuTrendline( false ), + bMayAddTrendline( false ), + bMayAddTrendlineEquation( false ), + bMayAddR2Value( false ), + bMayAddMeanValue( false ), + bMayAddXErrorBars( false ), + bMayAddYErrorBars( false ), + bMayDeleteTrendline( false ), + bMayDeleteTrendlineEquation( false ), + bMayDeleteR2Value( false ), + bMayDeleteMeanValue( false ), + bMayDeleteXErrorBars( false ), + bMayDeleteYErrorBars( false ), + bMayFormatTrendline( false ), + bMayFormatTrendlineEquation( false ), + bMayFormatMeanValue( false ), + bMayFormatXErrorBars( false ), + bMayFormatYErrorBars( false ) +{} + +void ControllerState::update( + const Reference< frame::XController > & xController, + const rtl::Reference<::chart::ChartModel> & xModel ) +{ + Reference< view::XSelectionSupplier > xSelectionSupplier( + xController, uno::UNO_QUERY ); + + // Update ControllerState variables. + if( !xSelectionSupplier.is()) + return; + + uno::Any aSelObj( xSelectionSupplier->getSelection() ); + ObjectIdentifier aSelOID( aSelObj ); + OUString aSelObjCID( aSelOID.getObjectCID() ); + + bHasSelectedObject = aSelOID.isValid(); + + ObjectType aObjectType(ObjectIdentifier::getObjectType( aSelObjCID )); + + bIsPositionableObject = (aObjectType != OBJECTTYPE_DATA_POINT) && aSelOID.isDragableObject(); + bIsTextObject = aObjectType == OBJECTTYPE_TITLE; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + bIsFormateableObjectSelected = bHasSelectedObject && aSelOID.isAutoGeneratedObject(); + if( aObjectType==OBJECTTYPE_DIAGRAM || aObjectType==OBJECTTYPE_DIAGRAM_WALL || aObjectType==OBJECTTYPE_DIAGRAM_FLOOR ) + bIsFormateableObjectSelected = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + + rtl::Reference< DataSeries > xGivenDataSeries = + ObjectIdentifier::getDataSeriesForCID( + aSelObjCID, xModel ); + + bIsDeleteableObjectSelected = ChartController::isObjectDeleteable( aSelObj ); + + bMayMoveSeriesForward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable( + ChartModelHelper::findDiagram( xModel ), + xGivenDataSeries, + MOVE_SERIES_FORWARD ); + + bMayMoveSeriesBackward = (aObjectType!=OBJECTTYPE_DATA_POINT) && DiagramHelper::isSeriesMoveable( + ChartModelHelper::findDiagram( xModel ), + xGivenDataSeries, + MOVE_SERIES_BACKWARD ); + + bMayAddMenuTrendline = false; + bMayAddTrendline = false; + bMayAddTrendlineEquation = false; + bMayAddR2Value = false; + bMayAddMeanValue = false; + bMayAddXErrorBars = false; + bMayAddYErrorBars = false; + bMayDeleteTrendline = false; + bMayDeleteTrendlineEquation = false; + bMayDeleteR2Value = false; + bMayDeleteMeanValue = false; + bMayDeleteXErrorBars = false; + bMayDeleteYErrorBars = false; + bMayFormatTrendline = false; + bMayFormatTrendlineEquation = false; + bMayFormatMeanValue = false; + bMayFormatXErrorBars = false; + bMayFormatYErrorBars = false; + if( !bHasSelectedObject ) + return; + + if( xGivenDataSeries.is()) + { + bMayAddMenuTrendline = true; + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + rtl::Reference< ::chart::ChartType > xFirstChartType( + DataSeriesHelper::getChartTypeOfSeries( xGivenDataSeries, xDiagram )); + + // trend lines/mean value line + if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT) + && ChartTypeHelper::isSupportingRegressionProperties( xFirstChartType, nDimensionCount )) + { + // Trendline + bMayAddTrendline = true; + + // Mean Value + bMayFormatMeanValue = bMayDeleteMeanValue = RegressionCurveHelper::hasMeanValueLine( xGivenDataSeries ); + bMayAddMeanValue = ! bMayDeleteMeanValue; + } + + // error bars + if( (aObjectType == OBJECTTYPE_DATA_SERIES || aObjectType == OBJECTTYPE_DATA_POINT) + && ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount )) + { + bMayFormatXErrorBars = bMayDeleteXErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries, false ); + bMayAddXErrorBars = ! bMayDeleteXErrorBars; + + bMayFormatYErrorBars = bMayDeleteYErrorBars = StatisticsHelper::hasErrorBars( xGivenDataSeries ); + bMayAddYErrorBars = ! bMayDeleteYErrorBars; + } + } + + if( aObjectType == OBJECTTYPE_DATA_AVERAGE_LINE ) + bMayFormatMeanValue = true; + + if( aObjectType == OBJECTTYPE_DATA_ERRORS_X) + bMayFormatXErrorBars = true; + + if( aObjectType == OBJECTTYPE_DATA_ERRORS_Y ) + bMayFormatYErrorBars = true; + + if( aObjectType == OBJECTTYPE_DATA_CURVE ) + { + bMayFormatTrendline = true; + bMayDeleteTrendline = true; + uno::Reference< chart2::XRegressionCurve > xRegCurve( + ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel ), uno::UNO_QUERY ); + + // Trendline Equation + bMayFormatTrendlineEquation = bMayDeleteTrendlineEquation = RegressionCurveHelper::hasEquation( xRegCurve ); + bMayAddTrendlineEquation = !bMayDeleteTrendlineEquation; + } + else if( aObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) + { + bMayFormatTrendlineEquation = true; + bool bHasR2Value = false; + try + { + uno::Reference< beans::XPropertySet > xEquationProperties = + ObjectIdentifier::getObjectPropertySet( aSelObjCID, xModel ); + if( xEquationProperties.is() ) + xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient" ) >>= bHasR2Value; + } + catch(const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + bMayAddR2Value = !bHasR2Value; + bMayDeleteR2Value = bHasR2Value; + } +} + +/** Represents the current state of the model. + + You can set the state by calling update(). After this call the state is + preserved in this class until the next call to update(). + + This is useful, not to say necessary, for enabling and disabling of menu + entries and toolbar icons. As the status requests are sent very frequently + it would be impossible, from a performance point of view, to query the + current status every time directly at the model. So this class serves as a + cache for the state. + */ +struct ModelState +{ + ModelState(); + + void update( const rtl::Reference<::chart::ChartModel> & xModel ); + + bool HasAnyAxis() const; + bool HasAnyGrid() const; + bool HasAnyTitle() const; + + bool bIsReadOnly; + bool bIsThreeD; + bool bHasOwnData; + bool bHasDataFromPivotTable; + + bool bHasMainTitle; + bool bHasSubTitle; + bool bHasXAxisTitle; + bool bHasYAxisTitle; + bool bHasZAxisTitle; + bool bHasSecondaryXAxisTitle; + bool bHasSecondaryYAxisTitle; + + bool bHasXAxis; + bool bHasYAxis; + bool bHasZAxis; + bool bHasAAxis; + bool bHasBAxis; + + bool bHasMainXGrid; + bool bHasMainYGrid; + bool bHasMainZGrid; + bool bHasHelpXGrid; + bool bHasHelpYGrid; + bool bHasHelpZGrid; + + bool bHasAutoScaledText; + bool bHasLegend; + bool bHasWall; + bool bHasFloor; + + bool bSupportsStatistics; + bool bSupportsAxes; +}; + +ModelState::ModelState() : + bIsReadOnly(true), + bIsThreeD(false), + bHasOwnData(false), + bHasDataFromPivotTable(false), + bHasMainTitle(false), + bHasSubTitle(false), + bHasXAxisTitle(false), + bHasYAxisTitle(false), + bHasZAxisTitle(false), + bHasSecondaryXAxisTitle(false), + bHasSecondaryYAxisTitle(false), + bHasXAxis(false), + bHasYAxis(false), + bHasZAxis(false), + bHasAAxis(false), + bHasBAxis(false), + bHasMainXGrid(false), + bHasMainYGrid(false), + bHasMainZGrid(false), + bHasHelpXGrid(false), + bHasHelpYGrid(false), + bHasHelpZGrid(false), + bHasAutoScaledText(false), + bHasLegend(false), + bHasWall(false), + bHasFloor(false), + bSupportsStatistics(false), + bSupportsAxes(false) +{} + +void ModelState::update( const rtl::Reference<::chart::ChartModel> & xModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + + bIsReadOnly = xModel->isReadonly(); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + rtl::Reference< ChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + bSupportsStatistics = ChartTypeHelper::isSupportingStatisticProperties( xFirstChartType, nDimensionCount ); + bSupportsAxes = ChartTypeHelper::isSupportingMainAxis( xFirstChartType, nDimensionCount, 0 ); + + bIsThreeD = (nDimensionCount == 3); + if (xModel.is()) + { + bHasOwnData = xModel->hasInternalDataProvider(); + bHasDataFromPivotTable = !bHasOwnData && xModel->isDataFromPivotTable(); + } + + bHasMainTitle = TitleHelper::getTitle( TitleHelper::MAIN_TITLE, xModel ).is(); + bHasSubTitle = TitleHelper::getTitle( TitleHelper::SUB_TITLE, xModel ).is(); + bHasXAxisTitle = TitleHelper::getTitle( TitleHelper::X_AXIS_TITLE, xModel ).is(); + bHasYAxisTitle = TitleHelper::getTitle( TitleHelper::Y_AXIS_TITLE, xModel ).is(); + bHasZAxisTitle = TitleHelper::getTitle( TitleHelper::Z_AXIS_TITLE, xModel ).is(); + bHasSecondaryXAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, xModel ).is(); + bHasSecondaryYAxisTitle = TitleHelper::getTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, xModel ).is(); + + bHasXAxis = bSupportsAxes && AxisHelper::getAxis( 0, true, xDiagram ).is(); + bHasYAxis = bSupportsAxes && AxisHelper::getAxis( 1, true, xDiagram ).is(); + bHasZAxis = bSupportsAxes && AxisHelper::getAxis( 2, true, xDiagram ).is(); + bHasAAxis = bSupportsAxes && AxisHelper::getAxis( 0, false, xDiagram ).is(); + bHasBAxis = bSupportsAxes && AxisHelper::getAxis( 1, false, xDiagram ).is(); + + bHasMainXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, true, xDiagram ); + bHasMainYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, true, xDiagram ); + bHasMainZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, true, xDiagram ); + bHasHelpXGrid = bSupportsAxes && AxisHelper::isGridShown( 0, 0, false, xDiagram ); + bHasHelpYGrid = bSupportsAxes && AxisHelper::isGridShown( 1, 0, false, xDiagram ); + bHasHelpZGrid = bSupportsAxes && AxisHelper::isGridShown( 2, 0, false, xDiagram ); + + bHasAutoScaledText = + (ReferenceSizeProvider::getAutoResizeState( xModel ) == + ReferenceSizeProvider::AUTO_RESIZE_YES); + + bHasLegend = LegendHelper::hasLegend( xDiagram ); + bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + bHasFloor = bHasWall && bIsThreeD; +} + +bool ModelState::HasAnyAxis() const +{ + return bHasXAxis || bHasYAxis || bHasZAxis || bHasAAxis || bHasBAxis; +} + +bool ModelState::HasAnyGrid() const +{ + return bHasMainXGrid || bHasMainYGrid || bHasMainZGrid || + bHasHelpXGrid || bHasHelpYGrid || bHasHelpZGrid; +} + +bool ModelState::HasAnyTitle() const +{ + return bHasMainTitle || bHasSubTitle || bHasXAxisTitle || bHasYAxisTitle || bHasZAxisTitle || bHasSecondaryXAxisTitle || bHasSecondaryYAxisTitle; +} + +} // namespace impl + +ControllerCommandDispatch::ControllerCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + ChartController* pController, CommandDispatchContainer* pContainer ) : + impl::ControllerCommandDispatch_Base( xContext ), + m_xChartController( pController ), + m_xSelectionSupplier( Reference< view::XSelectionSupplier >( pController ) ), + m_xDispatch( Reference< frame::XDispatch >( pController ) ), + m_apModelState( new impl::ModelState() ), + m_apControllerState( new impl::ControllerState() ), + m_pDispatchContainer( pContainer ) +{ +} + +ControllerCommandDispatch::~ControllerCommandDispatch() +{ +} + +void ControllerCommandDispatch::initialize() +{ + if( !m_xChartController.is()) + return; + + rtl::Reference<::chart::ChartModel> xModel( m_xChartController->getChartModel()); + OSL_ASSERT( xModel.is()); + if( xModel.is()) + xModel->addModifyListener( this ); + + // Listen selection modifications (Arrangement feature - issue 63017). + if( m_xSelectionSupplier.is() ) + m_xSelectionSupplier->addSelectionChangeListener( this ); + + if( m_apModelState && xModel.is()) + m_apModelState->update( xModel ); + + if( m_apControllerState && xModel.is()) + m_apControllerState->update( m_xChartController, xModel ); + + updateCommandAvailability(); +} + +void ControllerCommandDispatch::fireStatusEventForURLImpl( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener ) +{ + std::map< OUString, uno::Any >::const_iterator aArgIt( m_aCommandArguments.find( rURL )); + if( aArgIt != m_aCommandArguments.end()) + fireStatusEventForURL( rURL, aArgIt->second, commandAvailable( rURL ), xSingleListener ); + else + fireStatusEventForURL( rURL, uno::Any(), commandAvailable( rURL ), xSingleListener ); +} + +void ControllerCommandDispatch::updateCommandAvailability() +{ + bool bModelStateIsValid = (m_apModelState != nullptr); + bool bControllerStateIsValid = (m_apControllerState != nullptr); + // Model and controller states exist. + OSL_ASSERT( bModelStateIsValid ); + OSL_ASSERT( bControllerStateIsValid ); + + // read-only + bool bIsWritable = bModelStateIsValid && (! m_apModelState->bIsReadOnly); + bool bShapeContext = m_xChartController.is() && m_xChartController->isShapeContext(); + + bool bEnableDataTableDialog = false; + bool bCanCreateDataProvider = false; + + if ( m_xChartController.is() ) + { + Reference< beans::XPropertySet > xProps( m_xChartController->getModel(), uno::UNO_QUERY ); + if ( xProps.is() ) + { + try + { + xProps->getPropertyValue("EnableDataTableDialog") >>= bEnableDataTableDialog; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + rtl::Reference< ChartModel > xChartModel = m_xChartController->getChartModel(); + OSL_ENSURE(xChartModel.is(), "Invalid XChartDocument"); + if ( xChartModel.is() ) + { + css::uno::Reference< com::sun::star::chart2::XDataProviderAccess > xCreatorDoc(xChartModel->getParent(), uno::UNO_QUERY); + bCanCreateDataProvider = xCreatorDoc.is(); + } + } + + // edit commands + m_aCommandAvailability[ ".uno:Cut" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsDeleteableObjectSelected; + m_aCommandAvailability[ ".uno:Copy" ] = bControllerStateIsValid && m_apControllerState->bHasSelectedObject; + m_aCommandAvailability[ ".uno:Paste" ] = bIsWritable; + + // toolbar commands + m_aCommandAvailability[ ".uno:ToggleGridHorizontal" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleGridHorizontal" ] <<= bModelStateIsValid && m_apModelState->bHasMainYGrid; + m_aCommandAvailability[ ".uno:ToggleGridVertical" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleGridVertical" ] <<= bModelStateIsValid && m_apModelState->bHasMainXGrid; + + m_aCommandAvailability[ ".uno:ToggleLegend" ] = bIsWritable; + m_aCommandArguments[ ".uno:ToggleLegend" ] <<= bModelStateIsValid && m_apModelState->bHasLegend; + + m_aCommandAvailability[ ".uno:NewArrangement" ] = bIsWritable; + m_aCommandAvailability[ ".uno:Update" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DefaultColors" ] = bIsWritable; + m_aCommandAvailability[ ".uno:BarWidth" ] = bIsWritable; + m_aCommandAvailability[ ".uno:NumberOfLines" ] = bIsWritable; + m_aCommandAvailability[ ".uno:ArrangeRow" ] = + bShapeContext || ( bIsWritable && bControllerStateIsValid && ( m_apControllerState->bMayMoveSeriesForward || m_apControllerState->bMayMoveSeriesBackward ) ); + + // insert objects + m_aCommandAvailability[ ".uno:InsertTitles" ] = m_aCommandAvailability[ ".uno:InsertMenuTitles" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertLegend" ] = m_aCommandAvailability[ ".uno:InsertMenuLegend" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteLegend" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMenuDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertRemoveAxes" ] = m_aCommandAvailability[ ".uno:InsertMenuAxes" ] = bIsWritable && m_apModelState->bSupportsAxes; + m_aCommandAvailability[ ".uno:InsertMenuGrids" ] = bIsWritable && m_apModelState->bSupportsAxes; + m_aCommandAvailability[ ".uno:InsertMenuTrendlines" ] = bIsWritable && m_apModelState->bSupportsStatistics && bControllerStateIsValid && m_apControllerState->bMayAddMenuTrendline; + m_aCommandAvailability[ ".uno:InsertMenuMeanValues" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertMenuXErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertMenuYErrorBars" ] = bIsWritable && m_apModelState->bSupportsStatistics; + m_aCommandAvailability[ ".uno:InsertSymbol" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsTextObject; + + // format objects + bool bFormatObjectAvailable = bIsWritable && bControllerStateIsValid && m_apControllerState->bIsFormateableObjectSelected; + m_aCommandAvailability[ ".uno:FormatSelection" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatAxis" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatTitle" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataSeries" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataPoint" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataLabels" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatDataLabel" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatXErrorBars; + m_aCommandAvailability[ ".uno:FormatYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatYErrorBars; + m_aCommandAvailability[ ".uno:FormatMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatMeanValue; + m_aCommandAvailability[ ".uno:FormatTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendline; + m_aCommandAvailability[ ".uno:FormatTrendlineEquation" ] = bFormatObjectAvailable && bControllerStateIsValid && m_apControllerState->bMayFormatTrendlineEquation; + m_aCommandAvailability[ ".uno:FormatStockLoss" ] = bFormatObjectAvailable; + m_aCommandAvailability[ ".uno:FormatStockGain" ] = bFormatObjectAvailable; + + m_aCommandAvailability[ ".uno:DiagramType" ] = bIsWritable; + m_aCommandAvailability[ ".uno:Legend" ] = bIsWritable && m_apModelState->bHasLegend; + m_aCommandAvailability[ ".uno:DiagramWall" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasWall; + m_aCommandAvailability[ ".uno:DiagramArea" ] = bIsWritable; + + m_aCommandAvailability[ ".uno:TransformDialog" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bHasSelectedObject && m_apControllerState->bIsPositionableObject; + + // 3d commands + m_aCommandAvailability[ ".uno:View3D" ] = bIsWritable && bModelStateIsValid && m_apModelState->bIsThreeD; + m_aCommandAvailability[ ".uno:DiagramFloor" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasFloor; + + //some more format commands with different ui text + m_aCommandAvailability[ ".uno:FormatWall" ] = m_aCommandAvailability[ ".uno:DiagramWall" ]; + m_aCommandAvailability[ ".uno:FormatFloor" ] = m_aCommandAvailability[ ".uno:DiagramFloor" ]; + m_aCommandAvailability[ ".uno:FormatChartArea" ] = m_aCommandAvailability[ ".uno:DiagramArea" ]; + m_aCommandAvailability[ ".uno:FormatLegend" ] = m_aCommandAvailability[ ".uno:Legend" ]; + + // depending on own data and ability to create new data provider + m_aCommandAvailability[".uno:DataRanges"] = bIsWritable && bModelStateIsValid && !m_apModelState->bHasDataFromPivotTable + && ((m_apModelState->bHasOwnData && bCanCreateDataProvider) || !m_apModelState->bHasOwnData); + m_aCommandAvailability[ ".uno:DiagramData" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasOwnData && bEnableDataTableDialog; + + // titles + m_aCommandAvailability[ ".uno:MainTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainTitle; + m_aCommandAvailability[ ".uno:SubTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSubTitle; + m_aCommandAvailability[ ".uno:XTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxisTitle; + m_aCommandAvailability[ ".uno:YTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxisTitle; + m_aCommandAvailability[ ".uno:ZTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxisTitle; + m_aCommandAvailability[ ".uno:SecondaryXTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryXAxisTitle; + m_aCommandAvailability[ ".uno:SecondaryYTitle" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasSecondaryYAxisTitle; + m_aCommandAvailability[ ".uno:AllTitles" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyTitle(); + + // text + m_aCommandAvailability[ ".uno:ScaleText" ] = bIsWritable && bModelStateIsValid ; + m_aCommandArguments[ ".uno:ScaleText" ] <<= bModelStateIsValid && m_apModelState->bHasAutoScaledText; + + // axes + m_aCommandAvailability[ ".uno:DiagramAxisX" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasXAxis; + m_aCommandAvailability[ ".uno:DiagramAxisY" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasYAxis; + m_aCommandAvailability[ ".uno:DiagramAxisZ" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasZAxis; + m_aCommandAvailability[ ".uno:DiagramAxisA" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasAAxis; + m_aCommandAvailability[ ".uno:DiagramAxisB" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasBAxis; + m_aCommandAvailability[ ".uno:DiagramAxisAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyAxis(); + + // grids + // note: x and y are swapped in the commands! + m_aCommandAvailability[ ".uno:DiagramGridYMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainXGrid; + m_aCommandAvailability[ ".uno:DiagramGridXMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainYGrid; + m_aCommandAvailability[ ".uno:DiagramGridZMain" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasMainZGrid; + m_aCommandAvailability[ ".uno:DiagramGridYHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpXGrid; + m_aCommandAvailability[ ".uno:DiagramGridXHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpYGrid; + m_aCommandAvailability[ ".uno:DiagramGridZHelp" ] = bIsWritable && bModelStateIsValid && m_apModelState->bHasHelpZGrid; + m_aCommandAvailability[ ".uno:DiagramGridAll" ] = bIsWritable && bModelStateIsValid && m_apModelState->HasAnyGrid(); + + // series arrangement + m_aCommandAvailability[ ".uno:Forward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Forward" ) : + ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesForward && bEnableDataTableDialog ) ); + m_aCommandAvailability[ ".uno:Backward" ] = ( bShapeContext ? isShapeControllerCommandAvailable( ".uno:Backward" ) : + ( bIsWritable && bControllerStateIsValid && m_apControllerState->bMayMoveSeriesBackward && bEnableDataTableDialog ) ); + + m_aCommandAvailability[ ".uno:InsertDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertDataLabel" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddMeanValue; + m_aCommandAvailability[ ".uno:InsertTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendline; + m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddTrendlineEquation; + m_aCommandAvailability[ ".uno:InsertTrendlineEquationAndR2" ] = m_aCommandAvailability[ ".uno:InsertTrendlineEquation" ]; + m_aCommandAvailability[ ".uno:InsertR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddR2Value; + m_aCommandAvailability[ ".uno:DeleteR2Value" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteR2Value; + + m_aCommandAvailability[ ".uno:InsertXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddXErrorBars; + m_aCommandAvailability[ ".uno:InsertYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayAddYErrorBars; + + m_aCommandAvailability[ ".uno:DeleteDataLabels" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteDataLabel" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteTrendline" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendline; + m_aCommandAvailability[ ".uno:DeleteTrendlineEquation" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteTrendlineEquation; + m_aCommandAvailability[ ".uno:DeleteMeanValue" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteMeanValue; + m_aCommandAvailability[ ".uno:DeleteXErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteXErrorBars; + m_aCommandAvailability[ ".uno:DeleteYErrorBars" ] = bIsWritable && bControllerStateIsValid && m_apControllerState->bMayDeleteYErrorBars; + + m_aCommandAvailability[ ".uno:ResetDataPoint" ] = bIsWritable; + m_aCommandAvailability[ ".uno:ResetAllDataPoints" ] = bIsWritable; + + m_aCommandAvailability[ ".uno:InsertAxis" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteAxis" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertAxisTitle" ] = bIsWritable; + m_aCommandAvailability[ ".uno:FormatMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteMajorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:FormatMinorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:InsertMinorGrid" ] = bIsWritable; + m_aCommandAvailability[ ".uno:DeleteMinorGrid" ] = bIsWritable; +} + +bool ControllerCommandDispatch::commandAvailable( const OUString & rCommand ) +{ + std::map< OUString, bool >::const_iterator aIt( m_aCommandAvailability.find( rCommand )); + if( aIt != m_aCommandAvailability.end()) + return aIt->second; + SAL_WARN("chart2", "commandAvailable: command not in availability map:" << rCommand); + return false; +} + +bool ControllerCommandDispatch::isShapeControllerCommandAvailable( const OUString& rCommand ) +{ + ShapeController* pShapeController(nullptr); + { + SolarMutexGuard g; + if (m_pDispatchContainer) + pShapeController = m_pDispatchContainer->getShapeController(); + } + if ( pShapeController ) + { + FeatureState aState( pShapeController->getState( rCommand ) ); + return aState.bEnabled; + } + return false; +} + +void ControllerCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + bool bIsChartSelectorURL = rURL == ".uno:ChartElementSelector"; + if( rURL.isEmpty() || bIsChartSelectorURL ) + { + uno::Any aArg; + aArg <<= Reference< frame::XController >(m_xChartController); + fireStatusEventForURL( ".uno:ChartElementSelector", aArg, true, xSingleListener ); + } + + if( rURL.isEmpty() ) + { + for (auto const& elem : m_aCommandAvailability) + fireStatusEventForURLImpl( elem.first, xSingleListener ); + } + else if( !bIsChartSelectorURL ) + fireStatusEventForURLImpl( rURL, xSingleListener ); + + // statusbar. Should be handled by base implementation + // @todo: remove if Issue 68864 is fixed + if( rURL.isEmpty() || rURL == ".uno:StatusBarVisible" ) + { + bool bIsStatusBarVisible( lcl_isStatusBarVisible( m_xChartController )); + fireStatusEventForURL( ".uno:StatusBarVisible", uno::Any( bIsStatusBarVisible ), true, xSingleListener ); + } +} + +// ____ XDispatch ____ +void SAL_CALL ControllerCommandDispatch::dispatch( + const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + if( commandAvailable( URL.Complete )) + m_xDispatch->dispatch( URL, Arguments ); +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL ControllerCommandDispatch::disposing() +{ + m_xChartController.clear(); + m_xDispatch.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL ControllerCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xChartController.clear(); + m_xDispatch.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XModifyListener ____ +void SAL_CALL ControllerCommandDispatch::modified( const lang::EventObject& aEvent ) +{ + bool bUpdateCommandAvailability = false; + + // Update the "ModelState" Struct. + if( m_apModelState && m_xChartController.is()) + { + m_apModelState->update( m_xChartController->getChartModel()); + bUpdateCommandAvailability = true; + } + + // Update the "ControllerState" Struct. + if( m_apControllerState && m_xChartController.is()) + { + m_apControllerState->update( m_xChartController, m_xChartController->getChartModel()); + bUpdateCommandAvailability = true; + } + + if( bUpdateCommandAvailability ) + updateCommandAvailability(); + + if (comphelper::LibreOfficeKit::isActive()) + { + if (SfxViewShell* pViewShell = SfxViewShell::Current()) + if (SfxObjectShell* pObjSh = pViewShell->GetObjectShell()) + pObjSh->SetModified(); + } + + CommandDispatch::modified( aEvent ); +} + +// ____ XSelectionChangeListener ____ +void SAL_CALL ControllerCommandDispatch::selectionChanged( const lang::EventObject& aEvent ) +{ + // Update the "ControllerState" Struct. + if( m_apControllerState && m_xChartController.is()) + { + m_apControllerState->update( m_xChartController, m_xChartController->getChartModel()); + updateCommandAvailability(); + } + + CommandDispatch::modified( aEvent ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ControllerCommandDispatch.hxx b/chart2/source/controller/main/ControllerCommandDispatch.hxx new file mode 100644 index 000000000..38b00c48d --- /dev/null +++ b/chart2/source/controller/main/ControllerCommandDispatch.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "CommandDispatch.hxx" +#include +#include +#include + +#include + +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ + +class ChartController; +class CommandDispatchContainer; + +namespace impl +{ +struct ModelState; +struct ControllerState; + +// #i63017# : need to implement the XSelectionChangeListener in order +// to update the ControllerState when the selection changes. +typedef ::cppu::ImplInheritanceHelper< + CommandDispatch, + css::view::XSelectionChangeListener > + ControllerCommandDispatch_Base; +} + +/** This class is a CommandDispatch that is responsible for all commands that + the ChartController supports. + + This class determines which commands are currently available (via the model + state) and if an available command is called forwards it to the + ChartController. + */ +class ControllerCommandDispatch : public impl::ControllerCommandDispatch_Base +{ +public: + explicit ControllerCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + ChartController* pController, CommandDispatchContainer* pContainer ); + virtual ~ControllerCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + + bool commandAvailable( const OUString & rCommand ); + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; + +private: + void fireStatusEventForURLImpl( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ); + + void updateCommandAvailability(); + + bool isShapeControllerCommandAvailable( const OUString& rCommand ); + + rtl::Reference m_xChartController; + css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier; + css::uno::Reference< css::frame::XDispatch > m_xDispatch; + + std::unique_ptr< impl::ModelState > m_apModelState; + std::unique_ptr< impl::ControllerState > m_apControllerState; + + mutable std::map< OUString, bool > m_aCommandAvailability; + mutable std::map< OUString, css::uno::Any > m_aCommandArguments; + + CommandDispatchContainer* m_pDispatchContainer; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_Base.cxx b/chart2/source/controller/main/DragMethod_Base.cxx new file mode 100644 index 000000000..e617acd34 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_Base.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DragMethod_Base.hxx" +#include +#include +#include +#include + +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::WeakReference; + +DragMethod_Base::DragMethod_Base( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , ActionDescriptionProvider::ActionType eActionType ) + : SdrDragMethod( rDrawViewWrapper ) + , m_rDrawViewWrapper(rDrawViewWrapper) + , m_aObjectCID(rObjectCID) + , m_eActionType( eActionType ) + , m_xChartModel( xChartModel.get() ) +{ + setMoveOnly(true); +} +DragMethod_Base::~DragMethod_Base() +{ +} + +rtl::Reference<::chart::ChartModel> DragMethod_Base::getChartModel() const +{ + return m_xChartModel.get(); +} + +OUString DragMethod_Base::getUndoDescription() const +{ + return ActionDescriptionProvider::createDescription( + m_eActionType, + ObjectNameProvider::getName( ObjectIdentifier::getObjectType( m_aObjectCID ))); +} +OUString DragMethod_Base::GetSdrDragComment() const +{ + return getUndoDescription(); +} +PointerStyle DragMethod_Base::GetSdrDragPointer() const +{ + if( IsDraggingPoints() || IsDraggingGluePoints() ) + return PointerStyle::MovePoint; + else + return PointerStyle::Move; +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_Base.hxx b/chart2/source/controller/main/DragMethod_Base.hxx new file mode 100644 index 000000000..497b31f6e --- /dev/null +++ b/chart2/source/controller/main/DragMethod_Base.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart { class DrawViewWrapper; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +class DragMethod_Base : public SdrDragMethod +{ +public: + DragMethod_Base( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , ActionDescriptionProvider::ActionType eActionType = ActionDescriptionProvider::ActionType::Move ); + virtual ~DragMethod_Base() override; + + OUString getUndoDescription() const; + + virtual OUString GetSdrDragComment() const override; + virtual PointerStyle GetSdrDragPointer() const override; + +protected: + rtl::Reference<::chart::ChartModel> getChartModel() const; + +protected: + DrawViewWrapper& m_rDrawViewWrapper; + OUString m_aObjectCID; + ActionDescriptionProvider::ActionType m_eActionType; + +private: + unotools::WeakReference<::chart::ChartModel> m_xChartModel; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_PieSegment.cxx b/chart2/source/controller/main/DragMethod_PieSegment.cxx new file mode 100644 index 000000000..002c54ec0 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_PieSegment.cxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DragMethod_PieSegment.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::basegfx::B2DVector; + +DragMethod_PieSegment::DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) + : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel ) + , m_aStartVector(100.0,100.0) + , m_fInitialOffset(0.0) + , m_fAdditionalOffset(0.0) + , m_aDragDirection(1000.0,1000.0) + , m_fDragRange( 1.0 ) +{ + std::u16string_view aParameter( ObjectIdentifier::getDragParameterString( m_aObjectCID ) ); + + sal_Int32 nOffsetPercent(0); + awt::Point aMinimumPosition(0,0); + awt::Point aMaximumPosition(0,0); + + ObjectIdentifier::parsePieSegmentDragParameterString( + aParameter, nOffsetPercent, aMinimumPosition, aMaximumPosition ); + + m_fInitialOffset = nOffsetPercent / 100.0; + if( m_fInitialOffset < 0.0 ) + m_fInitialOffset = 0.0; + if( m_fInitialOffset > 1.0 ) + m_fInitialOffset = 1.0; + B2DVector aMinVector( aMinimumPosition.X, aMinimumPosition.Y ); + B2DVector aMaxVector( aMaximumPosition.X, aMaximumPosition.Y ); + m_aDragDirection = aMaxVector - aMinVector; + m_fDragRange = m_aDragDirection.scalar( m_aDragDirection ); + if( m_fDragRange == 0.0 ) + m_fDragRange = 1.0; +} +DragMethod_PieSegment::~DragMethod_PieSegment() +{ +} +OUString DragMethod_PieSegment::GetSdrDragComment() const +{ + OUString aStr = SchResId(STR_STATUS_PIE_SEGMENT_EXPLODED); + aStr = aStr.replaceFirst( "%PERCENTVALUE", OUString::number( static_cast((m_fAdditionalOffset+m_fInitialOffset)*100.0) )); + return aStr; +} +bool DragMethod_PieSegment::BeginSdrDrag() +{ + Point aStart( DragStat().GetStart() ); + m_aStartVector = B2DVector( aStart.X(), aStart.Y() ); + Show(); + return true; +} +void DragMethod_PieSegment::MoveSdrDrag(const Point& rPnt) +{ + if( !DragStat().CheckMinMoved(rPnt) ) + return; + + //calculate new offset + B2DVector aShiftVector( B2DVector( rPnt.X(), rPnt.Y() ) - m_aStartVector ); + m_fAdditionalOffset = m_aDragDirection.scalar( aShiftVector )/m_fDragRange; // projection + + if( m_fAdditionalOffset < -m_fInitialOffset ) + m_fAdditionalOffset = -m_fInitialOffset; + else if( m_fAdditionalOffset > (1.0-m_fInitialOffset) ) + m_fAdditionalOffset = 1.0 - m_fInitialOffset; + + B2DVector aNewPosVector = m_aStartVector + (m_aDragDirection * m_fAdditionalOffset); + Point aNewPos( static_cast(aNewPosVector.getX()), static_cast(aNewPosVector.getY()) ); + if( aNewPos != DragStat().GetNow() ) + { + Hide(); + DragStat().NextMove( aNewPos ); + Show(); + } +} +bool DragMethod_PieSegment::EndSdrDrag(bool /*bCopy*/) +{ + Hide(); + + try + { + rtl::Reference<::chart::ChartModel> xChartModel( getChartModel() ); + if( xChartModel.is() ) + { + Reference< beans::XPropertySet > xPointProperties( + ObjectIdentifier::getObjectPropertySet( m_aObjectCID, xChartModel ) ); + if( xPointProperties.is() ) + xPointProperties->setPropertyValue( "Offset", uno::Any( m_fAdditionalOffset+m_fInitialOffset )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return true; +} +basegfx::B2DHomMatrix DragMethod_PieSegment::getCurrentTransformation() const +{ + basegfx::B2DHomMatrix aRetval; + + aRetval.translate(DragStat().GetDX(), DragStat().GetDY()); + + return aRetval; +} +void DragMethod_PieSegment::createSdrDragEntries() +{ + SdrObject* pObj = m_rDrawViewWrapper.getSelectedObject(); + SdrPageView* pPV = m_rDrawViewWrapper.GetPageView(); + + if( pObj && pPV ) + { + const basegfx::B2DPolyPolygon aNewPolyPolygon(pObj->TakeXorPoly()); + addSdrDragEntry(std::unique_ptr(new SdrDragEntryPolyPolygon(aNewPolyPolygon))); + } +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_PieSegment.hxx b/chart2/source/controller/main/DragMethod_PieSegment.hxx new file mode 100644 index 000000000..8cb498373 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_PieSegment.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "DragMethod_Base.hxx" +#include + +namespace chart +{ + +class DragMethod_PieSegment : public DragMethod_Base +{ +public: + DragMethod_PieSegment( DrawViewWrapper& rDrawViewWrapper, const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + virtual ~DragMethod_PieSegment() override; + + virtual OUString GetSdrDragComment() const override; + virtual bool BeginSdrDrag() override; + virtual void MoveSdrDrag(const Point& rPnt) override; + virtual bool EndSdrDrag(bool bCopy) override; + + virtual basegfx::B2DHomMatrix getCurrentTransformation() const override; + +protected: + virtual void createSdrDragEntries() override; + +private: + ::basegfx::B2DVector m_aStartVector; + double m_fInitialOffset; + double m_fAdditionalOffset; + ::basegfx::B2DVector m_aDragDirection; + double m_fDragRange; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.cxx b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx new file mode 100644 index 000000000..34efccfd9 --- /dev/null +++ b/chart2/source/controller/main/DragMethod_RotateDiagram.cxx @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DragMethod_RotateDiagram.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +DragMethod_RotateDiagram::DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , RotationDirection eRotationDirection ) + : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel, ActionDescriptionProvider::ActionType::Rotate ) + , m_pScene(nullptr) + , m_aReferenceRect(100,100,100,100) + , m_aStartPos(0,0) + , m_fInitialXAngleRad(0.0) + , m_fInitialYAngleRad(0.0) + , m_fInitialZAngleRad(0.0) + , m_fAdditionalXAngleRad(0.0) + , m_fAdditionalYAngleRad(0.0) + , m_fAdditionalZAngleRad(0.0) + , m_nInitialHorizontalAngleDegree(0) + , m_nInitialVerticalAngleDegree(0) + , m_nAdditionalHorizontalAngleDegree(0) + , m_nAdditionalVerticalAngleDegree(0) + , m_eRotationDirection(eRotationDirection) + , m_bRightAngledAxes(false) +{ + m_pScene = SelectionHelper::getSceneToRotate( rDrawViewWrapper.getNamedSdrObject( rObjectCID ) ); + SdrObject* pObj = rDrawViewWrapper.getSelectedObject(); + if(!(pObj && m_pScene)) + return; + + m_aReferenceRect = pObj->GetLogicRect(); + + m_aWireframePolyPolygon = m_pScene->CreateWireframe(); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram(getChartModel()); + if( !xDiagram.is() ) + return; + + ThreeDHelper::getRotationFromDiagram( xDiagram + , m_nInitialHorizontalAngleDegree, m_nInitialVerticalAngleDegree ); + + ThreeDHelper::getRotationAngleFromDiagram( xDiagram + , m_fInitialXAngleRad, m_fInitialYAngleRad, m_fInitialZAngleRad ); + + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) + xDiagram->getPropertyValue("RightAngledAxes") >>= m_bRightAngledAxes; + if(m_bRightAngledAxes) + { + if( m_eRotationDirection==ROTATIONDIRECTION_Z ) + m_eRotationDirection=ROTATIONDIRECTION_FREE; + ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fInitialXAngleRad, m_fInitialYAngleRad ); + } +} +DragMethod_RotateDiagram::~DragMethod_RotateDiagram() +{ +} +OUString DragMethod_RotateDiagram::GetSdrDragComment() const +{ + return OUString(); +} +bool DragMethod_RotateDiagram::BeginSdrDrag() +{ + m_aStartPos = DragStat().GetStart(); + Show(); + return true; +} +void DragMethod_RotateDiagram::MoveSdrDrag(const Point& rPnt) +{ + if( !DragStat().CheckMinMoved(rPnt) ) + return; + + Hide(); + + //calculate new angle + double fX = M_PI_2 * static_cast(rPnt.Y() - m_aStartPos.Y()) + / (m_aReferenceRect.GetHeight() > 0 ? static_cast(m_aReferenceRect.GetHeight()) : 1.0); + double fY = M_PI * static_cast(rPnt.X() - m_aStartPos.X()) + / (m_aReferenceRect.GetWidth() > 0 ? static_cast(m_aReferenceRect.GetWidth()) : 1.0); + + if( m_eRotationDirection != ROTATIONDIRECTION_Y ) + m_fAdditionalYAngleRad = fY; + else + m_fAdditionalYAngleRad = 0.0; + if( m_eRotationDirection != ROTATIONDIRECTION_X ) + m_fAdditionalXAngleRad = fX; + else + m_fAdditionalXAngleRad = 0.0; + m_fAdditionalZAngleRad = 0.0; + + if( m_eRotationDirection == ROTATIONDIRECTION_Z ) + { + m_fAdditionalXAngleRad = 0.0; + m_fAdditionalYAngleRad = 0.0; + + double fCx = m_aReferenceRect.Center().X(); + double fCy = m_aReferenceRect.Center().Y(); + + m_fAdditionalZAngleRad = atan((fCx - m_aStartPos.X())/(m_aStartPos.Y()-fCy)) + + atan((fCx - rPnt.X())/(fCy-rPnt.Y())); + } + + m_nAdditionalHorizontalAngleDegree = static_cast(basegfx::rad2deg(m_fAdditionalXAngleRad)); + m_nAdditionalVerticalAngleDegree = -static_cast(basegfx::rad2deg(m_fAdditionalYAngleRad)); + + DragStat().NextMove(rPnt); + Show(); +} +bool DragMethod_RotateDiagram::EndSdrDrag(bool /*bCopy*/) +{ + Hide(); + + if( m_bRightAngledAxes || m_eRotationDirection==ROTATIONDIRECTION_Z ) + { + double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad; + double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad; + double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad; + + if(m_bRightAngledAxes) + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY ); + + ThreeDHelper::setRotationAngleToDiagram( ChartModelHelper::findDiagram( getChartModel() ) + , fResultX, fResultY, fResultZ ); + } + else + { + ThreeDHelper::setRotationToDiagram( ChartModelHelper::findDiagram( getChartModel() ) + , m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree ); + } + + return true; +} +void DragMethod_RotateDiagram::CreateOverlayGeometry( + sdr::overlay::OverlayManager& rOverlayManager, + const sdr::contact::ObjectContact& rObjectContact) +{ + ::basegfx::B3DHomMatrix aCurrentTransform; + aCurrentTransform.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + + double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad; + double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad; + double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad; + + if(!m_bRightAngledAxes) + { + if( m_eRotationDirection!=ROTATIONDIRECTION_Z ) + { + ThreeDHelper::convertElevationRotationDegToXYZAngleRad( + m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, -(m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree) + , fResultX, fResultY, fResultZ ); + } + aCurrentTransform.rotate( fResultX, fResultY, fResultZ ); + } + else + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY ); + aCurrentTransform.shearXY(fResultY,-fResultX); + } + + if(!(m_aWireframePolyPolygon.count() && m_pScene)) + return; + + const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(m_pScene->GetViewContact()); + const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D()); + const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation()); + const basegfx::B3DHomMatrix aTransform(aWorldToView * aCurrentTransform); + + // transform to relative scene coordinates + basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(m_aWireframePolyPolygon, aTransform)); + + // transform to 2D view coordinates + aPolyPolygon.transform(rVCScene.getObjectTransformation()); + + std::unique_ptr pNew( + new sdr::overlay::OverlayPolyPolygonStripedAndFilled( + aPolyPolygon)); + + insertNewlyCreatedOverlayObjectForSdrDragMethod( + std::move(pNew), + rObjectContact, + rOverlayManager); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DragMethod_RotateDiagram.hxx b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx new file mode 100644 index 000000000..69e9050ee --- /dev/null +++ b/chart2/source/controller/main/DragMethod_RotateDiagram.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "DragMethod_Base.hxx" + +#include + +class E3dScene; +namespace chart { class DrawViewWrapper; } + +namespace chart +{ + +class DragMethod_RotateDiagram : public DragMethod_Base +{ +public: + enum RotationDirection + { + ROTATIONDIRECTION_FREE, + ROTATIONDIRECTION_X, + ROTATIONDIRECTION_Y, + ROTATIONDIRECTION_Z + }; + + DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper + , const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , RotationDirection eRotationDirection + ); + virtual ~DragMethod_RotateDiagram() override; + + virtual OUString GetSdrDragComment() const override; + + virtual bool BeginSdrDrag() override; + virtual void MoveSdrDrag(const Point& rPnt) override; + virtual bool EndSdrDrag(bool bCopy) override; + + virtual void CreateOverlayGeometry( + sdr::overlay::OverlayManager& rOverlayManager, + const sdr::contact::ObjectContact& rObjectContact) override; + +private: + E3dScene* m_pScene; + + tools::Rectangle m_aReferenceRect; + Point m_aStartPos; + basegfx::B3DPolyPolygon m_aWireframePolyPolygon; + + double m_fInitialXAngleRad; + double m_fInitialYAngleRad; + double m_fInitialZAngleRad; + + double m_fAdditionalXAngleRad; + double m_fAdditionalYAngleRad; + double m_fAdditionalZAngleRad; + + sal_Int32 m_nInitialHorizontalAngleDegree; + sal_Int32 m_nInitialVerticalAngleDegree; + + sal_Int32 m_nAdditionalHorizontalAngleDegree; + sal_Int32 m_nAdditionalVerticalAngleDegree; + + RotationDirection m_eRotationDirection; + bool m_bRightAngledAxes; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.cxx b/chart2/source/controller/main/DrawCommandDispatch.cxx new file mode 100644 index 000000000..c5cea4c5b --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.cxx @@ -0,0 +1,614 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DrawCommandDispatch.hxx" +#include "DrawCommandDispatch.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::frame; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +namespace chart +{ + +DrawCommandDispatch::DrawCommandDispatch( const Reference< uno::XComponentContext >& rxContext, + ChartController* pController ) + :FeatureCommandDispatchBase( rxContext ) + ,m_pChartController( pController ) +{ +} + +DrawCommandDispatch::~DrawCommandDispatch() +{ +} + +bool DrawCommandDispatch::isFeatureSupported( const OUString& rCommandURL ) +{ + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + return parseCommandURL( rCommandURL, &nFeatureId, &aBaseCommand, &aCustomShapeType ); +} + +static ::basegfx::B2DPolyPolygon getPolygon(TranslateId pResId, const SdrModel& rModel) +{ + ::basegfx::B2DPolyPolygon aReturn; + XLineEndListRef pLineEndList = rModel.GetLineEndList(); + if ( pLineEndList.is() ) + { + OUString aName(SvxResId(pResId)); + tools::Long nCount = pLineEndList->Count(); + for ( tools::Long nIndex = 0; nIndex < nCount; ++nIndex ) + { + const XLineEndEntry* pEntry = pLineEndList->GetLineEnd(nIndex); + if ( pEntry->GetName() == aName ) + { + aReturn = pEntry->GetLineEnd(); + break; + } + } + } + return aReturn; +} + +void DrawCommandDispatch::setAttributes( SdrObject* pObj ) +{ + if ( !m_pChartController ) + return; + + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawModelWrapper && pDrawViewWrapper && pDrawViewWrapper->GetCurrentObjIdentifier() == SdrObjKind::CustomShape) ) + return; + + bool bAttributesAppliedFromGallery = false; + if ( GalleryExplorer::GetSdrObjCount( GALLERY_THEME_POWERPOINT ) ) + { + std::vector< OUString > aObjList; + if ( GalleryExplorer::FillObjListTitle( GALLERY_THEME_POWERPOINT, aObjList ) ) + { + for ( size_t i = 0; i < aObjList.size(); ++i ) + { + if ( aObjList[ i ].equalsIgnoreAsciiCase( m_aCustomShapeType ) ) + { + FmFormModel aModel; + SfxItemPool& rPool(aModel.GetItemPool()); + rPool.FreezeIdRanges(); + + if ( GalleryExplorer::GetSdrObj( GALLERY_THEME_POWERPOINT, i, &aModel ) ) + { + const SdrObject* pSourceObj = aModel.GetPage( 0 )->GetObj( 0 ); + if ( pSourceObj ) + { + const SfxItemSet& rSource = pSourceObj->GetMergedItemSet(); + SfxItemSetFixed< + // Ranges from SdrAttrObj: + SDRATTR_START, SDRATTR_SHADOW_LAST, + SDRATTR_MISC_FIRST, + SDRATTR_MISC_LAST, + SDRATTR_TEXTDIRECTION, + SDRATTR_TEXTDIRECTION, + // Graphic attributes, 3D + // properties, CustomShape + // properties: + SDRATTR_GRAF_FIRST, + SDRATTR_CUSTOMSHAPE_LAST, + // Range from SdrTextObj: + EE_ITEMS_START, EE_ITEMS_END> + aDest(pObj->getSdrModelFromSdrObject().GetItemPool()); + aDest.Set( rSource ); + pObj->SetMergedItemSet( aDest ); + Degree100 nAngle = pSourceObj->GetRotateAngle(); + if ( nAngle ) + pObj->NbcRotate( pObj->GetSnapRect().Center(), nAngle ); + bAttributesAppliedFromGallery = true; + } + } + break; + } + } + } + } + if ( !bAttributesAppliedFromGallery ) + { + pObj->SetMergedItem( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) ); + pObj->SetMergedItem( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_BLOCK ) ); + pObj->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) ); + + o3tl::unsafe_downcast< SdrObjCustomShape* >( pObj )->MergeDefaultAttributes( &m_aCustomShapeType ); + } +} + +void DrawCommandDispatch::setLineEnds( SfxItemSet& rAttr ) +{ + if ( !(m_nFeatureId == COMMAND_ID_LINE_ARROW_END && m_pChartController) ) + return; + + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawModelWrapper && pDrawViewWrapper) ) + return; + + ::basegfx::B2DPolyPolygon aArrow( getPolygon( RID_SVXSTR_ARROW, pDrawModelWrapper->getSdrModel() ) ); + if ( !aArrow.count() ) + { + ::basegfx::B2DPolygon aNewArrow; + aNewArrow.append( ::basegfx::B2DPoint( 10.0, 0.0 ) ); + aNewArrow.append( ::basegfx::B2DPoint( 0.0, 30.0) ); + aNewArrow.append( ::basegfx::B2DPoint( 20.0, 30.0 ) ); + aNewArrow.setClosed( true ); + aArrow.append( aNewArrow ); + } + + SfxItemSet aSet( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aSet ); + + tools::Long nWidth = 300; // (1/100th mm) + if ( aSet.GetItemState( XATTR_LINEWIDTH ) != SfxItemState::DONTCARE ) + { + tools::Long nValue = aSet.Get( XATTR_LINEWIDTH ).GetValue(); + if ( nValue > 0 ) + { + nWidth = nValue * 3; + } + } + + rAttr.Put( XLineEndItem( SvxResId( RID_SVXSTR_ARROW ), aArrow ) ); + rAttr.Put( XLineEndWidthItem( nWidth ) ); +} + +// WeakComponentImplHelperBase +void DrawCommandDispatch::disposing() +{ +} + +// XEventListener +void DrawCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ +} + +FeatureState DrawCommandDispatch::getState( const OUString& rCommand ) +{ + FeatureState aReturn; + aReturn.bEnabled = false; + aReturn.aState <<= false; + + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + if ( parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) ) + { + switch ( nFeatureId ) + { + case COMMAND_ID_OBJECT_SELECT: + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + case COMMAND_ID_DRAW_RECT: + case COMMAND_ID_DRAW_ELLIPSE: + case COMMAND_ID_DRAW_FREELINE_NOFILL: + case COMMAND_ID_DRAW_TEXT: + case COMMAND_ID_DRAW_CAPTION: + case COMMAND_ID_DRAWTBX_CS_BASIC: + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + case COMMAND_ID_DRAWTBX_CS_ARROW: + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + case COMMAND_ID_DRAWTBX_CS_STAR: + { + aReturn.bEnabled = true; + aReturn.aState <<= false; + } + break; + default: + { + aReturn.bEnabled = false; + aReturn.aState <<= false; + } + break; + } + } + + return aReturn; +} + +void DrawCommandDispatch::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& rArgs ) +{ + ChartDrawMode eDrawMode = CHARTDRAW_SELECT; + SdrObjKind eKind = SdrObjKind::NONE; + + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aCustomShapeType; + if ( !parseCommandURL( rCommand, &nFeatureId, &aBaseCommand, &aCustomShapeType ) ) + return; + + bool bCreate = false; + m_nFeatureId = nFeatureId; + m_aCustomShapeType = aCustomShapeType; + + switch ( nFeatureId ) + { + case COMMAND_ID_OBJECT_SELECT: + { + eDrawMode = CHARTDRAW_SELECT; + eKind = SdrObjKind::NONE; + } + break; + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Line; + } + break; + case COMMAND_ID_DRAW_RECT: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Rectangle; + } + break; + case COMMAND_ID_DRAW_ELLIPSE: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::CircleOrEllipse; + } + break; + case COMMAND_ID_DRAW_FREELINE_NOFILL: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::FreehandLine; + } + break; + case COMMAND_ID_DRAW_TEXT: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Text; + bCreate = true; + } + break; + case COMMAND_ID_DRAW_CAPTION: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::Caption; + } + break; + case COMMAND_ID_DRAWTBX_CS_BASIC: + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + case COMMAND_ID_DRAWTBX_CS_ARROW: + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + case COMMAND_ID_DRAWTBX_CS_STAR: + { + eDrawMode = CHARTDRAW_INSERT; + eKind = SdrObjKind::CustomShape; + } + break; + default: + { + eDrawMode = CHARTDRAW_SELECT; + eKind = SdrObjKind::NONE; + } + break; + } + + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !pDrawViewWrapper ) + return; + + SolarMutexGuard aGuard; + m_pChartController->setDrawMode( eDrawMode ); + setInsertObj(eKind); + if ( bCreate ) + { + pDrawViewWrapper->SetCreateMode(); + } + + const beans::PropertyValue* pIter = rArgs.getConstArray(); + const beans::PropertyValue* pEnd = pIter + rArgs.getLength(); + const beans::PropertyValue* pKeyModifier = std::find_if(pIter, pEnd, + [](const beans::PropertyValue& lhs) + {return lhs.Name == "KeyModifier";} ); + sal_Int16 nKeyModifier = 0; + if ( !(pKeyModifier != pEnd && ( pKeyModifier->Value >>= nKeyModifier ) && nKeyModifier == KEY_MOD1) ) + return; + + if ( eDrawMode != CHARTDRAW_INSERT ) + return; + + SdrObject* pObj = createDefaultObject( nFeatureId ); + if ( pObj ) + { + SdrPageView* pPageView = pDrawViewWrapper->GetSdrPageView(); + if (pDrawViewWrapper->InsertObjectAtView(pObj, *pPageView)) + m_pChartController->SetAndApplySelection(Reference(pObj->getUnoShape(), uno::UNO_QUERY)); + if ( nFeatureId == COMMAND_ID_DRAW_TEXT ) + { + m_pChartController->StartTextEdit(); + } + } +} + +void DrawCommandDispatch::describeSupportedFeatures() +{ + implDescribeSupportedFeature( ".uno:SelectObject", COMMAND_ID_OBJECT_SELECT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Line", COMMAND_ID_DRAW_LINE, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:LineArrowEnd", COMMAND_ID_LINE_ARROW_END, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Rect", COMMAND_ID_DRAW_RECT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Ellipse", COMMAND_ID_DRAW_ELLIPSE, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:Freeline_Unfilled", COMMAND_ID_DRAW_FREELINE_NOFILL, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DrawText", COMMAND_ID_DRAW_TEXT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:DrawCaption", COMMAND_ID_DRAW_CAPTION, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:BasicShapes", COMMAND_ID_DRAWTBX_CS_BASIC, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:SymbolShapes", COMMAND_ID_DRAWTBX_CS_SYMBOL, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:ArrowShapes", COMMAND_ID_DRAWTBX_CS_ARROW, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:FlowChartShapes", COMMAND_ID_DRAWTBX_CS_FLOWCHART, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:CalloutShapes", COMMAND_ID_DRAWTBX_CS_CALLOUT, CommandGroup::INSERT ); + implDescribeSupportedFeature( ".uno:StarShapes", COMMAND_ID_DRAWTBX_CS_STAR, CommandGroup::INSERT ); +} + +void DrawCommandDispatch::setInsertObj(SdrObjKind eObj) +{ + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( pDrawViewWrapper ) + { + pDrawViewWrapper->SetCurrentObj( eObj /*, Inventor */); + } +} + +SdrObject* DrawCommandDispatch::createDefaultObject( const sal_uInt16 nID ) +{ + SdrObject* pObj = nullptr; + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + + if ( pDrawViewWrapper && pDrawModelWrapper ) + { + Reference< drawing::XDrawPage > xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + SdrPage* pPage = GetSdrPageFromXDrawPage( xDrawPage ); + if ( pPage ) + { + SolarMutexGuard aGuard; + + pObj = SdrObjFactory::MakeNewObject( + pDrawModelWrapper->getSdrModel(), + pDrawViewWrapper->GetCurrentObjInventor(), + pDrawViewWrapper->GetCurrentObjIdentifier()); + + if ( pObj ) + { + Size aObjectSize( 4000, 2500 ); + tools::Rectangle aPageRect( tools::Rectangle( Point( 0, 0 ), pPage->GetSize() ) ); + Point aObjectPos = aPageRect.Center(); + aObjectPos.AdjustX( -(aObjectSize.Width() / 2) ); + aObjectPos.AdjustY( -(aObjectSize.Height() / 2) ); + tools::Rectangle aRect( aObjectPos, aObjectSize ); + + switch ( nID ) + { + case COMMAND_ID_DRAW_LINE: + case COMMAND_ID_LINE_ARROW_END: + { + if ( auto const pathObj = dynamic_cast( pObj) ) + { + Point aStart = aRect.TopLeft(); + Point aEnd = aRect.BottomRight(); + sal_Int32 nYMiddle( ( aRect.Top() + aRect.Bottom() ) / 2 ); + basegfx::B2DPolygon aPoly; + aPoly.append( basegfx::B2DPoint( aStart.X(), nYMiddle ) ); + aPoly.append( basegfx::B2DPoint( aEnd.X(), nYMiddle ) ); + pathObj->SetPathPoly(basegfx::B2DPolyPolygon(aPoly)); + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + setLineEnds( aSet ); + pObj->SetMergedItemSet( aSet ); + } + } + break; + case COMMAND_ID_DRAW_FREELINE_NOFILL: + { + if ( auto const pathObj = dynamic_cast( pObj) ) + { + basegfx::B2DPolygon aInnerPoly; + aInnerPoly.append( basegfx::B2DPoint( aRect.Left(), aRect.Bottom() ) ); + aInnerPoly.appendBezierSegment( + basegfx::B2DPoint( aRect.Left(), aRect.Top() ), + basegfx::B2DPoint( aRect.Center().X(), aRect.Top() ), + basegfx::B2DPoint( aRect.Center().X(), aRect.Center().Y() ) ); + aInnerPoly.appendBezierSegment( + basegfx::B2DPoint( aRect.Center().X(), aRect.Bottom() ), + basegfx::B2DPoint( aRect.Right(), aRect.Bottom() ), + basegfx::B2DPoint( aRect.Right(), aRect.Top() ) ); + basegfx::B2DPolyPolygon aPoly; + aPoly.append( aInnerPoly ); + pathObj->SetPathPoly(aPoly); + } + } + break; + case COMMAND_ID_DRAW_TEXT: + case COMMAND_ID_DRAW_TEXT_VERTICAL: + { + if ( SdrTextObj* pTextObj = dynamic_cast( pObj) ) + { + pTextObj->SetLogicRect( aRect ); + bool bVertical = ( nID == COMMAND_ID_DRAW_TEXT_VERTICAL ); + pTextObj->SetVerticalWriting( bVertical ); + if ( bVertical ) + { + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + aSet.Put( makeSdrTextAutoGrowWidthItem( true ) ); + aSet.Put( makeSdrTextAutoGrowHeightItem( false ) ); + aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_TOP ) ); + aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) ); + pTextObj->SetMergedItemSet( aSet ); + } + } + } + break; + case COMMAND_ID_DRAW_CAPTION: + case COMMAND_ID_DRAW_CAPTION_VERTICAL: + { + if ( SdrCaptionObj* pCaptionObj = dynamic_cast( pObj) ) + { + bool bIsVertical( nID == COMMAND_ID_DRAW_CAPTION_VERTICAL ); + pCaptionObj->SetVerticalWriting( bIsVertical ); + if ( bIsVertical ) + { + SfxItemSet aSet( pObj->GetMergedItemSet() ); + aSet.Put( SdrTextVertAdjustItem( SDRTEXTVERTADJUST_CENTER ) ); + aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_RIGHT ) ); + pObj->SetMergedItemSet( aSet ); + } + pCaptionObj->SetLogicRect( aRect ); + pCaptionObj->SetTailPos( + aRect.TopLeft() - Point( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ) ); + } + } + break; + default: + { + pObj->SetLogicRect( aRect ); + SfxItemSet aSet( pDrawModelWrapper->GetItemPool() ); + setAttributes( pObj ); + pObj->SetMergedItemSet( aSet ); + } + break; + } + } + } + } + + return pObj; +} + +bool DrawCommandDispatch::parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId, + OUString* pBaseCommand, OUString* pCustomShapeType ) +{ + bool bFound = true; + sal_uInt16 nFeatureId = 0; + OUString aBaseCommand; + OUString aType; + + sal_Int32 nIndex = std::min(sal_Int32(1), rCommandURL.getLength()); + std::u16string_view aToken = o3tl::getToken(rCommandURL, 0, '.', nIndex ); + if ( nIndex == -1 || aToken.empty() ) + { + aBaseCommand = rCommandURL; + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + nFeatureId = aIter->second.nFeatureId; + + switch ( nFeatureId ) + { + case COMMAND_ID_DRAWTBX_CS_BASIC: + { + aType = "diamond"; + } + break; + case COMMAND_ID_DRAWTBX_CS_SYMBOL: + { + aType = "smiley"; + } + break; + case COMMAND_ID_DRAWTBX_CS_ARROW: + { + aType = "left-right-arrow"; + } + break; + case COMMAND_ID_DRAWTBX_CS_FLOWCHART: + { + aType = "flowchart-internal-storage"; + } + break; + case COMMAND_ID_DRAWTBX_CS_CALLOUT: + { + aType = "round-rectangular-callout"; + } + break; + case COMMAND_ID_DRAWTBX_CS_STAR: + { + aType = "star5"; + } + break; + default: + { + } + break; + } + } + else + { + bFound = false; + } + } + else + { + aBaseCommand = rCommandURL.copy( 0, nIndex - 1 ); + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( aBaseCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + nFeatureId = aIter->second.nFeatureId; + aType = rCommandURL.getToken( 0, '.', nIndex ); + } + else + { + bFound = false; + } + } + + *pnFeatureId = nFeatureId; + *pBaseCommand = aBaseCommand; + *pCustomShapeType = aType; + + return bFound; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.h b/chart2/source/controller/main/DrawCommandDispatch.h new file mode 100644 index 000000000..faf70bde1 --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef CHART_DRAWCOMMANDDISPATCH_HRC +#define CHART_DRAWCOMMANDDISPATCH_HRC + +//Command Ids: +#define COMMAND_ID_OBJECT_SELECT 1 +#define COMMAND_ID_DRAW_LINE 2 +#define COMMAND_ID_LINE_ARROW_END 3 +#define COMMAND_ID_DRAW_RECT 4 +#define COMMAND_ID_DRAW_ELLIPSE 5 +#define COMMAND_ID_DRAW_FREELINE_NOFILL 6 +#define COMMAND_ID_DRAW_TEXT 7 +#define COMMAND_ID_DRAW_TEXT_VERTICAL 8 +#define COMMAND_ID_DRAW_CAPTION 9 +#define COMMAND_ID_DRAW_CAPTION_VERTICAL 10 +#define COMMAND_ID_DRAWTBX_CS_BASIC 11 +#define COMMAND_ID_DRAWTBX_CS_SYMBOL 12 +#define COMMAND_ID_DRAWTBX_CS_ARROW 13 +#define COMMAND_ID_DRAWTBX_CS_FLOWCHART 14 +#define COMMAND_ID_DRAWTBX_CS_CALLOUT 15 +#define COMMAND_ID_DRAWTBX_CS_STAR 16 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/DrawCommandDispatch.hxx b/chart2/source/controller/main/DrawCommandDispatch.hxx new file mode 100644 index 000000000..febfa8338 --- /dev/null +++ b/chart2/source/controller/main/DrawCommandDispatch.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "FeatureCommandDispatchBase.hxx" + +class SfxItemSet; +class SdrObject; + +namespace chart +{ + +class ChartController; + +/** This is a CommandDispatch implementation for drawing objects. + */ +class DrawCommandDispatch: public FeatureCommandDispatchBase +{ +public: + DrawCommandDispatch( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController ); + virtual ~DrawCommandDispatch() override; + + virtual bool isFeatureSupported( const OUString& rCommandURL ) override; + + void setAttributes( SdrObject* pObj ); + void setLineEnds( SfxItemSet& rAttr ); + +protected: + // WeakComponentImplHelperBase + virtual void SAL_CALL disposing() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) override; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + +private: + void setInsertObj(SdrObjKind eObj); + SdrObject* createDefaultObject( const sal_uInt16 nID ); + + bool parseCommandURL( const OUString& rCommandURL, sal_uInt16* pnFeatureId, OUString* pBaseCommand, OUString* pCustomShapeType ); + + ChartController* m_pChartController; + OUString m_aCustomShapeType; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ElementSelector.cxx b/chart2/source/controller/main/ElementSelector.cxx new file mode 100644 index 000000000..d538108ae --- /dev/null +++ b/chart2/source/controller/main/ElementSelector.cxx @@ -0,0 +1,319 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ElementSelector.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace chart { class ExplicitValueProvider; } + +namespace chart +{ + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +constexpr OUStringLiteral lcl_aServiceName + = u"com.sun.star.comp.chart.ElementSelectorToolbarController"; +} + +SelectorListBox::SelectorListBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/schart/ui/combobox.ui", "ComboBox") + , m_xWidget(m_xBuilder->weld_combo_box("combobox")) + , m_bReleaseFocus(true) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->connect_key_press(LINK(this, SelectorListBox, KeyInputHdl)); + m_xWidget->connect_changed(LINK(this, SelectorListBox, SelectHdl)); + m_xWidget->connect_focus_out(LINK(this, SelectorListBox, FocusOutHdl)); + + ::Size aLogicalSize(75, 0); + ::Size aPixelSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont)); + m_xWidget->set_size_request(aPixelSize.Width(), -1); + SetSizePixel(m_xContainer->get_preferred_size()); +} + +void SelectorListBox::dispose() +{ + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +SelectorListBox::~SelectorListBox() +{ + disposeOnce(); +} + +static void lcl_addObjectsToList( const ObjectHierarchy& rHierarchy, const ObjectIdentifier & rParent, std::vector< ListBoxEntryData >& rEntries + , const sal_Int32 nHierarchyDepth, const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + ObjectHierarchy::tChildContainer aChildren( rHierarchy.getChildren(rParent) ); + for (auto const& child : aChildren) + { + ListBoxEntryData aEntry; + aEntry.OID = child; + aEntry.UIName = ObjectNameProvider::getNameForCID( child.getObjectCID(), xChartDoc ); + aEntry.nHierarchyDepth = nHierarchyDepth; + rEntries.push_back(aEntry); + lcl_addObjectsToList( rHierarchy, child, rEntries, nHierarchyDepth+1, xChartDoc ); + } +} + +void SelectorListBox::SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController ) +{ + m_xChartController = xChartController.get(); +} + +void SelectorListBox::UpdateChartElementsListAndSelection() +{ + m_xWidget->clear(); + m_aEntries.clear(); + + rtl::Reference< ::chart::ChartController > xChartController = m_xChartController.get(); + if( xChartController.is() ) + { + ObjectIdentifier aSelectedOID( xChartController->getSelection() ); + OUString aSelectedCID = aSelectedOID.getObjectCID(); + + rtl::Reference<::chart::ChartModel> xChartDoc = xChartController->getChartModel(); + ObjectType eType( aSelectedOID.getObjectType() ); + bool bAddSelectionToList = false; + if ( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL || eType == OBJECTTYPE_SHAPE ) + bAddSelectionToList = true; + + Reference< uno::XInterface > xChartView; + rtl::Reference< ChartModel > xFact = xChartController->getChartModel(); + if( xFact.is() ) + xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME ); + ExplicitValueProvider* pExplicitValueProvider = nullptr; //ExplicitValueProvider::getExplicitValueProvider(xChartView); this creates all visible data points, that's too much + ObjectHierarchy aHierarchy( xChartDoc, pExplicitValueProvider, true /*bFlattenDiagram*/, true /*bOrderingForElementSelector*/ ); + lcl_addObjectsToList( aHierarchy, ::chart::ObjectHierarchy::getRootNodeOID(), m_aEntries, 0, xChartDoc ); + + if( bAddSelectionToList ) + { + if ( aSelectedOID.isAutoGeneratedObject() ) + { + OUString aSeriesCID = ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::getSeriesParticleFromCID( aSelectedCID ) ); + std::vector< ListBoxEntryData >::iterator aIt = std::find_if(m_aEntries.begin(), m_aEntries.end(), + [&aSeriesCID](const ListBoxEntryData& rEntry) { return rEntry.OID.getObjectCID().match(aSeriesCID); }); + if (aIt != m_aEntries.end()) + { + ListBoxEntryData aEntry; + aEntry.UIName = ObjectNameProvider::getNameForCID( aSelectedCID, xChartDoc ); + aEntry.OID = aSelectedOID; + ++aIt; + if( aIt != m_aEntries.end() ) + m_aEntries.insert(aIt, aEntry); + else + m_aEntries.push_back( aEntry ); + } + } + else if ( aSelectedOID.isAdditionalShape() ) + { + ListBoxEntryData aEntry; + SdrObject* pSelectedObj = DrawViewWrapper::getSdrObject( aSelectedOID.getAdditionalShape() ); + OUString aName = pSelectedObj ? pSelectedObj->GetName() : OUString(); + aEntry.UIName = ( aName.isEmpty() ? SchResId( STR_OBJECT_SHAPE ) : aName ); + aEntry.OID = aSelectedOID; + m_aEntries.push_back( aEntry ); + } + } + + m_xWidget->freeze(); + sal_uInt16 nEntryPosToSelect = 0; bool bSelectionFound = false; + sal_uInt16 nN=0; + for (auto const& entry : m_aEntries) + { + // tdf#152087 strip any newlines from the entry + m_xWidget->append_text(entry.UIName.replaceAll("\n", " ")); + if ( !bSelectionFound && aSelectedOID == entry.OID ) + { + nEntryPosToSelect = nN; + bSelectionFound = true; + } + ++nN; + } + m_xWidget->thaw(); + + if( bSelectionFound ) + m_xWidget->set_active(nEntryPosToSelect); + } + m_xWidget->save_value(); //remind current selection pos +} + +void SelectorListBox::ReleaseFocus_Impl() +{ + if ( !m_bReleaseFocus ) + { + m_bReleaseFocus = true; + return; + } + + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + Reference< frame::XFrame > xFrame( xController->getFrame() ); + if ( xFrame.is() && xFrame->getContainerWindow().is() ) + xFrame->getContainerWindow()->setFocus(); +} + +IMPL_LINK(SelectorListBox, SelectHdl, weld::ComboBox&, rComboBox, void) +{ + if (rComboBox.changed_by_direct_pick()) + { + const sal_Int32 nPos = rComboBox.get_active(); + if (o3tl::make_unsigned(nPos) < m_aEntries.size()) + { + ObjectIdentifier aOID = m_aEntries[nPos].OID; + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + if( xController.is() ) + xController->select( aOID.getAny() ); + } + ReleaseFocus_Impl(); + } +} + +IMPL_LINK(SelectorListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch ( nCode ) + { + case KEY_RETURN: + case KEY_TAB: + { + if ( nCode == KEY_TAB ) + m_bReleaseFocus = false; + else + bHandled = true; + SelectHdl(*m_xWidget); + break; + } + + case KEY_ESCAPE: + m_xWidget->set_active_text(m_xWidget->get_saved_value()); //restore saved selection + ReleaseFocus_Impl(); + break; + } + + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(SelectorListBox, FocusOutHdl, weld::Widget&, void) +{ + if (m_xWidget && !m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus + m_xWidget->set_active_text(m_xWidget->get_saved_value()); +} + +OUString SAL_CALL ElementSelectorToolbarController::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL ElementSelectorToolbarController::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ElementSelectorToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} +ElementSelectorToolbarController::ElementSelectorToolbarController() +{ +} +ElementSelectorToolbarController::~ElementSelectorToolbarController() +{ +} +// XInterface +Any SAL_CALL ElementSelectorToolbarController::queryInterface( const Type& _rType ) +{ + Any aReturn = ToolboxController::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ElementSelectorToolbarController_BASE::queryInterface(_rType); + return aReturn; +} +void SAL_CALL ElementSelectorToolbarController::acquire() noexcept +{ + ToolboxController::acquire(); +} +void SAL_CALL ElementSelectorToolbarController::release() noexcept +{ + ToolboxController::release(); +} +void SAL_CALL ElementSelectorToolbarController::statusChanged( const frame::FeatureStateEvent& rEvent ) +{ + if( m_apSelectorListBox ) + { + SolarMutexGuard aSolarMutexGuard; + if ( rEvent.FeatureURL.Path == "ChartElementSelector" ) + { + Reference< frame::XController > xChartController; + rEvent.State >>= xChartController; + ::chart::ChartController* pController = dynamic_cast<::chart::ChartController*>(xChartController.get()); + assert(!xChartController || pController); + m_apSelectorListBox->SetChartController( pController ); + m_apSelectorListBox->UpdateChartElementsListAndSelection(); + } + } +} +uno::Reference< awt::XWindow > SAL_CALL ElementSelectorToolbarController::createItemWindow( const uno::Reference< awt::XWindow >& xParent ) +{ + uno::Reference< awt::XWindow > xItemWindow; + if( !m_apSelectorListBox ) + { + VclPtr pParent = VCLUnoHelper::GetWindow( xParent ); + if( pParent ) + { + m_apSelectorListBox.reset(VclPtr::Create(pParent)); + } + } + if( m_apSelectorListBox ) + xItemWindow = VCLUnoHelper::GetInterface( m_apSelectorListBox.get() ); + return xItemWindow; +} + +} // chart2 + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ElementSelectorToolbarController_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::ElementSelectorToolbarController ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ElementSelector.hxx b/chart2/source/controller/main/ElementSelector.hxx new file mode 100644 index 000000000..fb1e4e052 --- /dev/null +++ b/chart2/source/controller/main/ElementSelector.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace chart +{ +class ChartController; + +struct ListBoxEntryData +{ + OUString UIName; + ObjectIdentifier OID; + sal_Int32 nHierarchyDepth; + + ListBoxEntryData() : nHierarchyDepth(0) + { + } +}; + +class SelectorListBox final : public InterimItemWindow +{ +public: + SelectorListBox(vcl::Window* pParent); + virtual void dispose() override; + virtual ~SelectorListBox() override; + + void ReleaseFocus_Impl(); + + void SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController ); + void UpdateChartElementsListAndSelection(); + +private: + unotools::WeakReference<::chart::ChartController> m_xChartController; + std::unique_ptr m_xWidget; + + std::vector m_aEntries; + + bool m_bReleaseFocus; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); +}; + +typedef ::cppu::ImplHelper1 < css::lang::XServiceInfo> ElementSelectorToolbarController_BASE; + +class ElementSelectorToolbarController : public ::svt::ToolboxController + , public ElementSelectorToolbarController_BASE +{ +public: + explicit ElementSelectorToolbarController(); + virtual ~ElementSelectorToolbarController() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XStatusListener + virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override; + // XToolbarController + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createItemWindow( const css::uno::Reference< css::awt::XWindow >& Parent ) override; + +private: + VclPtr< SelectorListBox > m_apSelectorListBox; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.cxx b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx new file mode 100644 index 000000000..90dcf77b2 --- /dev/null +++ b/chart2/source/controller/main/FeatureCommandDispatchBase.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "FeatureCommandDispatchBase.hxx" + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +FeatureCommandDispatchBase::FeatureCommandDispatchBase( const Reference< uno::XComponentContext >& rxContext ) + :CommandDispatch( rxContext ) + ,m_nFeatureId( 0 ) +{ +} + +FeatureCommandDispatchBase::~FeatureCommandDispatchBase() +{ +} + +void FeatureCommandDispatchBase::initialize() +{ + CommandDispatch::initialize(); + describeSupportedFeatures(); +} + +bool FeatureCommandDispatchBase::isFeatureSupported( const OUString& rCommandURL ) +{ + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommandURL ); + return aIter != m_aSupportedFeatures.end(); +} + +void FeatureCommandDispatchBase::fireStatusEvent( const OUString& rURL, + const Reference< frame::XStatusListener >& xSingleListener /* = 0 */ ) +{ + if ( rURL.isEmpty() ) + { + for (auto const& elem : m_aSupportedFeatures) + { + FeatureState aFeatureState( getState(elem.first) ); + fireStatusEventForURL( elem.first, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener ); + } + } + else + { + FeatureState aFeatureState( getState( rURL ) ); + fireStatusEventForURL( rURL, aFeatureState.aState, aFeatureState.bEnabled, xSingleListener ); + } +} + +// XDispatch +void FeatureCommandDispatchBase::dispatch( const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + OUString aCommand( URL.Complete ); + if ( getState( aCommand ).bEnabled ) + { + execute( aCommand, Arguments ); + } +} + +void FeatureCommandDispatchBase::implDescribeSupportedFeature( const char* pAsciiCommandURL, + sal_uInt16 nId, sal_Int16 nGroup ) +{ + ControllerFeature aFeature; + aFeature.Command = OUString::createFromAscii( pAsciiCommandURL ); + aFeature.nFeatureId = nId; + aFeature.GroupId = nGroup; + + m_aSupportedFeatures[ aFeature.Command ] = aFeature; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/FeatureCommandDispatchBase.hxx b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx new file mode 100644 index 000000000..0c291a684 --- /dev/null +++ b/chart2/source/controller/main/FeatureCommandDispatchBase.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "CommandDispatch.hxx" + +#include + +namespace chart +{ + +struct ControllerFeature: public css::frame::DispatchInformation +{ + sal_uInt16 nFeatureId; +}; + +typedef std::map< OUString, + ControllerFeature > SupportedFeatures; + +struct FeatureState +{ + bool bEnabled; + css::uno::Any aState; + + FeatureState() : bEnabled( false ) { } +}; + +/** This is a base class for CommandDispatch implementations with feature support. + */ +class FeatureCommandDispatchBase: public CommandDispatch +{ +public: + explicit FeatureCommandDispatchBase( const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~FeatureCommandDispatchBase() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + + virtual bool isFeatureSupported( const OUString& rCommandURL ); + +protected: + // XDispatch + virtual void SAL_CALL dispatch( const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + virtual void fireStatusEvent( const OUString& rURL, + const css::uno::Reference< css::frame::XStatusListener >& xSingleListener ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) = 0; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) = 0; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() = 0; + + /** describes a feature supported by the controller + + Must not be called outside describeSupportedFeatures. + + @param pAsciiCommandURL + the URL of the feature command + @param nId + the id of the feature. Later references to this feature usually happen by id, not by + URL. + @param nGroup + the command group of the feature. This is important for configuring the controller UI + by the user, see also CommandGroup. + */ + void implDescribeSupportedFeature( const char* pAsciiCommandURL, sal_uInt16 nId, + sal_Int16 nGroup ); + + mutable SupportedFeatures m_aSupportedFeatures; + + sal_uInt16 m_nFeatureId; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ObjectHierarchy.cxx b/chart2/source/controller/main/ObjectHierarchy.cxx new file mode 100644 index 000000000..5a04b7ae4 --- /dev/null +++ b/chart2/source/controller/main/ObjectHierarchy.cxx @@ -0,0 +1,718 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +void lcl_getChildOIDs( + ::chart::ObjectHierarchy::tChildContainer& rOutChildren, + const Reference< container::XIndexAccess >& xShapes ) +{ + if( !xShapes.is()) + return; + + sal_Int32 nCount = xShapes->getCount(); + for( sal_Int32 i=0; i xShapeProp( xShapes->getByIndex( i ), uno::UNO_QUERY ); + if( xShapeProp.is()) + { + Reference< beans::XPropertySetInfo > xInfo( xShapeProp->getPropertySetInfo()); + OUString aName; + if( xInfo.is() && + xInfo->hasPropertyByName( "Name") && + (xShapeProp->getPropertyValue( "Name") >>= aName ) && + !aName.isEmpty() && + ::chart::ObjectIdentifier::isCID( aName )) + { + rOutChildren.emplace_back( aName ); + } + Reference< container::XIndexAccess > xNewShapes( xShapeProp, uno::UNO_QUERY ); + if( xNewShapes.is()) + lcl_getChildOIDs( rOutChildren, xNewShapes ); + } + } +} + +void lcl_addAxisTitle( const rtl::Reference< ::chart::Axis >& xAxis, ::chart::ObjectHierarchy::tChildContainer& rContainer, const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( xAxis.is()) + { + Reference< XTitle > xAxisTitle( xAxis->getTitleObject()); + if( xAxisTitle.is()) + rContainer.emplace_back( ::chart::ObjectIdentifier::createClassifiedIdentifierForObject( xAxisTitle, xChartModel ) ); + } +} + +} // anonymous namespace + +namespace chart +{ + +void ObjectHierarchy::createTree( const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + m_aChildMap = tChildMap();//clear tree + + if( !xChartDocument.is() ) + return; + + //@todo: change ObjectIdentifier to take an XChartDocument rather than XModel + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDocument ); + ObjectIdentifier aDiaOID; + if( xDiagram.is() ) + aDiaOID = ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( static_cast(xDiagram.get()), xChartDocument ) ); + ObjectHierarchy::tChildContainer aTopLevelContainer; + + // First Level + + // Chart Area + if( m_bOrderingForElementSelector ) + { + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); + if( xDiagram.is() ) + { + aTopLevelContainer.push_back( aDiaOID ); + createWallAndFloor( aTopLevelContainer, xDiagram ); + createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); + } + } + + // Main Title + Reference< XTitle > xMainTitle( xChartDocument->getTitleObject()); + if( xMainTitle.is()) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xMainTitle, xChartDocument ) ); + + if( xDiagram.is()) + { + // Sub Title. Note: This is interpreted of being top level + Reference< XTitle > xSubTitle( xDiagram->getTitleObject()); + if( xSubTitle.is()) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xSubTitle, xChartDocument ) ); + + if( !m_bOrderingForElementSelector ) + { + // Axis Titles. Note: These are interpreted of being top level + const std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aAxes ) + lcl_addAxisTitle( axis, aTopLevelContainer, xChartDocument ); + + // Diagram + aTopLevelContainer.push_back( aDiaOID ); + } + + if( m_bFlattenDiagram ) + createDiagramTree( aTopLevelContainer, xChartDocument, xDiagram ); + else + { + ObjectHierarchy::tChildContainer aSubContainer; + createDiagramTree( aSubContainer, xChartDocument, xDiagram ); + if( !aSubContainer.empty() ) + m_aChildMap[ aDiaOID ] = aSubContainer; + } + + if( !m_bOrderingForElementSelector ) + createLegendTree( aTopLevelContainer, xChartDocument, xDiagram ); + } + + // #i12587# support for shapes in chart + if ( !m_bOrderingForElementSelector ) + { + createAdditionalShapesTree( aTopLevelContainer ); + } + + // Chart Area + if( !m_bOrderingForElementSelector ) + aTopLevelContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); + + if( ! aTopLevelContainer.empty()) + m_aChildMap[ ObjectHierarchy::getRootNodeOID() ] = aTopLevelContainer; +} + +void ObjectHierarchy::createLegendTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + if( !(xDiagram.is() && LegendHelper::hasLegend( xDiagram )) ) + return; + + ObjectIdentifier aLegendOID( ObjectIdentifier( ObjectIdentifier::createClassifiedIdentifierForObject( xDiagram->getLegend(), xChartDoc ) ) ); + rContainer.push_back( aLegendOID ); + + // iterate over child shapes of legend and search for matching CIDs + if( m_pExplicitValueProvider ) + { + rtl::Reference< SvxShapeGroupAnyD > xLegendShapeContainer = + dynamic_cast( + m_pExplicitValueProvider->getShapeForCID( aLegendOID.getObjectCID() ).get() ); + ObjectHierarchy::tChildContainer aLegendEntryOIDs; + lcl_getChildOIDs( aLegendEntryOIDs, xLegendShapeContainer ); + + m_aChildMap[ aLegendOID ] = aLegendEntryOIDs; + } +} + +void ObjectHierarchy::createAxesTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + bool bSupportsAxesGrids = ChartTypeHelper::isSupportingMainAxis( xChartType, nDimensionCount, 0 ); + if( !bSupportsAxesGrids ) + return; + + std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram, /* bOnlyVisible = */ true ); + if( !m_bOrderingForElementSelector ) + { + for (const auto & rAxis : std::as_const(aAxes)) + rContainer.push_back( ObjectIdentifier::createClassifiedIdentifierForObject( rAxis, xChartDoc ) ); + } + + // get all axes, also invisible ones + aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + // Grids + for( rtl::Reference< Axis > const & xAxis : aAxes ) + { + if(!xAxis.is()) + continue; + + sal_Int32 nCooSysIndex = 0; + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ); + if( nAxisIndex>0 && !ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimensionCount ) ) + continue; + + if( m_bOrderingForElementSelector ) + { + // axis + if( AxisHelper::isAxisVisible( xAxis ) ) + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForObject( xAxis, xChartDoc ) ); + + // axis title + lcl_addAxisTitle( xAxis, rContainer, xChartDoc ); + } + + Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); + if( AxisHelper::isGridVisible( xGridProperties ) ) + { + //main grid + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc ) ); + } + + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + sal_Int32 nSubGrid = 0; + for( nSubGrid = 0; nSubGrid < aSubGrids.getLength(); ++nSubGrid ) + { + Reference< beans::XPropertySet > xSubGridProperties( aSubGrids[nSubGrid] ); + if( AxisHelper::isGridVisible( xSubGridProperties ) ) + { + //sub grid + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForGrid( xAxis, xChartDoc, nSubGrid ) ); + } + } + } +} + +void ObjectHierarchy::createWallAndFloor( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference< Diagram > & xDiagram ) +{ + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + bool bIsThreeD = ( nDimensionCount == 3 ); + bool bHasWall = DiagramHelper::isSupportingFloorAndWall( xDiagram ); + if( bHasWall && bIsThreeD ) + { + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) ); + + Reference< beans::XPropertySet > xFloor( xDiagram->getFloor()); + if( xFloor.is()) + rContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, u"" ) ); + } + +} + +void ObjectHierarchy::createDiagramTree( + ObjectHierarchy::tChildContainer & rContainer, + const rtl::Reference<::chart::ChartModel> & xChartDoc, + const rtl::Reference< Diagram > & xDiagram ) +{ + if( !m_bOrderingForElementSelector ) + { + createDataSeriesTree( rContainer, xDiagram ); + createAxesTree( rContainer, xChartDoc, xDiagram ); + createWallAndFloor( rContainer, xDiagram ); + } + else + { + createAxesTree( rContainer, xChartDoc, xDiagram ); + createDataSeriesTree( rContainer, xDiagram ); + } +} + +void ObjectHierarchy::createDataSeriesTree( + ObjectHierarchy::tChildContainer & rOutDiagramSubContainer, + const rtl::Reference< Diagram > & xDiagram ) +{ + try + { + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + for( std::size_t nCooSysIdx=0; nCooSysIdx > aChartTypeSeq( aCooSysSeq[nCooSysIdx]->getChartTypes2()); + for( std::size_t nCTIdx=0; nCTIdx xChartType( aChartTypeSeq[nCTIdx] ); + std::vector< rtl::Reference< DataSeries > > aSeriesSeq( xChartType->getDataSeries2() ); + const sal_Int32 nNumberOfSeries = + ChartTypeHelper::getNumberOfDisplayedSeries( xChartType, aSeriesSeq.size()); + + for( sal_Int32 nSeriesIdx=0; nSeriesIdx const & xSeries = aSeriesSeq[nSeriesIdx]; + + // data labels + if( DataSeriesHelper::hasDataLabelsAtSeries( xSeries ) ) + { + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierForParticles( aSeriesParticle, aChildParticle ) ); + } + + // Statistics + if( ChartTypeHelper::isSupportingStatisticProperties( xChartType, nDimensionCount ) ) + { + Sequence< Reference< chart2::XRegressionCurve > > aCurves( xSeries->getRegressionCurves()); + for( sal_Int32 nCurveIdx=0; nCurveIdx xErrorBarProp; + if( (xSeries->getPropertyValue( CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp) && + xErrorBarProp.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + ( nStyle != css::chart::ErrorBarStyle::NONE ) ) + { + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_ERRORS_Y, u"", aSeriesParticle ) ); + } + } + + if( (xSeries->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp) && + xErrorBarProp.is()) + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + ( nStyle != css::chart::ErrorBarStyle::NONE ) ) + { + aSeriesSubContainer.emplace_back( ObjectIdentifier::createClassifiedIdentifierWithParent( + OBJECTTYPE_DATA_ERRORS_X, u"", aSeriesParticle ) ); + } + } + } + + // Data Points + // iterate over child shapes of legend and search for matching CIDs + if( m_pExplicitValueProvider ) + { + rtl::Reference< SvxShapeGroupAnyD > xSeriesShapeContainer = + dynamic_cast( + m_pExplicitValueProvider->getShapeForCID( aSeriesOID.getObjectCID() ).get() ); + lcl_getChildOIDs( aSeriesSubContainer, xSeriesShapeContainer ); + } + + if( ! aSeriesSubContainer.empty()) + m_aChildMap[ aSeriesOID ] = aSeriesSubContainer; + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ObjectHierarchy::createAdditionalShapesTree( ObjectHierarchy::tChildContainer& rContainer ) +{ + try + { + if ( m_pExplicitValueProvider ) + { + rtl::Reference xDrawPage( m_pExplicitValueProvider->getDrawModelWrapper()->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + rContainer.emplace_back( xShape ); + } + } + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool ObjectHierarchy::hasChildren( const ObjectIdentifier& rParent ) const +{ + if ( rParent.isValid() ) + { + tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); + if( aIt != m_aChildMap.end()) + return ! (aIt->second.empty()); + } + return false; +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getChildren( const ObjectIdentifier& rParent ) const +{ + if ( rParent.isValid() ) + { + tChildMap::const_iterator aIt( m_aChildMap.find( rParent )); + if( aIt != m_aChildMap.end()) + return aIt->second; + } + static const ObjectHierarchy::tChildContainer EMPTY; + return EMPTY; +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getSiblings( const ObjectIdentifier& rNode ) const +{ + if ( rNode.isValid() && !ObjectHierarchy::isRootNode( rNode ) ) + { + for (auto const& child : m_aChildMap) + { + ObjectHierarchy::tChildContainer::const_iterator aElemIt( + std::find( child.second.begin(), child.second.end(), rNode )); + if( aElemIt != child.second.end()) + return child.second; + } + } + static const ObjectHierarchy::tChildContainer EMPTY; + return EMPTY; +} + +ObjectIdentifier ObjectHierarchy::getParentImpl( + const ObjectIdentifier & rParentOID, + const ObjectIdentifier & rOID ) const +{ + // search children + ObjectHierarchy::tChildContainer aChildren( getChildren( rParentOID )); + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aChildren.begin(), aChildren.end(), rOID )); + // recursion end + if( aIt != aChildren.end()) + return rParentOID; + + for (auto const& child : aChildren) + { + // recursion + ObjectIdentifier aTempParent( getParentImpl( child, rOID )); + if ( aTempParent.isValid() ) + { + // exit on success + return aTempParent; + } + } + + // exit on fail + return ObjectIdentifier(); +} + +ObjectIdentifier ObjectHierarchy::getParent( + const ObjectIdentifier & rOID ) const +{ + return getParentImpl( ObjectHierarchy::getRootNodeOID(), rOID ); +} + +ObjectHierarchy::ObjectHierarchy( + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider /* = 0 */, + bool bFlattenDiagram /* = false */, + bool bOrderingForElementSelector /* = false */) : + m_pExplicitValueProvider( pExplicitValueProvider ), + m_bFlattenDiagram( bFlattenDiagram ), + m_bOrderingForElementSelector( bOrderingForElementSelector ) +{ + createTree( xChartDocument ); + // don't remember this helper to avoid access after lifetime + m_pExplicitValueProvider = nullptr; +} + +ObjectHierarchy::~ObjectHierarchy() +{} + +ObjectIdentifier ObjectHierarchy::getRootNodeOID() +{ + return ObjectIdentifier( "ROOT" ); +} + +bool ObjectHierarchy::isRootNode( const ObjectIdentifier& rOID ) +{ + return ( rOID == ObjectHierarchy::getRootNodeOID() ); +} + +const ObjectHierarchy::tChildContainer & ObjectHierarchy::getTopLevelChildren() const +{ + return getChildren( ObjectHierarchy::getRootNodeOID()); +} + +sal_Int32 ObjectHierarchy::getIndexInParent( + const ObjectIdentifier& rNode ) const +{ + ObjectIdentifier aParentOID( getParent( rNode )); + const tChildContainer & aChildren( getChildren( aParentOID ) ); + sal_Int32 nIndex = 0; + for (auto const& child : aChildren) + { + if ( child == rNode ) + return nIndex; + ++nIndex; + } + return -1; +} + +ObjectKeyNavigation::ObjectKeyNavigation( + const ObjectIdentifier & rCurrentOID, + const rtl::Reference<::chart::ChartModel> & xChartDocument, + ExplicitValueProvider * pExplicitValueProvider /* = 0 */ ) : + m_aCurrentOID( rCurrentOID ), + m_xChartDocument( xChartDocument ), + m_pExplicitValueProvider( pExplicitValueProvider ) +{ + if ( !m_aCurrentOID.isValid() ) + { + setCurrentSelection( ObjectHierarchy::getRootNodeOID() ); + } +} + +bool ObjectKeyNavigation::handleKeyEvent( + const awt::KeyEvent & rEvent ) +{ + bool bResult = false; + + switch( rEvent.KeyCode ) + { + case awt::Key::TAB: + if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) + bResult = previous(); + else + bResult = next(); + break; + case awt::Key::HOME: + bResult = first(); + break; + case awt::Key::END: + bResult = last(); + break; + case awt::Key::F3: + if( rEvent.Modifiers & awt::KeyModifier::SHIFT ) + bResult = up(); + else + bResult = down(); + break; + case awt::Key::ESCAPE: + setCurrentSelection( ObjectIdentifier() ); + bResult = true; + break; + default: + bResult = false; + break; + } + return bResult; +} + +void ObjectKeyNavigation::setCurrentSelection( const ObjectIdentifier& rOID ) +{ + m_aCurrentOID = rOID; +} + +bool ObjectKeyNavigation::first() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + setCurrentSelection( aSiblings.front()); + else + bResult = veryFirst(); + return bResult; +} + +bool ObjectKeyNavigation::last() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + setCurrentSelection( aSiblings.back()); + else + bResult = veryLast(); + return bResult; +} + +bool ObjectKeyNavigation::next() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection() ) ); + bool bResult = !aSiblings.empty(); + if( bResult ) + { + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); + assert(aIt != aSiblings.end()); + if( ++aIt == aSiblings.end()) + aIt = aSiblings.begin(); + setCurrentSelection( *aIt ); + } + else + bResult = veryFirst(); + + return bResult; +} + +bool ObjectKeyNavigation::previous() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aSiblings( aHierarchy.getSiblings( getCurrentSelection())); + bool bResult = !aSiblings.empty(); + if( bResult ) + { + ObjectHierarchy::tChildContainer::const_iterator aIt( + std::find( aSiblings.begin(), aSiblings.end(), getCurrentSelection())); + OSL_ASSERT( aIt != aSiblings.end()); + if( aIt == aSiblings.begin()) + aIt = aSiblings.end(); + --aIt; + setCurrentSelection( *aIt ); + } + else + bResult = veryLast(); + return bResult; +} + +bool ObjectKeyNavigation::up() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + bool bResult = !ObjectHierarchy::isRootNode( getCurrentSelection()); + if( bResult ) + setCurrentSelection( aHierarchy.getParent( getCurrentSelection())); + return bResult; +} + +bool ObjectKeyNavigation::down() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + bool bResult = aHierarchy.hasChildren( getCurrentSelection()); + if( bResult ) + { + ObjectHierarchy::tChildContainer aChildren = aHierarchy.getChildren( getCurrentSelection()); + OSL_ASSERT( !aChildren.empty()); + setCurrentSelection( aChildren.front()); + } + return bResult; +} + +bool ObjectKeyNavigation::veryFirst() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); + bool bResult = !aChildren.empty(); + if( bResult ) + setCurrentSelection( aChildren.front()); + return bResult; +} + +bool ObjectKeyNavigation::veryLast() +{ + ObjectHierarchy aHierarchy( m_xChartDocument, m_pExplicitValueProvider ); + ObjectHierarchy::tChildContainer aChildren( aHierarchy.getTopLevelChildren()); + bool bResult = !aChildren.empty(); + if( bResult ) + setCurrentSelection( aChildren.back()); + return bResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/PositionAndSizeHelper.cxx b/chart2/source/controller/main/PositionAndSizeHelper.cxx new file mode 100644 index 000000000..ca8a4549a --- /dev/null +++ b/chart2/source/controller/main/PositionAndSizeHelper.cxx @@ -0,0 +1,179 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +bool PositionAndSizeHelper::moveObject( ObjectType eObjectType + , const uno::Reference< beans::XPropertySet >& xObjectProp + , const awt::Rectangle& rNewPositionAndSize + , const awt::Rectangle& rOldPositionAndSize + , const awt::Rectangle& rPageRectangle + ) +{ + if(!xObjectProp.is()) + return false; + tools::Rectangle aObjectRect( Point(rNewPositionAndSize.X,rNewPositionAndSize.Y), Size(rNewPositionAndSize.Width,rNewPositionAndSize.Height) ); + tools::Rectangle aPageRect( Point(rPageRectangle.X,rPageRectangle.Y), Size(rPageRectangle.Width,rPageRectangle.Height) ); + + // every following branch divides by width and height + if (aPageRect.getWidth() == 0 || aPageRect.getHeight() == 0) + return false; + + if( eObjectType==OBJECTTYPE_TITLE ) + { + //@todo decide whether x is primary or secondary + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_CENTER; + //the anchor point at the title object is top/middle + Point aPos = aObjectRect.TopLeft(); + aRelativePosition.Primary = (double(aPos.X())+double(aObjectRect.getWidth())/2.0)/double(aPageRect.getWidth()); + aRelativePosition.Secondary = (double(aPos.Y())+double(aObjectRect.getHeight())/2.0)/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } + else if( eObjectType == OBJECTTYPE_DATA_LABEL ) + { + RelativePosition aAbsolutePosition; + RelativePosition aCustomLabelPosition; + aAbsolutePosition.Primary = double(rOldPositionAndSize.X) / double(aPageRect.getWidth()); + aAbsolutePosition.Secondary = double(rOldPositionAndSize.Y) / double(aPageRect.getHeight()); + + if( xObjectProp->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition ) + { + aAbsolutePosition.Primary -= aCustomLabelPosition.Primary; + aAbsolutePosition.Secondary -= aCustomLabelPosition.Secondary; + } + + //the anchor point at the data label object is top/left + Point aPos = aObjectRect.TopLeft(); + double fRotation = 0.0; + xObjectProp->getPropertyValue("TextRotation") >>= fRotation; + if( fRotation == 90.0 ) + aPos = aObjectRect.BottomLeft(); + else if( fRotation == 270.0 ) + aPos = aObjectRect.TopRight(); + + aCustomLabelPosition.Primary = double(aPos.X()) / double(aPageRect.getWidth()) - aAbsolutePosition.Primary; + aCustomLabelPosition.Secondary = double(aPos.Y()) / double(aPageRect.getHeight()) - aAbsolutePosition.Secondary; + xObjectProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomLabelPosition)); + } + else if( eObjectType==OBJECTTYPE_DATA_CURVE_EQUATION ) + { + //@todo decide whether x is primary or secondary + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_TOP_LEFT; + //the anchor point at the title object is top/middle + Point aPos = aObjectRect.TopLeft(); + aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getWidth()); + aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + } + else if(eObjectType==OBJECTTYPE_LEGEND) + { + xObjectProp->setPropertyValue( "Expansion", uno::Any(css::chart::ChartLegendExpansion_CUSTOM)); + chart2::RelativePosition aRelativePosition; + chart2::RelativeSize aRelativeSize; + Point aAnchor = aObjectRect.TopLeft(); + + aRelativePosition.Primary = + static_cast< double >( aAnchor.X()) / + static_cast< double >( aPageRect.getWidth() ); + aRelativePosition.Secondary = + static_cast< double >( aAnchor.Y()) / + static_cast< double >( aPageRect.getHeight()); + + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + + aRelativeSize.Primary = + static_cast< double >( aObjectRect.getWidth()) / + static_cast< double >( aPageRect.getWidth() ); + if (aRelativeSize.Primary > 1.0) + aRelativeSize.Primary = 1.0; + aRelativeSize.Secondary = + static_cast< double >( aObjectRect.getHeight()) / + static_cast< double >( aPageRect.getHeight()); + if (aRelativeSize.Secondary > 1.0) + aRelativeSize.Secondary = 1.0; + + xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + } + else if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR) + { + //@todo decide whether x is primary or secondary + + //set position: + chart2::RelativePosition aRelativePosition; + aRelativePosition.Anchor = drawing::Alignment_CENTER; + + Point aPos = aObjectRect.Center(); + aRelativePosition.Primary = double(aPos.X())/double(aPageRect.getWidth()); + aRelativePosition.Secondary = double(aPos.Y())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativePosition", uno::Any(aRelativePosition) ); + + //set size: + RelativeSize aRelativeSize; + //the anchor points for the diagram are in the middle of the diagram + //and in the middle of the page + aRelativeSize.Primary = double(aObjectRect.getWidth())/double(aPageRect.getWidth()); + aRelativeSize.Secondary = double(aObjectRect.getHeight())/double(aPageRect.getHeight()); + xObjectProp->setPropertyValue( "RelativeSize", uno::Any(aRelativeSize) ); + } + else + return false; + return true; +} + +bool PositionAndSizeHelper::moveObject( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , const awt::Rectangle& rNewPositionAndSize + , const awt::Rectangle& rOldPositionAndSize + , const awt::Rectangle& rPageRectangle + ) +{ + ControllerLockGuardUNO aLockedControllers( xChartModel ); + + awt::Rectangle aNewPositionAndSize( rNewPositionAndSize ); + + uno::Reference< beans::XPropertySet > xObjectProp = ObjectIdentifier::getObjectPropertySet( rObjectCID, xChartModel ); + ObjectType eObjectType( ObjectIdentifier::getObjectType( rObjectCID ) ); + if(eObjectType==OBJECTTYPE_DIAGRAM || eObjectType==OBJECTTYPE_DIAGRAM_WALL || eObjectType==OBJECTTYPE_DIAGRAM_FLOOR) + { + xObjectProp = ObjectIdentifier::getDiagramForCID( rObjectCID, xChartModel ); + if(!xObjectProp.is()) + return false; + } + return moveObject( eObjectType, xObjectProp, aNewPositionAndSize, rOldPositionAndSize, rPageRectangle ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/SelectionHelper.cxx b/chart2/source/controller/main/SelectionHelper.cxx new file mode 100644 index 000000000..177d7acf5 --- /dev/null +++ b/chart2/source/controller/main/SelectionHelper.cxx @@ -0,0 +1,652 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ + +OUString lcl_getObjectName( SdrObject const * pObj ) +{ + if(pObj) + return pObj->GetName(); + return OUString(); +} + +void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper ) +{ + SolarMutexGuard aSolarGuard; + + if(pObjectToSelect) + { + SelectionHelper aSelectionHelper( pObjectToSelect ); + SdrObject* pMarkObj = aSelectionHelper.getObjectToMark(); + rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper); + rDrawViewWrapper.MarkObject(pMarkObj); + rDrawViewWrapper.setMarkHandleProvider(nullptr); + } +} + +}//anonymous namespace + +bool Selection::hasSelection() const +{ + return m_aSelectedOID.isValid(); +} + +OUString const & Selection::getSelectedCID() const +{ + return m_aSelectedOID.getObjectCID(); +} + +uno::Reference< drawing::XShape > const & Selection::getSelectedAdditionalShape() const +{ + return m_aSelectedOID.getAdditionalShape(); +} + +bool Selection::setSelection( const OUString& rCID ) +{ + if ( rCID != m_aSelectedOID.getObjectCID() ) + { + m_aSelectedOID = ObjectIdentifier( rCID ); + return true; + } + return false; +} + +bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape ) +{ + if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) ) + { + clearSelection(); + m_aSelectedOID = ObjectIdentifier( xShape ); + return true; + } + return false; +} + +void Selection::clearSelection() +{ + m_aSelectedOID = ObjectIdentifier(); + m_aSelectedOID_beforeMouseDown = ObjectIdentifier(); + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); +} + +bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured() +{ + if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() + && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID ) + { + m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing; + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + return true; + } + return false; +} + +void Selection::resetPossibleSelectionAfterSingleClickWasEnsured() +{ + if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() ) + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + } +} + +void Selection::remindSelectionBeforeMouseDown() +{ + m_aSelectedOID_beforeMouseDown = m_aSelectedOID; +} + +bool Selection::isSelectionDifferentFromBeforeMouseDown() const +{ + return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown ); +} + +void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper ) +{ + if( !pDrawViewWrapper ) + return; + + { + SolarMutexGuard aSolarGuard; + pDrawViewWrapper->UnmarkAll(); + } + SdrObject* pObjectToSelect = nullptr; + if ( m_aSelectedOID.isAutoGeneratedObject() ) + { + pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() ); + } + else if( m_aSelectedOID.isAdditionalShape() ) + { + pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() ); + } + + impl_selectObject( pObjectToSelect, *pDrawViewWrapper ); +} + +void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper + , bool bIsRightMouse, bool bWaitingForDoubleClick ) +{ + if( !pDrawViewWrapper ) + return; + + //do not toggle multiclick selection if right clicked on the selected object or waiting for double click + bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick; + + ObjectIdentifier aLastSelectedObject( m_aSelectedOID ); + + SolarMutexGuard aSolarGuard; + + //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point) + + //get object to select: + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + + //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree) + //further we travel along the grouping hierarchy from child to parent + SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos); + m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj + + //ignore handle only objects for hit test + while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) ) + { + pNewObj->SetMarkProtect(true); + pNewObj = pDrawViewWrapper->getHitObject(rMousePos); + m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) ); + } + + //accept only named objects while searching for the object to select + //this call may change m_aSelectedOID + if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) ) + { + //if the so far found object is a multi click object further steps are necessary + while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) ) + { + bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID ); + if( bSameObjectAsLastSelected ) + { + //if the same child is clicked again don't go up further + break; + } + if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) ) + { + //if a sibling of the last selected object is clicked don't go up further + break; + } + ObjectIdentifier aLastChild = m_aSelectedOID; + if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) ) + { + //take the one found so far + break; + } + //if the last selected object is found don't go up further + //but take the last child if selection change is allowed + if ( aLastSelectedObject == m_aSelectedOID ) + { + if( bAllowMultiClickSelectionChange ) + { + m_aSelectedOID = aLastChild; + } + else + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild; + break; + } + } + + OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object"); + } + else + { + //maybe an additional shape was hit + if ( pNewObj ) + { + m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) ); + } + else + { + m_aSelectedOID = ObjectIdentifier(); + } + } + + if ( !m_aSelectedOID.isAdditionalShape() ) + { + OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model + + if ( !m_aSelectedOID.isAutoGeneratedObject() ) + { + m_aSelectedOID = ObjectIdentifier( aPageCID ); + } + + //check whether the diagram was hit but not selected (e.g. because it has no filling): + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + bool bBackGroundHit = m_aSelectedOID.getObjectCID() == aPageCID || m_aSelectedOID.getObjectCID() == aWallCID || !m_aSelectedOID.isAutoGeneratedObject(); + if( bBackGroundHit ) + { + //todo: if more than one diagram is available in future do check the list of all diagrams here + SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID ); + if( pDiagram ) + { + if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) ) + { + m_aSelectedOID = ObjectIdentifier( aDiagramCID ); + } + } + } + //check whether the legend was hit but not selected (e.g. because it has no filling): + if( bBackGroundHit || m_aSelectedOID.getObjectCID() == aDiagramCID ) + { + OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(nullptr) ) );//@todo read CID from model + SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID ); + if( pLegend ) + { + if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) ) + { + m_aSelectedOID = ObjectIdentifier( aLegendCID ); + } + } + } + } + } + + if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() ) + { + m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier(); + } +} + +bool Selection::isResizeableObjectSelected() const +{ + ObjectType eObjectType = m_aSelectedOID.getObjectType(); + switch( eObjectType ) + { + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DIAGRAM_WALL: + case OBJECTTYPE_SHAPE: + case OBJECTTYPE_LEGEND: + return true; + default: + return false; + } +} + +bool Selection::isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const +{ + return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel ); +} + +bool Selection::isDragableObjectSelected() const +{ + return m_aSelectedOID.isDragableObject(); +} + +bool Selection::isAdditionalShapeSelected() const +{ + return m_aSelectedOID.isAdditionalShape(); +} + +bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject + , OUString& rOutName + , bool bGivenObjectMayBeResult ) +{ + SolarMutexGuard aSolarGuard; + //find the deepest named group + SdrObject* pObj = pInOutObject; + OUString aName; + if( bGivenObjectMayBeResult ) + aName = lcl_getObjectName( pObj ); + + while( pObj && !ObjectIdentifier::isCID( aName ) ) + { + SdrObjList* pObjList = pObj->getParentSdrObjListFromSdrObject(); + if( !pObjList ) + return false; + SdrObject* pOwner = pObjList->getSdrObjectFromSdrObjList(); + if( !pOwner ) + return false; + pObj = pOwner; + aName = lcl_getObjectName( pObj ); + } + + if(!pObj) + return false; + if(aName.isEmpty()) + return false; + + pInOutObject = pObj; + rOutName = aName; + return true; +} + +bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject + , ObjectIdentifier& rOutObject + , bool bGivenObjectMayBeResult ) +{ + OUString aName; + if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) ) + { + rOutObject = ObjectIdentifier( aName ); + return true; + } + return false; +} + +bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos + , const OUString& rNameOfSelectedObject + , const DrawViewWrapper& rDrawViewWrapper ) +{ + if(rNameOfSelectedObject.isEmpty()) + return false; + if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) ) + return false; + SolarMutexGuard aSolarGuard; + SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject ); + return DrawViewWrapper::IsObjectHit( pObj, rMPos ); +} + +OUString SelectionHelper::getHitObjectCID( + const Point& rMPos, + DrawViewWrapper const & rDrawViewWrapper, + bool bGetDiagramInsteadOf_Wall ) +{ + SolarMutexGuard aSolarGuard; + OUString aRet; + + SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos); + aRet = lcl_getObjectName( pNewObj );//name of pNewObj + + //ignore handle only objects for hit test + while( pNewObj && aRet.match("HandlesOnly") ) + { + pNewObj->SetMarkProtect(true); + pNewObj = rDrawViewWrapper.getHitObject(rMPos); + aRet = lcl_getObjectName( pNewObj ); + } + + //accept only named objects while searching for the object to select + if( !findNamedParent( pNewObj, aRet, true ) ) + { + aRet.clear(); + } + + OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model + //get page when nothing was hit + if( aRet.isEmpty() && !pNewObj ) + { + aRet = aPageCID; + } + + //get diagram instead wall or page if hit inside diagram + if( !aRet.isEmpty() ) + { + if( aRet == aPageCID ) + { + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + //todo: if more than one diagram is available in future do check the list of all diagrams here + SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID ); + if( pDiagram ) + { + if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) ) + { + aRet = aDiagramCID; + } + } + } + else if( bGetDiagramInsteadOf_Wall ) + { + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + + if( aRet == aWallCID ) + { + OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ); + aRet = aDiagramCID; + } + } + } + + return aRet; + // \\- solar mutex +} + +bool SelectionHelper::isRotateableObject( std::u16string_view rCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + if( !ObjectIdentifier::isRotateableObject( rCID ) ) + return false; + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( ChartModelHelper::findDiagram( xChartModel ) ); + + return nDimensionCount == 3; +} + +SelectionHelper::SelectionHelper( SdrObject* pSelectedObj ) + : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr) +{ + +} +SelectionHelper::~SelectionHelper() +{ +} + +bool SelectionHelper::getFrameDragSingles() +{ + //true == green == surrounding handles + return dynamic_cast( m_pSelectedObj) == nullptr; +} + +SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj ) +{ + if(!pObj) + return nullptr; + OUString aName( lcl_getObjectName( pObj ) ); + if( aName.match("MarkHandles") || aName.match("HandlesOnly") ) + return pObj; + if( !aName.isEmpty() )//don't get the markhandles of a different object + return nullptr; + + //search for a child with name "MarkHandles" or "HandlesOnly" + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + while (aIterator.IsMore()) + { + SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() ); + if( pMarkHandles ) + return pMarkHandles; + } + } + return nullptr; +} + +SdrObject* SelectionHelper::getObjectToMark() +{ + //return the selected object itself + //or a specific other object if that exists + SdrObject* pObj = m_pSelectedObj; + m_pMarkObj = pObj; + + //search for a child with name "MarkHandles" or "HandlesOnly" + if(pObj) + { + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + while (aIterator.IsMore()) + { + SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() ); + if( pMarkHandles ) + { + m_pMarkObj = pMarkHandles; + break; + } + } + } + } + return m_pMarkObj; +} + +E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj ) +{ + //search whether the object or one of its children is a 3D object + //if so, return the accessory 3DScene + + E3dObject* pRotateable = nullptr; + + if(pObj) + { + pRotateable = dynamic_cast(pObj); + if( !pRotateable ) + { + SolarMutexGuard aSolarGuard; + SdrObjList* pSubList = pObj->GetSubList(); + if(pSubList) + { + SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups); + while( aIterator.IsMore() && !pRotateable ) + { + SdrObject* pSubObj = aIterator.Next(); + pRotateable = dynamic_cast(pSubObj); + } + } + } + } + + E3dScene* pScene(nullptr); + + if(pRotateable) + { + SolarMutexGuard aSolarGuard; + pScene = pRotateable->getRootE3dSceneFromE3dObject(); + } + + return pScene; +} + +bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList ) +{ + SolarMutexGuard aSolarGuard; + + //@todo -> more flexible handle creation + //2 scenarios possible: + //1. add an additional invisible shape as a child to the selected object + //this child needs to be named somehow and handles need to be generated there from... + //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape + //.. or 3. feature from drawinglayer to create handles for each shape... (bad performance... ?) ? + + //scenario 1 is now used: + //if a child with name MarkHandles exists + //this child is marked instead of the logical selected object + +/* + //if a special mark object was found + //that object should be used for marking only + if( m_pMarkObj != m_pSelectedObj) + return false; +*/ + //if a special mark object was found + //that object should be used to create handles from + if( m_pMarkObj && m_pMarkObj != m_pSelectedObj) + { + rHdlList.Clear(); + if( auto pPathObj = dynamic_cast( m_pMarkObj) ) + { + //if th object is a polygon + //from each point a handle is generated + const ::basegfx::B2DPolyPolygon& rPolyPolygon = pPathObj->GetPathPoly(); + for( sal_uInt32 nN = 0; nN < rPolyPolygon.count(); nN++) + { + const ::basegfx::B2DPolygon& aPolygon(rPolyPolygon.getB2DPolygon(nN)); + for( sal_uInt32 nM = 0; nM < aPolygon.count(); nM++) + { + const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM)); + rHdlList.AddHdl(std::make_unique(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), SdrHdlKind::Poly)); + } + } + return true; + } + else + return false; //use the special MarkObject for marking + } + + //@todo: + //add and document good marking defaults ... + + rHdlList.Clear(); + + SdrObject* pObj = m_pSelectedObj; + if(!pObj) + return false; + SdrObjList* pSubList = pObj->GetSubList(); + if( !pSubList )//no group object !pObj->IsGroupObject() + return false; + + OUString aName( lcl_getObjectName( pObj ) ); + ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) ); + if( eObjectType == OBJECTTYPE_DATA_POINT + || eObjectType == OBJECTTYPE_DATA_LABEL + || eObjectType == OBJECTTYPE_LEGEND_ENTRY + || eObjectType == OBJECTTYPE_AXIS_UNITLABEL ) + { + return false; + } + + SdrObjListIter aIterator(pSubList, SdrIterMode::Flat); + + while (aIterator.IsMore()) + { + SdrObject* pSubObj = aIterator.Next(); + if( eObjectType == OBJECTTYPE_DATA_SERIES ) + { + OUString aSubName( lcl_getObjectName( pSubObj ) ); + ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) ); + if( eSubObjectType!=OBJECTTYPE_DATA_POINT ) + return false; + } + + Point aPos = pSubObj->GetCurrentBoundRect().Center(); + rHdlList.AddHdl(std::make_unique(aPos,SdrHdlKind::Poly)); + } + return true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ShapeController.cxx b/chart2/source/controller/main/ShapeController.cxx new file mode 100644 index 000000000..3dae73fd8 --- /dev/null +++ b/chart2/source/controller/main/ShapeController.cxx @@ -0,0 +1,671 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ShapeController.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::frame; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +ShapeController::ShapeController( const Reference< uno::XComponentContext >& rxContext, + ChartController* pController ) + :FeatureCommandDispatchBase( rxContext ) + ,m_pChartController( pController ) +{ +} + +ShapeController::~ShapeController() +{ +} + +// WeakComponentImplHelperBase +void ShapeController::disposing() +{ +} + +// XEventListener +void ShapeController::disposing( const lang::EventObject& /* Source */ ) +{ +} + +FeatureState ShapeController::getState( const OUString& rCommand ) +{ + FeatureState aReturn; + aReturn.bEnabled = false; + aReturn.aState <<= false; + + bool bWritable = false; + if ( m_pChartController ) + { + rtl::Reference< ChartModel > xStorable = m_pChartController->getChartModel(); + if ( xStorable.is() ) + { + bWritable = !xStorable->isReadonly(); + } + } + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand ); + if ( aIter != m_aSupportedFeatures.end() ) + { + sal_uInt16 nFeatureId = aIter->second.nFeatureId; + switch ( nFeatureId ) + { + case COMMAND_ID_FORMAT_LINE: + case COMMAND_ID_FORMAT_AREA: + case COMMAND_ID_TEXT_ATTRIBUTES: + case COMMAND_ID_TRANSFORM_DIALOG: + case COMMAND_ID_OBJECT_TITLE_DESCRIPTION: + case COMMAND_ID_RENAME_OBJECT: + { + aReturn.bEnabled = bWritable; + aReturn.aState <<= false; + } + break; + case COMMAND_ID_BRING_TO_FRONT: + case COMMAND_ID_FORWARD: + { + aReturn.bEnabled = ( bWritable && isForwardPossible() ); + aReturn.aState <<= false; + } + break; + case COMMAND_ID_BACKWARD: + case COMMAND_ID_SEND_TO_BACK: + { + + aReturn.bEnabled = ( bWritable && isBackwardPossible() ); + aReturn.aState <<= false; + } + break; + case COMMAND_ID_FONT_DIALOG: + case COMMAND_ID_PARAGRAPH_DIALOG: + { + aReturn.bEnabled = bWritable; + aReturn.aState <<= false; + } + break; + default: + { + aReturn.bEnabled = false; + aReturn.aState <<= false; + } + break; + } + } + + return aReturn; +} + +void ShapeController::execute( const OUString& rCommand, const Sequence< beans::PropertyValue>& ) +{ + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( rCommand ); + if ( aIter == m_aSupportedFeatures.end() ) + return; + + sal_uInt16 nFeatureId = aIter->second.nFeatureId; + switch ( nFeatureId ) + { + case COMMAND_ID_FORMAT_LINE: + { + executeDispatch_FormatLine(); + } + break; + case COMMAND_ID_FORMAT_AREA: + { + executeDispatch_FormatArea(); + } + break; + case COMMAND_ID_TEXT_ATTRIBUTES: + { + executeDispatch_TextAttributes(); + } + break; + case COMMAND_ID_TRANSFORM_DIALOG: + { + executeDispatch_TransformDialog(); + } + break; + case COMMAND_ID_OBJECT_TITLE_DESCRIPTION: + { + executeDispatch_ObjectTitleDescription(); + } + break; + case COMMAND_ID_RENAME_OBJECT: + { + executeDispatch_RenameObject(); + } + break; + case COMMAND_ID_BRING_TO_FRONT: + case COMMAND_ID_FORWARD: + case COMMAND_ID_BACKWARD: + case COMMAND_ID_SEND_TO_BACK: + { + executeDispatch_ChangeZOrder( nFeatureId ); + } + break; + case COMMAND_ID_FONT_DIALOG: + { + executeDispatch_FontDialog(); + } + break; + case COMMAND_ID_PARAGRAPH_DIALOG: + { + executeDispatch_ParagraphDialog(); + } + break; + default: + { + } + break; + } +} + +void ShapeController::describeSupportedFeatures() +{ + implDescribeSupportedFeature( ".uno:FormatLine", COMMAND_ID_FORMAT_LINE, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:FormatArea", COMMAND_ID_FORMAT_AREA, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:TextAttributes", COMMAND_ID_TEXT_ATTRIBUTES, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:TransformDialog", COMMAND_ID_TRANSFORM_DIALOG, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:ObjectTitleDescription", COMMAND_ID_OBJECT_TITLE_DESCRIPTION, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:RenameObject", COMMAND_ID_RENAME_OBJECT, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:BringToFront", COMMAND_ID_BRING_TO_FRONT, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:Forward", COMMAND_ID_FORWARD, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:Backward", COMMAND_ID_BACKWARD, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:SendToBack", COMMAND_ID_SEND_TO_BACK, CommandGroup::FORMAT ); + implDescribeSupportedFeature( ".uno:FontDialog", COMMAND_ID_FONT_DIALOG, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:ParagraphDialog", COMMAND_ID_PARAGRAPH_DIALOG, CommandGroup::EDIT ); +} + +IMPL_LINK( ShapeController, CheckNameHdl, AbstractSvxObjectNameDialog&, rDialog, bool ) +{ + OUString aName; + rDialog.GetName( aName ); + + if ( !aName.isEmpty() ) + { + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( pDrawViewWrapper && pDrawViewWrapper->getNamedSdrObject( aName ) ) + { + return false; + } + } + return true; +} + +void ShapeController::executeDispatch_FormatLine() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateSvxLineTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(), + pSelectedObj, bHasMarked)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_FormatArea() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawModelWrapper && pDrawViewWrapper) ) + return; + + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< AbstractSvxAreaTabDialog > pDlg( + pFact->CreateSvxAreaTabDialog(pChartWindow, &aAttr, &pDrawModelWrapper->getSdrModel(), true, false)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttrToMarked( *pOutAttr, false ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_TextAttributes() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SfxItemSet aAttr( pDrawViewWrapper->GetDefaultAttr() ); + bool bHasMarked = pDrawViewWrapper->AreObjectsMarked(); + if ( bHasMarked ) + { + pDrawViewWrapper->MergeAttrFromMarked( aAttr, false ); + } + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateTextTabDialog(pChartWindow, &aAttr, pDrawViewWrapper)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + if ( bHasMarked ) + { + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } + else + { + pDrawViewWrapper->SetDefaultAttr( *pOutAttr, false ); + } + } +} + +void ShapeController::executeDispatch_TransformDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( pSelectedObj && pSelectedObj->GetObjIdentifier() == SdrObjKind::Caption ) + { + // item set for caption + SfxItemSet aAttr( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aAttr ); + // item set for position and size + SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateCaptionDialog(pChartWindow, pDrawViewWrapper)); + const WhichRangesContainer& pRange = pDlg->GetInputRanges( *aAttr.GetPool() ); + SfxItemSet aCombAttr( *aAttr.GetPool(), pRange ); + aCombAttr.Put( aAttr ); + aCombAttr.Put( aGeoAttr ); + pDlg->SetInputSet( &aCombAttr ); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr ); + } + } + else + { + SfxItemSet aGeoAttr( pDrawViewWrapper->GetGeoAttrFromMarked() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr< SfxAbstractTabDialog > pDlg( + pFact->CreateSvxTransformTabDialog(pChartWindow, &aGeoAttr, pDrawViewWrapper)); + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutAttr = pDlg->GetOutputItemSet(); + pDrawViewWrapper->SetGeoAttrToMarked( *pOutAttr ); + } + } +} + +void ShapeController::executeDispatch_ObjectTitleDescription() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( !pSelectedObj ) + return; + + OUString aTitle( pSelectedObj->GetTitle() ); + OUString aDescription( pSelectedObj->GetDescription() ); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + ScopedVclPtr< AbstractSvxObjectTitleDescDialog > pDlg( + pFact->CreateSvxObjectTitleDescDialog(pChartWindow, aTitle, aDescription)); + if ( pDlg->Execute() == RET_OK ) + { + pDlg->GetTitle( aTitle ); + pDlg->GetDescription( aDescription ); + pSelectedObj->SetTitle( aTitle ); + pSelectedObj->SetDescription( aDescription ); + } +} + +void ShapeController::executeDispatch_RenameObject() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pDrawViewWrapper && pDrawViewWrapper->GetMarkedObjectCount() == 1) ) + return; + + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + if ( !pSelectedObj ) + return; + + OUString aName = pSelectedObj->GetName(); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + ScopedVclPtr< AbstractSvxObjectNameDialog > pDlg( + pFact->CreateSvxObjectNameDialog(pChartWindow, aName)); + pDlg->SetCheckNameHdl( LINK( this, ShapeController, CheckNameHdl ) ); + if ( pDlg->Execute() == RET_OK ) + { + pDlg->GetName(aName); + if (pSelectedObj->GetName() == aName) + { + pSelectedObj->SetName( aName ); + } + } +} + +void ShapeController::executeDispatch_ChangeZOrder( sal_uInt16 nId ) +{ + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = ( m_pChartController ? m_pChartController->GetDrawViewWrapper() : nullptr ); + if ( !pDrawViewWrapper ) + return; + + switch ( nId ) + { + case COMMAND_ID_BRING_TO_FRONT: + { + if ( isForwardPossible() ) + { + pDrawViewWrapper->PutMarkedToTop(); + } + } + break; + case COMMAND_ID_FORWARD: + { + if ( isForwardPossible() ) + { + pDrawViewWrapper->MovMarkedToTop(); + } + } + break; + case COMMAND_ID_BACKWARD: + { + if ( isBackwardPossible() ) + { + pDrawViewWrapper->MovMarkedToBtm(); + } + } + break; + case COMMAND_ID_SEND_TO_BACK: + { + if ( isBackwardPossible() ) + { + SdrObject* pFirstObj = getFirstAdditionalShape(); + pDrawViewWrapper->PutMarkedBehindObj( pFirstObj ); + } + } + break; + default: + { + } + break; + } +} + +void ShapeController::executeDispatch_FontDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawModelWrapper* pDrawModelWrapper = m_pChartController->GetDrawModelWrapper(); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pChartWindow && pDrawModelWrapper && pDrawViewWrapper ) + { + SfxItemSet aAttr( pDrawViewWrapper->GetModel()->GetItemPool() ); + pDrawViewWrapper->GetAttributes( aAttr ); + ViewElementListProvider aViewElementListProvider( pDrawModelWrapper ); + ShapeFontDialog aDlg(pChartWindow, &aAttr, &aViewElementListProvider); + if (aDlg.run() == RET_OK) + { + const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } + } +} + +void ShapeController::executeDispatch_ParagraphDialog() +{ + SolarMutexGuard aGuard; + if ( !m_pChartController ) + return; + + weld::Window* pChartWindow(m_pChartController->GetChartFrame()); + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( !(pChartWindow && pDrawViewWrapper) ) + return; + + SfxItemPool& rPool = pDrawViewWrapper->GetModel()->GetItemPool(); + SfxItemSet aAttr( rPool ); + pDrawViewWrapper->GetAttributes( aAttr ); + + SfxItemSetFixed< + EE_ITEMS_START, EE_ITEMS_END, + SID_ATTR_PARA_PAGEBREAK, SID_ATTR_PARA_WIDOWS> aNewAttr(rPool); + aNewAttr.Put( aAttr ); + aNewAttr.Put( SvxHyphenZoneItem( false, SID_ATTR_PARA_HYPHENZONE ) ); + aNewAttr.Put( SvxFormatBreakItem( SvxBreak::NONE, SID_ATTR_PARA_PAGEBREAK ) ); + aNewAttr.Put( SvxFormatSplitItem( true, SID_ATTR_PARA_SPLIT) ); + aNewAttr.Put( SvxWidowsItem( 0, SID_ATTR_PARA_WIDOWS) ); + aNewAttr.Put( SvxOrphansItem( 0, SID_ATTR_PARA_ORPHANS) ); + + ShapeParagraphDialog aDlg(pChartWindow, &aNewAttr); + if (aDlg.run() == RET_OK) + { + const SfxItemSet* pOutAttr = aDlg.GetOutputItemSet(); + pDrawViewWrapper->SetAttributes( *pOutAttr ); + } +} + +SdrObject* ShapeController::getFirstAdditionalShape() +{ + SdrObject* pFirstObj = nullptr; + + try + { + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + if ( pDrawModelWrapper ) + { + Reference< drawing::XShape > xFirstShape; + rtl::Reference xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + xFirstShape = xShape; + break; + } + } + } + if ( xFirstShape.is() ) + { + pFirstObj = DrawViewWrapper::getSdrObject( xFirstShape ); + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return pFirstObj; +} + +SdrObject* ShapeController::getLastAdditionalShape() +{ + SdrObject* pLastObj = nullptr; + + try + { + DrawModelWrapper* pDrawModelWrapper = ( m_pChartController ? m_pChartController->GetDrawModelWrapper() : nullptr ); + if ( pDrawModelWrapper ) + { + Reference< drawing::XShape > xLastShape; + rtl::Reference xDrawPage( pDrawModelWrapper->getMainDrawPage() ); + Reference< drawing::XShapes > xChartRoot( DrawModelWrapper::getChartRootShape( xDrawPage ) ); + sal_Int32 nCount = xDrawPage->getCount(); + for ( sal_Int32 i = nCount - 1; i >= 0; --i ) + { + Reference< drawing::XShape > xShape; + if ( xDrawPage->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() && xShape != xChartRoot ) + { + xLastShape = xShape; + break; + } + } + } + if ( xLastShape.is() ) + { + pLastObj = DrawViewWrapper::getSdrObject( xLastShape ); + } + } + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return pLastObj; +} + +bool ShapeController::isBackwardPossible() +{ + if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() ) + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pDrawViewWrapper ) + { + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SdrObject* pFirstObj = getFirstAdditionalShape(); + if ( pSelectedObj && pFirstObj && pSelectedObj != pFirstObj ) + { + return true; + } + } + } + return false; +} + +bool ShapeController::isForwardPossible() +{ + if ( m_pChartController && m_pChartController->isAdditionalShapeSelected() ) + { + SolarMutexGuard aGuard; + DrawViewWrapper* pDrawViewWrapper = m_pChartController->GetDrawViewWrapper(); + if ( pDrawViewWrapper ) + { + SdrObject* pSelectedObj = pDrawViewWrapper->getSelectedObject(); + SdrObject* pLastObj = getLastAdditionalShape(); + if ( pSelectedObj && pLastObj && pSelectedObj != pLastObj ) + { + return true; + } + } + } + return false; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ShapeController.hxx b/chart2/source/controller/main/ShapeController.hxx new file mode 100644 index 000000000..3d65c49e5 --- /dev/null +++ b/chart2/source/controller/main/ShapeController.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "FeatureCommandDispatchBase.hxx" +#include + +class AbstractSvxObjectNameDialog; +class SdrObject; + +namespace chart +{ + +class ChartController; + +/** This is a CommandDispatch implementation for shapes. + */ +class ShapeController: public FeatureCommandDispatchBase +{ + friend class ControllerCommandDispatch; + +public: + ShapeController( const css::uno::Reference< css::uno::XComponentContext >& rxContext, ChartController* pController ); + virtual ~ShapeController() override; + +protected: + // WeakComponentImplHelperBase + virtual void SAL_CALL disposing() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // state of a feature + virtual FeatureState getState( const OUString& rCommand ) override; + + // execute a feature + virtual void execute( const OUString& rCommand, const css::uno::Sequence< css::beans::PropertyValue>& rArgs ) override; + + // all the features which should be handled by this class + virtual void describeSupportedFeatures() override; + +private: + DECL_LINK( CheckNameHdl, AbstractSvxObjectNameDialog&, bool); + + void executeDispatch_FormatLine(); + void executeDispatch_FormatArea(); + void executeDispatch_TextAttributes(); + void executeDispatch_TransformDialog(); + void executeDispatch_ObjectTitleDescription(); + void executeDispatch_RenameObject(); + void executeDispatch_ChangeZOrder( sal_uInt16 nId ); + void executeDispatch_FontDialog(); + void executeDispatch_ParagraphDialog(); + + SdrObject* getFirstAdditionalShape(); + SdrObject* getLastAdditionalShape(); + bool isBackwardPossible(); + bool isForwardPossible(); + + ChartController* m_pChartController; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.cxx b/chart2/source/controller/main/StatusBarCommandDispatch.cxx new file mode 100644 index 000000000..440bd9885 --- /dev/null +++ b/chart2/source/controller/main/StatusBarCommandDispatch.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "StatusBarCommandDispatch.hxx" +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +StatusBarCommandDispatch::StatusBarCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel, + const Reference< view::XSelectionSupplier > & xSelSupp ) : + impl::StatusBarCommandDispatch_Base( xContext ), + m_xChartModel( xModel ), + m_xSelectionSupplier( xSelSupp ), + m_bIsModified( false ) +{} + +StatusBarCommandDispatch::~StatusBarCommandDispatch() +{} + +void StatusBarCommandDispatch::initialize() +{ + if( m_xChartModel.is()) + { + m_xChartModel->addModifyListener( this ); + } + + if( m_xSelectionSupplier.is()) + { + m_xSelectionSupplier->addSelectionChangeListener( this ); + } +} + +void StatusBarCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + bool bFireAll( rURL.isEmpty() ); + bool bFireContext( bFireAll || rURL == ".uno:Context" ); + bool bFireModified( bFireAll || rURL == ".uno:ModifiedStatus" ); + + if( bFireContext && m_xChartModel.is()) + { + uno::Any aArg; + aArg <<= ObjectNameProvider::getSelectedObjectText( m_aSelectedOID.getObjectCID(), m_xChartModel ); + fireStatusEventForURL( ".uno:Context", aArg, true, xSingleListener ); + } + if( bFireModified ) + { + uno::Any aArg; + if( m_bIsModified ) + aArg <<= OUString("*"); + fireStatusEventForURL( ".uno:ModifiedStatus", aArg, true, xSingleListener ); + } +} + +// ____ XDispatch ____ +void SAL_CALL StatusBarCommandDispatch::dispatch( + const util::URL& /* URL */, + const Sequence< beans::PropertyValue >& /* Arguments */ ) +{ + // nothing to do here +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL StatusBarCommandDispatch::disposing() +{ + m_xChartModel.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL StatusBarCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xChartModel.clear(); + m_xSelectionSupplier.clear(); +} + +// ____ XModifyListener ____ +void SAL_CALL StatusBarCommandDispatch::modified( const lang::EventObject& aEvent ) +{ + if( m_xChartModel.is()) + m_bIsModified = m_xChartModel->isModified(); + + CommandDispatch::modified( aEvent ); +} + +// ____ XSelectionChangeListener ____ +void SAL_CALL StatusBarCommandDispatch::selectionChanged( const lang::EventObject& /* aEvent */ ) +{ + if( m_xSelectionSupplier.is()) + m_aSelectedOID = ObjectIdentifier( m_xSelectionSupplier->getSelection() ); + else + m_aSelectedOID = ObjectIdentifier(); + fireAllStatusEvents( nullptr ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/StatusBarCommandDispatch.hxx b/chart2/source/controller/main/StatusBarCommandDispatch.hxx new file mode 100644 index 000000000..c123475c0 --- /dev/null +++ b/chart2/source/controller/main/StatusBarCommandDispatch.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "CommandDispatch.hxx" +#include +#include +#include +#include + +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::util { class XModifiable; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ + +/** This is a CommandDispatch implementation for all commands the status bar offers + + This class reads the information needed from the XModel passed here. + */ + +namespace impl +{ +typedef ::cppu::ImplInheritanceHelper< + CommandDispatch, + css::view::XSelectionChangeListener > + StatusBarCommandDispatch_Base; +} + +class StatusBarCommandDispatch : public impl::StatusBarCommandDispatch_Base +{ +public: + explicit StatusBarCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel, + const css::uno::Reference< css::view::XSelectionSupplier > & xSelSupp ); + virtual ~StatusBarCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XModifyListener (override from CommandDispatch) ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + css::uno::Reference< css::view::XSelectionSupplier > m_xSelectionSupplier; + bool m_bIsModified; + ObjectIdentifier m_aSelectedOID; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/ToolbarController.cxx b/chart2/source/controller/main/ToolbarController.cxx new file mode 100644 index 000000000..17df7c7c8 --- /dev/null +++ b/chart2/source/controller/main/ToolbarController.cxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart { + +ChartToolbarController::ChartToolbarController(const css::uno::Sequence& rProperties) +{ + for (const auto& rProperty : rProperties) + { + css::beans::PropertyValue aPropValue; + rProperty >>= aPropValue; + if (aPropValue.Name == "Frame") + { + mxFramesSupplier.set(aPropValue.Value, css::uno::UNO_QUERY); + break; + } + } +} + +ChartToolbarController::~ChartToolbarController() +{ +} + +void ChartToolbarController::execute(sal_Int16 /*nKeyModifier*/) +{ +} + +void ChartToolbarController::click() +{ + css::uno::Reference xActiveFrame = mxFramesSupplier->getActiveFrame(); + if (!xActiveFrame.is()) + return; + + css::uno::Reference xActiveController = xActiveFrame->getController(); + if (!xActiveController.is()) + return; + + css::uno::Reference xDispatch(xActiveController, css::uno::UNO_QUERY); + if (!xDispatch.is()) + return; + + css::util::URL aURL; + aURL.Path = "FormatSelection"; + xDispatch->dispatch(aURL, css::uno::Sequence()); +} + +void ChartToolbarController::doubleClick() +{ + SAL_INFO("chart2", "double clicked"); +} + + +css::uno::Reference ChartToolbarController::createPopupWindow() +{ + return css::uno::Reference(); +} + +css::uno::Reference ChartToolbarController::createItemWindow( + const css::uno::Reference& /*rParent*/) +{ + return css::uno::Reference(); +} + +void ChartToolbarController::statusChanged(const css::frame::FeatureStateEvent& /*rEvent*/) +{ + +} + +void ChartToolbarController::disposing(const css::lang::EventObject& /*rSource*/) +{ +} + +void ChartToolbarController::initialize(const css::uno::Sequence& /*rAny*/) +{ +} + +void ChartToolbarController::update() +{ +} + + +OUString ChartToolbarController::getImplementationName() +{ + return "org.libreoffice.chart2.Chart2ToolboxController"; +} + +sal_Bool ChartToolbarController::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence ChartToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_chart2_Chart2ToolboxController(css::uno::XComponentContext*, css::uno::Sequence const & rProperties) +{ + return cppu::acquire(new ::chart::ChartToolbarController(rProperties)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoActions.cxx b/chart2/source/controller/main/UndoActions.cxx new file mode 100644 index 000000000..6d043137d --- /dev/null +++ b/chart2/source/controller/main/UndoActions.cxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "UndoActions.hxx" +#include "ChartModelClone.hxx" +#include + +#include + +#include + +#include + +using namespace ::com::sun::star; + +namespace chart::impl +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::lang::DisposedException; + +UndoElement::UndoElement( const OUString& i_actionString, const rtl::Reference<::chart::ChartModel>& i_documentModel, const std::shared_ptr< ChartModelClone >& i_modelClone ) + :m_sActionString( i_actionString ) + ,m_xDocumentModel( i_documentModel ) + ,m_pModelClone( i_modelClone ) +{ +} + +UndoElement::~UndoElement() +{ +} + +void UndoElement::disposing(std::unique_lock&) +{ + if ( m_pModelClone ) + m_pModelClone->dispose(); + m_pModelClone.reset(); + m_xDocumentModel.clear(); +} + +OUString SAL_CALL UndoElement::getTitle() +{ + return m_sActionString; +} + +void UndoElement::impl_toggleModelState() +{ + // get a snapshot of the current state of our model + auto pNewClone = std::make_shared( m_xDocumentModel, m_pModelClone->getFacet() ); + // apply the previous snapshot to our model + m_pModelClone->applyToModel( m_xDocumentModel ); + // remember the new snapshot, for the next toggle + m_pModelClone = pNewClone; +} + +void SAL_CALL UndoElement::undo( ) +{ + impl_toggleModelState(); +} + +void SAL_CALL UndoElement::redo( ) +{ + impl_toggleModelState(); +} + +// = ShapeUndoElement + +ShapeUndoElement::ShapeUndoElement( std::unique_ptr xSdrUndoAction ) + :m_xAction( std::move(xSdrUndoAction) ) +{ +} + +ShapeUndoElement::~ShapeUndoElement() +{ +} + +OUString SAL_CALL ShapeUndoElement::getTitle() +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + return m_xAction->GetComment(); +} + +void SAL_CALL ShapeUndoElement::undo( ) +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + m_xAction->Undo(); +} + +void SAL_CALL ShapeUndoElement::redo( ) +{ + if ( !m_xAction ) + throw DisposedException( OUString(), *this ); + m_xAction->Redo(); +} + +} // namespace chart::impl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoActions.hxx b/chart2/source/controller/main/UndoActions.hxx new file mode 100644 index 000000000..3291a72be --- /dev/null +++ b/chart2/source/controller/main/UndoActions.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include + +#include + +namespace com::sun::star::frame { class XModel; } + +class SdrUndoAction; + +namespace chart +{ +class ChartModel; +class ChartModelClone; + +namespace impl +{ + +typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > UndoElement_TBase; + +class UndoElement final : public UndoElement_TBase +{ +public: + /** creates a new undo action + + @param i_actionString + is the title of the Undo action + @param i_documentModel + is the actual document model which the undo actions operates on + @param i_modelClone + is the cloned model from before the changes, which the Undo action represents, have been applied. + Upon invoking, the clone model is applied to the document model. + */ + UndoElement( const OUString & i_actionString, + const rtl::Reference<::chart::ChartModel>& i_documentModel, + const std::shared_ptr< ChartModelClone >& i_modelClone + ); + virtual ~UndoElement() override; + + UndoElement(const UndoElement&) = delete; + const UndoElement& operator=(const UndoElement&) = delete; + + // XUndoAction + virtual OUString SAL_CALL getTitle() override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + + // WeakComponentImplHelper + virtual void disposing(std::unique_lock&) override; + +private: + void impl_toggleModelState(); + +private: + OUString m_sActionString; + rtl::Reference<::chart::ChartModel> m_xDocumentModel; + std::shared_ptr< ChartModelClone > m_pModelClone; +}; + +typedef comphelper::WeakComponentImplHelper< css::document::XUndoAction > ShapeUndoElement_TBase; +class ShapeUndoElement final : public ShapeUndoElement_TBase +{ +public: + explicit ShapeUndoElement( std::unique_ptr xSdrUndoAction ); + virtual ~ShapeUndoElement() override; + + // XUndoAction + virtual OUString SAL_CALL getTitle() override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + +private: + std::unique_ptr m_xAction; +}; + +} // namespace impl +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoCommandDispatch.cxx b/chart2/source/controller/main/UndoCommandDispatch.cxx new file mode 100644 index 000000000..03897adf3 --- /dev/null +++ b/chart2/source/controller/main/UndoCommandDispatch.cxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "UndoCommandDispatch.hxx" +#include + +#include +#include + +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +UndoCommandDispatch::UndoCommandDispatch( + const Reference< uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel ) : + CommandDispatch( xContext ), + m_xModel( xModel ) +{ + m_xUndoManager.set( m_xModel->getUndoManager(), uno::UNO_SET_THROW ); +} + +UndoCommandDispatch::~UndoCommandDispatch() +{} + +void UndoCommandDispatch::initialize() +{ + Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY ); + ENSURE_OR_RETURN_VOID( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" ); + xBroadcaster->addModifyListener( this ); +} + +void UndoCommandDispatch::fireStatusEvent( + const OUString & rURL, + const Reference< frame::XStatusListener > & xSingleListener /* = 0 */ ) +{ + if( !m_xUndoManager.is() ) + return; + + const bool bFireAll = rURL.isEmpty(); + uno::Any aUndoState, aRedoState, aUndoStrings, aRedoStrings; + if( m_xUndoManager->isUndoPossible()) + aUndoState <<= SvtResId( STR_UNDO ) + m_xUndoManager->getCurrentUndoActionTitle(); + if( m_xUndoManager->isRedoPossible()) + aRedoState <<= SvtResId( STR_REDO ) + m_xUndoManager->getCurrentRedoActionTitle(); + + aUndoStrings <<= m_xUndoManager->getAllUndoActionTitles(); + aRedoStrings <<= m_xUndoManager->getAllRedoActionTitles(); + + if( bFireAll || rURL == ".uno:Undo" ) + fireStatusEventForURL( ".uno:Undo", aUndoState, m_xUndoManager->isUndoPossible(), xSingleListener ); + if( bFireAll || rURL == ".uno:Redo" ) + fireStatusEventForURL( ".uno:Redo", aRedoState, m_xUndoManager->isRedoPossible(), xSingleListener ); + if( bFireAll || rURL == ".uno:GetUndoStrings" ) + fireStatusEventForURL( ".uno:GetUndoStrings", aUndoStrings, true, xSingleListener ); + if( bFireAll || rURL == ".uno:GetRedoStrings" ) + fireStatusEventForURL( ".uno:GetRedoStrings", aRedoStrings, true, xSingleListener ); +} + +// ____ XDispatch ____ +void SAL_CALL UndoCommandDispatch::dispatch( + const util::URL& URL, + const Sequence< beans::PropertyValue >& Arguments ) +{ + if( !m_xUndoManager.is() ) + return; + + // why is it necessary to lock the solar mutex here? + SolarMutexGuard aSolarGuard; + try + { + sal_Int16 nCount( 1 ); + if ( Arguments.hasElements() && Arguments[0].Name == URL.Path ) + Arguments[0].Value >>= nCount; + + while ( nCount-- ) + { + if ( URL.Path == "Undo" ) + m_xUndoManager->undo(); + else + m_xUndoManager->redo(); + } + } + catch( const document::UndoFailedException& ) + { + // silently ignore + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + // \-- +} + +// ____ WeakComponentImplHelperBase ____ +/// is called when this is disposed +void SAL_CALL UndoCommandDispatch::disposing() +{ + Reference< util::XModifyBroadcaster > xBroadcaster( m_xUndoManager, uno::UNO_QUERY ); + OSL_ENSURE( xBroadcaster.is(), "UndoCommandDispatch::initialize: missing modification broadcaster interface!" ); + if( xBroadcaster.is() ) + { + xBroadcaster->removeModifyListener( this ); + } + + m_xUndoManager.clear(); + m_xModel.clear(); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL UndoCommandDispatch::disposing( const lang::EventObject& /* Source */ ) +{ + m_xUndoManager.clear(); + m_xModel.clear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoCommandDispatch.hxx b/chart2/source/controller/main/UndoCommandDispatch.hxx new file mode 100644 index 000000000..7be241a5f --- /dev/null +++ b/chart2/source/controller/main/UndoCommandDispatch.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "CommandDispatch.hxx" +#include + +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class ChartModel; + +/** This is a CommandDispatch implementation for Undo and Redo. + */ +class UndoCommandDispatch : public CommandDispatch +{ +public: + explicit UndoCommandDispatch( + const css::uno::Reference< css::uno::XComponentContext > & xContext, + const rtl::Reference<::chart::ChartModel> & xModel ); + virtual ~UndoCommandDispatch() override; + + // late initialisation, especially for adding as listener + virtual void initialize() override; + +protected: + // ____ XDispatch ____ + virtual void SAL_CALL dispatch( + const css::util::URL& URL, + const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override; + + // ____ WeakComponentImplHelperBase ____ + /// is called when this is disposed + virtual void SAL_CALL disposing() override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + virtual void fireStatusEvent( + const OUString & rURL, + const css::uno::Reference< css::frame::XStatusListener > & xSingleListener ) override; + +private: + rtl::Reference<::chart::ChartModel> m_xModel; + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoGuard.cxx b/chart2/source/controller/main/UndoGuard.cxx new file mode 100644 index 000000000..85cb8bcc9 --- /dev/null +++ b/chart2/source/controller/main/UndoGuard.cxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "UndoGuard.hxx" +#include "ChartModelClone.hxx" +#include "UndoActions.hxx" +#include + +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +UndoGuard::UndoGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager > & i_undoManager, + const ModelFacet i_facet ) + :m_xUndoManager( i_undoManager ) + ,m_aUndoString( i_undoString ) + ,m_bActionPosted( false ) +{ + m_xChartModel = dynamic_cast<::chart::ChartModel*>(i_undoManager->getParent().get()); + assert(m_xChartModel); + m_pDocumentSnapshot = std::make_shared( m_xChartModel, i_facet ); +} + +UndoGuard::~UndoGuard() +{ + if ( m_pDocumentSnapshot ) + discardSnapshot(); +} + +void UndoGuard::commit() +{ + if ( !m_bActionPosted && m_pDocumentSnapshot ) + { + try + { + const Reference< document::XUndoAction > xAction( new impl::UndoElement( m_aUndoString, m_xChartModel, m_pDocumentSnapshot ) ); + m_pDocumentSnapshot.reset(); // don't dispose, it's data went over to the UndoElement + m_xUndoManager->addUndoAction( xAction ); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + m_bActionPosted = true; +} + +void UndoGuard::rollback() +{ + ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" ); + m_pDocumentSnapshot->applyToModel( m_xChartModel ); + discardSnapshot(); +} + +void UndoGuard::discardSnapshot() +{ + ENSURE_OR_RETURN_VOID( !!m_pDocumentSnapshot, "no snapshot!" ); + m_pDocumentSnapshot->dispose(); + m_pDocumentSnapshot.reset(); +} + +UndoLiveUpdateGuard::UndoLiveUpdateGuard( const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL ) +{ +} + +UndoLiveUpdateGuard::~UndoLiveUpdateGuard() +{ + if ( !isActionPosted() ) + rollback(); +} + +UndoLiveUpdateGuardWithData::UndoLiveUpdateGuardWithData( + const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_DATA ) +{ +} + +UndoLiveUpdateGuardWithData::~UndoLiveUpdateGuardWithData() +{ + if ( !isActionPosted() ) + rollback(); +} + +UndoGuardWithSelection::UndoGuardWithSelection( + const OUString& i_undoString, const uno::Reference< document::XUndoManager >& i_undoManager ) + :UndoGuard( i_undoString, i_undoManager, E_MODEL_WITH_SELECTION ) +{ +} + +UndoGuardWithSelection::~UndoGuardWithSelection() +{ + if ( !isActionPosted() ) + rollback(); +} + +HiddenUndoContext::HiddenUndoContext( const Reference< document::XUndoManager > & i_undoManager ) + :m_xUndoManager( i_undoManager ) +{ + ENSURE_OR_THROW( m_xUndoManager.is(), "invalid undo manager!" ); + try + { + m_xUndoManager->enterHiddenUndoContext(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + m_xUndoManager.clear(); + // prevents the leaveUndoContext in the dtor + } +} + +HiddenUndoContext::~HiddenUndoContext() +{ + try + { + if ( m_xUndoManager.is() ) + m_xUndoManager->leaveUndoContext(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/main/UndoGuard.hxx b/chart2/source/controller/main/UndoGuard.hxx new file mode 100644 index 000000000..9808da8bc --- /dev/null +++ b/chart2/source/controller/main/UndoGuard.hxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "ChartModelClone.hxx" + +#include + +#include + +namespace com::sun::star::document { class XUndoManager; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ + +/** A guard which does nothing, unless you explicitly call commitAction. In particular, in its destructor, it + does neither auto-commit nor auto-rollback the model changes. + */ +class UndoGuard +{ +public: + explicit UndoGuard( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager, + const ModelFacet i_facet = E_MODEL + ); + ~UndoGuard(); + + void commit(); + void rollback(); + +protected: + bool isActionPosted() const { return m_bActionPosted; } + +private: + void discardSnapshot(); + +private: + rtl::Reference<::chart::ChartModel> m_xChartModel; + const css::uno::Reference< css::document::XUndoManager > m_xUndoManager; + + std::shared_ptr< ChartModelClone > m_pDocumentSnapshot; + OUString m_aUndoString; + bool m_bActionPosted; +}; + +/** A guard which, in its destructor, restores the model state it found in the constructor. If + commitAction is called inbetween, the restoration is not performed. + */ +class UndoLiveUpdateGuard : public UndoGuard +{ +public: + explicit UndoLiveUpdateGuard( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~UndoLiveUpdateGuard(); +}; + +/** Same as UndoLiveUpdateGuard but with additional storage of the chart's data. + Only use this if the data has internal data. + */ +class UndoLiveUpdateGuardWithData : + public UndoGuard +{ +public: + explicit UndoLiveUpdateGuardWithData( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~UndoLiveUpdateGuardWithData(); +}; + +class UndoGuardWithSelection : public UndoGuard +{ +public: + explicit UndoGuardWithSelection( + const OUString& i_undoMessage, + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + virtual ~UndoGuardWithSelection(); +}; + +class HiddenUndoContext +{ +public: + explicit HiddenUndoContext( + const css::uno::Reference< css::document::XUndoManager > & i_undoManager + ); + ~HiddenUndoContext(); + +private: + css::uno::Reference< css::document::XUndoManager > m_xUndoManager; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/Chart2PanelFactory.cxx b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx new file mode 100644 index 000000000..081322b09 --- /dev/null +++ b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Chart2PanelFactory.hxx" + +#include +#include +#include +#include +#include +#include + +#include "ChartElementsPanel.hxx" +#include "ChartTypePanel.hxx" +#include "ChartSeriesPanel.hxx" +#include +#include "ChartAxisPanel.hxx" +#include "ChartErrorBarPanel.hxx" +#include "ChartAreaPanel.hxx" +#include "ChartLinePanel.hxx" + +using namespace css::uno; + +namespace chart::sidebar { + +ChartPanelFactory::ChartPanelFactory() +{ +} + +ChartPanelFactory::~ChartPanelFactory() +{ +} + +Reference SAL_CALL ChartPanelFactory::createUIElement ( + const OUString& rsResourceURL, + const ::css::uno::Sequence& rArguments) +{ + Reference xElement; + + try + { + const ::comphelper::NamedValueCollection aArguments (rArguments); + Reference xFrame (aArguments.getOrDefault("Frame", Reference())); + Reference xParentWindow (aArguments.getOrDefault("ParentWindow", Reference())); + Reference xController (aArguments.getOrDefault("Controller", Reference())); + + weld::Widget* pParent(nullptr); + if (weld::TransportAsXWindow* pTunnel = dynamic_cast(xParentWindow.get())) + pParent = pTunnel->getWidget(); + + if (!pParent) + throw RuntimeException( + "PanelFactory::createUIElement called without ParentWindow", + nullptr); + if ( ! xFrame.is()) + throw RuntimeException( + "PanelFactory::createUIElement called without Frame", + nullptr); + if (!xController.is()) + throw RuntimeException( + "ChartPanelFactory::createUIElement called without Controller", + nullptr); + + ChartController* pController = dynamic_cast(xController.get()); + if (!pController) + throw RuntimeException( + "ChartPanelFactory::createUIElement called without valid ChartController", + nullptr); + + std::unique_ptr xPanel; + if (rsResourceURL.endsWith("/ElementsPanel")) + xPanel = ChartElementsPanel::Create( pParent, pController ); + else if (rsResourceURL.endsWith("/TypePanel")) + xPanel = std::make_unique(pParent, pController); + else if (rsResourceURL.endsWith("/SeriesPanel")) + xPanel = ChartSeriesPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/AxisPanel")) + xPanel = ChartAxisPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/ErrorBarPanel")) + xPanel = ChartErrorBarPanel::Create(pParent, pController); + else if (rsResourceURL.endsWith("/AreaPanel")) + xPanel = ChartAreaPanel::Create(pParent, xFrame, pController); + else if (rsResourceURL.endsWith("/LinePanel")) + xPanel = ChartLinePanel::Create(pParent, xFrame, pController); + + if (xPanel) + xElement = sfx2::sidebar::SidebarPanelBase::Create( + rsResourceURL, + xFrame, + std::move(xPanel), + css::ui::LayoutSize(-1,-1,-1)); + } + catch (const css::uno::RuntimeException &) + { + throw; + } + catch (const css::uno::Exception&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "ChartPanelFactory::createUIElement exception", + nullptr, anyEx ); + } + + return xElement; +} + +OUString ChartPanelFactory::getImplementationName() +{ + return "org.libreoffice.comp.chart2.sidebar.ChartPanelFactory"; +} + +sal_Bool ChartPanelFactory::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence ChartPanelFactory::getSupportedServiceNames() +{ + return { "com.sun.star.ui.UIElementFactory" }; +} + +} // end of namespace chart::sidebar + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_libreoffice_comp_chart2_sidebar_ChartPanelFactory(css::uno::XComponentContext*, css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::sidebar::ChartPanelFactory()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/Chart2PanelFactory.hxx b/chart2/source/controller/sidebar/Chart2PanelFactory.hxx new file mode 100644 index 000000000..87619f647 --- /dev/null +++ b/chart2/source/controller/sidebar/Chart2PanelFactory.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + + +namespace chart::sidebar { + +typedef comphelper::WeakComponentImplHelper < + css::ui::XUIElementFactory, css::lang::XServiceInfo + > PanelFactoryInterfaceBase; + +class ChartPanelFactory final + : public PanelFactoryInterfaceBase +{ +public: + ChartPanelFactory(); + virtual ~ChartPanelFactory() override; + + ChartPanelFactory(const ChartPanelFactory&) = delete; + const ChartPanelFactory& operator=(const ChartPanelFactory&) = delete; + + // XUIElementFactory + virtual css::uno::Reference SAL_CALL createUIElement( + const OUString& rsResourceURL, + const ::css::uno::Sequence& rArguments) override; + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +} // end of namespace chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAreaPanel.cxx b/chart2/source/controller/sidebar/ChartAreaPanel.cxx new file mode 100644 index 000000000..b8bd8198b --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAreaPanel.cxx @@ -0,0 +1,551 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include "ChartAreaPanel.hxx" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace chart::sidebar { + +namespace { + +SvxColorToolBoxControl* getColorToolBoxControl(const ToolbarUnoDispatcher& rColorDispatch) +{ + css::uno::Reference xController = rColorDispatch.GetControllerForCommand(".uno:FillColor"); + SvxColorToolBoxControl* pToolBoxColorControl = dynamic_cast(xController.get()); + return pToolBoxColorControl; +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + { + // if no selection, default to diagram wall so sidebar can show some editable properties + ChartController* pController = dynamic_cast(xController.get()); + if (pController) + { + pController->select( css::uno::Any( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ) ); + xSelectionSupplier = css::uno::Reference(xController, css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + aAny = xSelectionSupplier->getSelection(); + } + + if (!aAny.hasValue()) + return OUString(); + } + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +ChartController* getController(const css::uno::Reference& xModel) +{ + css::uno::ReferencexController = xModel->getCurrentController(); + if (!xController.is()) + throw std::exception(); + + ChartController* pController = dynamic_cast(xController.get()); + if (!pController) + throw std::exception(); + + return pController; +} + +ViewElementListProvider getViewElementListProvider( const css::uno::Reference& xModel) +{ + ChartController* pController = getController(xModel); + ViewElementListProvider aProvider = pController->getViewElementListProvider(); + return aProvider; +} + +DrawModelWrapper* getDrawModelWrapper(const css::uno::Reference& xModel) +{ + ChartController* pController = getController(xModel); + return pController->GetDrawModelWrapper(); +} + +XFillGradientItem getXGradientForName(const css::uno::Reference& xModel, + const OUString& rName) +{ + css::uno::Reference xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference xNameAccess( + xFact->createInstance("com.sun.star.drawing.GradientTable"), css::uno::UNO_QUERY); + if (!xNameAccess.is()) + return XFillGradientItem(); + + if (!xNameAccess->hasByName(rName)) + return XFillGradientItem(); + + css::uno::Any aAny = xNameAccess->getByName(rName); + + XFillGradientItem aItem; + aItem.SetName(rName); + aItem.PutValue(aAny, MID_FILLGRADIENT); + + return aItem; + +} + +XFillFloatTransparenceItem getXTransparencyGradientForName(const css::uno::Reference& xModel, + const OUString& rName) +{ + css::uno::Reference xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference xNameAccess( + xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), css::uno::UNO_QUERY); + if (!xNameAccess.is()) + return XFillFloatTransparenceItem(); + + if (!xNameAccess->hasByName(rName)) + return XFillFloatTransparenceItem(); + + css::uno::Any aAny = xNameAccess->getByName(rName); + + XFillFloatTransparenceItem aItem; + aItem.SetName(rName); + aItem.PutValue(aAny, MID_FILLGRADIENT); + aItem.SetEnabled(true); + + return aItem; +} + +XHatch getXHatchFromName(const css::uno::Reference& xModel, + OUString& rName) +{ + try + { + ViewElementListProvider aProvider = getViewElementListProvider(xModel); + XHatchListRef aRef = aProvider.GetHatchList(); + size_t n = aRef->Count(); + for (size_t i = 0; i < n; ++i) + { + const XHatchEntry* pHatch = aRef->GetHatch(i); + if (!pHatch) + continue; + + if (pHatch->GetName().equalsIgnoreAsciiCase(rName)) + { + // we need to update the hatch name + rName = pHatch->GetName(); + return pHatch->GetHatch(); + } + } + } + catch (...) + { + // ignore exception + } + + return XHatch(); +} + +GraphicObject getXBitmapFromName(const css::uno::Reference& xModel, + std::u16string_view rName) +{ + try + { + ViewElementListProvider aProvider = getViewElementListProvider(xModel); + XBitmapListRef aBmpRef = aProvider.GetBitmapList(); + XPatternListRef aPatRef = aProvider.GetPatternList(); + + size_t n = aBmpRef->Count(); + for (size_t i = 0; i < n; ++i) + { + const XBitmapEntry* pBitmap = aBmpRef->GetBitmap(i); + if (!pBitmap) + continue; + + if (pBitmap->GetName().equalsIgnoreAsciiCase(rName)) + { + return pBitmap->GetGraphicObject(); + } + } + + // perhaps it's a pattern + size_t m = aPatRef->Count(); + for (size_t i = 0; i < m; ++i) + { + const XBitmapEntry* pBitmap = aPatRef->GetBitmap(i); + if (!pBitmap) + continue; + + if (pBitmap->GetName().equalsIgnoreAsciiCase(rName)) + { + return pBitmap->GetGraphicObject(); + } + } + } + catch (...) + { + // ignore exception + } + + return GraphicObject(); +} + +class PreventUpdate +{ +public: + explicit PreventUpdate(bool& bUpdate): + mbUpdate(bUpdate) + { + mbUpdate = false; + } + + ~PreventUpdate() + { + mbUpdate = true; + } + +private: + bool& mbUpdate; +}; + +} + +std::unique_ptr ChartAreaPanel::Create( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw css::lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + if (!rxFrame.is()) + throw css::lang::IllegalArgumentException("no XFrame given to ChartAxisPanel::Create", nullptr, 1); + + return std::make_unique(pParent, rxFrame, pController); +} + +ChartAreaPanel::ChartAreaPanel(weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController): + svx::sidebar::AreaPropertyPanelBase(pParent, rxFrame), + mxModel(pController->getChartModel()), + mxListener(new ChartSidebarModifyListener(this)), + mxSelectionListener(new ChartSidebarSelectionListener(this)), + mbUpdate(true), + mbModelValid(true), + maFillColorWrapper(mxModel, getColorToolBoxControl(*mxColorDispatch), "FillColor") +{ + std::vector aAcceptedTypes { OBJECTTYPE_PAGE, OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DATA_SERIES, OBJECTTYPE_DATA_POINT, + OBJECTTYPE_TITLE, OBJECTTYPE_LEGEND}; + mxSelectionListener->setAcceptedTypes(std::move(aAcceptedTypes)); + Initialize(); +} + +ChartAreaPanel::~ChartAreaPanel() +{ + doUpdateModel(nullptr); +} + +void ChartAreaPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + SvxColorToolBoxControl* pToolBoxColor = getColorToolBoxControl(*mxColorDispatch); + pToolBoxColor->setColorSelectFunction(maFillColorWrapper); + + updateData(); +} + +void ChartAreaPanel::setFillTransparence(const XFillTransparenceItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("FillTransparence", css::uno::Any(rItem.GetValue())); +} + +void ChartAreaPanel::setFillFloatTransparence( + const XFillFloatTransparenceItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (!rItem.IsEnabled()) + { + xPropSet->setPropertyValue("FillTransparenceGradientName", css::uno::Any(OUString())); + return; + } + + const OUString& aName = rItem.GetName(); + css::uno::Any aGradientVal; + rItem.QueryValue(aGradientVal, MID_FILLGRADIENT); + OUString aNewName = PropertyHelper::addTransparencyGradientUniqueNameToTable(aGradientVal, mxModel, aName); + xPropSet->setPropertyValue("FillTransparenceGradientName", css::uno::Any(aNewName)); +} + +void ChartAreaPanel::setFillStyle(const XFillStyleItem& rItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("FillStyle", css::uno::Any(rItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndColor(const XFillStyleItem* pStyleItem, + const XFillColorItem& rColorItem) +{ + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + xPropSet->setPropertyValue("FillColor", css::uno::Any(rColorItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndGradient(const XFillStyleItem* pStyleItem, + const XFillGradientItem& rGradientItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + + const OUString& aName = rGradientItem.GetName(); + css::uno::Any aGradientVal; + rGradientItem.QueryValue(aGradientVal, MID_FILLGRADIENT); + OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(aGradientVal, mxModel, aName); + xPropSet->setPropertyValue("FillGradientName", css::uno::Any(aNewName)); +} + +void ChartAreaPanel::setFillStyleAndHatch(const XFillStyleItem* pStyleItem, + const XFillHatchItem& rHatchItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + xPropSet->setPropertyValue("FillHatchName", css::uno::Any(rHatchItem.GetValue())); +} + +void ChartAreaPanel::setFillStyleAndBitmap(const XFillStyleItem* pStyleItem, + const XFillBitmapItem& rBitmapItem) +{ + PreventUpdate aProtector(mbUpdate); + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + if (pStyleItem) + xPropSet->setPropertyValue("FillStyle", css::uno::Any(pStyleItem->GetValue())); + + css::uno::Any aBitmap; + rBitmapItem.QueryValue(aBitmap, MID_BITMAP); + const OUString& aPreferredName = rBitmapItem.GetName(); + aBitmap <<= PropertyHelper::addBitmapUniqueNameToTable(aBitmap, mxModel, aPreferredName); + xPropSet->setPropertyValue("FillBitmapName", aBitmap); +} + +void ChartAreaPanel::setFillUseBackground(const XFillStyleItem* pStyleItem, + const XFillUseSlideBackgroundItem& /*rItem*/) +{ + setFillStyle(*pStyleItem); +} + +void ChartAreaPanel::updateData() +{ + if (!mbUpdate || !mbModelValid) + return; + + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::uno::Reference xInfo(xPropSet->getPropertySetInfo()); + if (!xInfo.is()) + return; + + SolarMutexGuard aGuard; + if (xInfo->hasPropertyByName("FillStyle")) + { + css::drawing::FillStyle eFillStyle = css::drawing::FillStyle_SOLID; + xPropSet->getPropertyValue("FillStyle") >>= eFillStyle; + XFillStyleItem aFillStyleItem(eFillStyle); + updateFillStyle(false, true, &aFillStyleItem); + } + + if (xInfo->hasPropertyByName("FillTransparence")) + { + sal_uInt16 nFillTransparence = 0; + xPropSet->getPropertyValue("FillTransparence") >>= nFillTransparence; + SfxUInt16Item aTransparenceItem(0, nFillTransparence); + updateFillTransparence(false, true, &aTransparenceItem); + } + + if (xInfo->hasPropertyByName("FillGradientName")) + { + OUString aGradientName; + xPropSet->getPropertyValue("FillGradientName") >>= aGradientName; + XFillGradientItem aGradientItem = getXGradientForName(mxModel, aGradientName); + updateFillGradient(false, true, &aGradientItem); + } + + if (xInfo->hasPropertyByName("FillHatchName")) + { + OUString aHatchName; + xPropSet->getPropertyValue("FillHatchName") >>= aHatchName; + XHatch aHatch = getXHatchFromName(mxModel, aHatchName); + XFillHatchItem aHatchItem(aHatchName, aHatch); + updateFillHatch(false, true, &aHatchItem); + } + + if (xInfo->hasPropertyByName("FillBitmapName")) + { + OUString aBitmapName; + xPropSet->getPropertyValue("FillBitmapName") >>= aBitmapName; + GraphicObject aBitmap = getXBitmapFromName(mxModel, aBitmapName); + XFillBitmapItem aBitmapItem(aBitmapName, aBitmap); + std::unique_ptr pBitmapItem; + try + { + DrawModelWrapper* pModelWrapper = getDrawModelWrapper(mxModel); + if (pModelWrapper) + { + pBitmapItem = aBitmapItem.checkForUniqueItem(&pModelWrapper->getSdrModel()); + } + } + catch (...) + { + } + updateFillBitmap(false, true, pBitmapItem ? pBitmapItem.get() : &aBitmapItem); + } + + if (xInfo->hasPropertyByName("FillTransparenceGradientName")) + { + OUString aFillFloatTransparenceName; + xPropSet->getPropertyValue("FillTransparenceGradientName") >>= aFillFloatTransparenceName; + XFillFloatTransparenceItem aFillFloatTransparenceItem = getXTransparencyGradientForName(mxModel, aFillFloatTransparenceName); + updateFillFloatTransparence(false, true, &aFillFloatTransparenceItem); + + maFillColorWrapper.updateData(); + } + + if (xInfo->hasPropertyByName("FillColor")) + { + sal_uInt32 nFillColor = 0; + xPropSet->getPropertyValue("FillColor") >>= nFillColor; + XFillColorItem aFillColorItem("", Color(ColorTransparency, nFillColor)); + updateFillColor(true, &aFillColorItem); + } +} + +void ChartAreaPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartAreaPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +void ChartAreaPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + + css::uno::Reference oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartAreaPanel::updateModel( css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAreaPanel.hxx b/chart2/source/controller/sidebar/ChartAreaPanel.hxx new file mode 100644 index 000000000..75caf8d0d --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAreaPanel.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" +#include "ChartColorWrapper.hxx" + +class XFillFloatTransparenceItem; +class XFillTransparenceItem; +class XFillColorItem; + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartAreaPanel : public svx::sidebar::AreaPropertyPanelBase, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController); + + // constructor/destructor + ChartAreaPanel( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController); + + virtual ~ChartAreaPanel() override; + + virtual void setFillTransparence(const XFillTransparenceItem& rItem) override; + virtual void setFillFloatTransparence(const XFillFloatTransparenceItem& rItem) override; + virtual void setFillStyle(const XFillStyleItem& rItem) override; + virtual void setFillStyleAndColor(const XFillStyleItem* pStyleItem, const XFillColorItem& rColorItem) override; + virtual void setFillStyleAndGradient(const XFillStyleItem* pStyleItem, const XFillGradientItem& rGradientItem) override; + virtual void setFillStyleAndHatch(const XFillStyleItem* pStyleItem, const XFillHatchItem& rHatchItem) override; + virtual void setFillStyleAndBitmap(const XFillStyleItem* pStyleItem, const XFillBitmapItem& rBitmapItem) override; + virtual void setFillUseBackground(const XFillStyleItem* pStyleItem, const XFillUseSlideBackgroundItem& rItem) override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference xModel) override; + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxListener; + rtl::Reference mxSelectionListener; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + bool mbUpdate; + bool mbModelValid; + + ChartColorWrapper maFillColorWrapper; +}; + +} } // end of namespace svx::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAxisPanel.cxx b/chart2/source/controller/sidebar/ChartAxisPanel.cxx new file mode 100644 index 000000000..acc4a8add --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAxisPanel.cxx @@ -0,0 +1,373 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include "ChartAxisPanel.hxx" +#include +#include +#include + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +bool isLabelShown(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return false; + + uno::Any aAny = xAxis->getPropertyValue("DisplayLabels"); + if (!aAny.hasValue()) + return false; + + bool bVisible = false; + aAny >>= bVisible; + return bVisible; +} + +void setLabelShown(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bVisible) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + xAxis->setPropertyValue("DisplayLabels", css::uno::Any(bVisible)); +} + +struct AxisLabelPosMap +{ + sal_Int32 nPos; + css::chart::ChartAxisLabelPosition ePos; +}; + +AxisLabelPosMap const aLabelPosMap[] = { + { 0, css::chart::ChartAxisLabelPosition_NEAR_AXIS }, + { 1, css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE }, + { 2, css::chart::ChartAxisLabelPosition_OUTSIDE_START }, + { 3, css::chart::ChartAxisLabelPosition_OUTSIDE_END } +}; + +sal_Int32 getLabelPosition(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return 0; + + uno::Any aAny = xAxis->getPropertyValue("LabelPosition"); + if (!aAny.hasValue()) + return 0; + + css::chart::ChartAxisLabelPosition ePos; + aAny >>= ePos; + for (AxisLabelPosMap const & i : aLabelPosMap) + { + if (i.ePos == ePos) + return i.nPos; + } + + return 0; +} + +void setLabelPosition(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + rtl::Reference< ::chart::Axis > xAxis = ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + css::chart::ChartAxisLabelPosition ePos; + for (AxisLabelPosMap const & i : aLabelPosMap) + { + if (i.nPos == nPos) + ePos = i.ePos; + } + + xAxis->setPropertyValue("LabelPosition", css::uno::Any(ePos)); +} + +bool isReverse(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return false; + + css::chart2::ScaleData aData = xAxis->getScaleData(); + + return aData.Orientation == css::chart2::AxisOrientation_REVERSE; +} + +void setReverse(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bReverse) +{ + rtl::Reference< Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + css::chart2::ScaleData aData = xAxis->getScaleData(); + if (bReverse) + aData.Orientation = css::chart2::AxisOrientation_REVERSE; + else + aData.Orientation = css::chart2::AxisOrientation_MATHEMATICAL; + + xAxis->setScaleData(aData); +} + +OUString getCID(const css::uno::Reference& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + assert(aAny.hasValue()); + OUString aCID; + aAny >>= aCID; +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if(eType != OBJECTTYPE_AXIS) + SAL_WARN("chart2","Selected item is not an axis"); +#endif + + return aCID; +} + +void setAxisRotation(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, double nVal) +{ + rtl::Reference< ::chart::Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return; + + xAxis->setPropertyValue("TextRotation", css::uno::Any(nVal)); +} + +double getAxisRotation(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< ::chart::Axis > xAxis = + ObjectIdentifier::getAxisForCID(rCID, xModel); + + if (!xAxis.is()) + return 0; + + css::uno::Any aAny = xAxis->getPropertyValue("TextRotation"); + double nVal = 0; + aAny >>= nVal; + return nVal; +} + +} + +ChartAxisPanel::ChartAxisPanel( + weld::Widget* pParent, + ChartController* pController) + : PanelLayout(pParent, "ChartAxisPanel", "modules/schart/ui/sidebaraxis.ui") + , mxCBShowLabel(m_xBuilder->weld_check_button("checkbutton_show_label")) + , mxCBReverse(m_xBuilder->weld_check_button("checkbutton_reverse")) + , mxLBLabelPos(m_xBuilder->weld_combo_box("comboboxtext_label_position")) + , mxGridLabel(m_xBuilder->weld_widget("label_props")) + , mxNFRotation(m_xBuilder->weld_metric_spin_button("spinbutton1", FieldUnit::DEGREE)) + , mxModel(pController->getChartModel()) + , mxModifyListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_AXIS)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartAxisPanel::~ChartAxisPanel() +{ + doUpdateModel(nullptr); + + mxCBShowLabel.reset(); + mxCBReverse.reset(); + + mxLBLabelPos.reset(); + mxGridLabel.reset(); + + mxNFRotation.reset(); +} + +void ChartAxisPanel::Initialize() +{ + mxModel->addModifyListener(mxModifyListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + updateData(); + + Link aLink = LINK(this, ChartAxisPanel, CheckBoxHdl); + mxCBShowLabel->connect_toggled(aLink); + mxCBReverse->connect_toggled(aLink); + + Link aSpinButtonLink = LINK(this, ChartAxisPanel, TextRotationHdl); + mxNFRotation->connect_value_changed(aSpinButtonLink); + + mxLBLabelPos->connect_changed(LINK(this, ChartAxisPanel, ListBoxHdl)); +} + +void ChartAxisPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType!=OBJECTTYPE_AXIS) + return; + + SolarMutexGuard aGuard; + + mxCBShowLabel->set_active(isLabelShown(mxModel, aCID)); + mxCBReverse->set_active(isReverse(mxModel, aCID)); + + mxLBLabelPos->set_active(getLabelPosition(mxModel, aCID)); + mxNFRotation->set_value(getAxisRotation(mxModel, aCID), FieldUnit::DEGREE); +} + +std::unique_ptr ChartAxisPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + return std::make_unique(pParent, pController); +} + +void ChartAxisPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartAxisPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartAxisPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartAxisPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartAxisPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxModifyListener); + + css::uno::Reference oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxModifyListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartAxisPanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartAxisPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +IMPL_LINK(ChartAxisPanel, CheckBoxHdl, weld::Toggleable&, rCheckbox, void) +{ + OUString aCID = getCID(mxModel); + bool bChecked = rCheckbox.get_active(); + + if (&rCheckbox == mxCBShowLabel.get()) + { + mxGridLabel->set_sensitive(bChecked); + setLabelShown(mxModel, aCID, bChecked); + } + else if (&rCheckbox == mxCBReverse.get()) + setReverse(mxModel, aCID, bChecked); +} + +IMPL_LINK_NOARG(ChartAxisPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + sal_Int32 nPos = mxLBLabelPos->get_active(); + + setLabelPosition(mxModel, aCID, nPos); +} + +IMPL_LINK(ChartAxisPanel, TextRotationHdl, weld::MetricSpinButton&, rMetricField, void) +{ + OUString aCID = getCID(mxModel); + double nVal = rMetricField.get_value(FieldUnit::DEGREE); + setAxisRotation(mxModel, aCID, nVal); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartAxisPanel.hxx b/chart2/source/controller/sidebar/ChartAxisPanel.hxx new file mode 100644 index 000000000..32f3c0b33 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartAxisPanel.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include +#include +#include +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } +namespace com::sun::star::view { class XSelectionChangeListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartAxisPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartAxisPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartAxisPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference xModel) override; + +private: + //ui controls + std::unique_ptr mxCBShowLabel; + std::unique_ptr mxCBReverse; + std::unique_ptr mxLBLabelPos; + std::unique_ptr mxGridLabel; + std::unique_ptr mxNFRotation; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxModifyListener; + css::uno::Reference mxSelectionListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); + DECL_LINK(TextRotationHdl, weld::MetricSpinButton&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartColorWrapper.cxx b/chart2/source/controller/sidebar/ChartColorWrapper.cxx new file mode 100644 index 000000000..47df22d6e --- /dev/null +++ b/chart2/source/controller/sidebar/ChartColorWrapper.cxx @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include "ChartColorWrapper.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace chart::sidebar { + +namespace { + +OUString getCID(const css::uno::Reference& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + return OUString(); + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +} + +ChartColorWrapper::ChartColorWrapper( + rtl::Reference<::chart::ChartModel> const & xModel, + SvxColorToolBoxControl* pControl, + const OUString& rName): + mxModel(xModel), + mpControl(pControl), + maPropertyName(rName) +{ +} + +void ChartColorWrapper::operator()([[maybe_unused]] const OUString& , const svx::NamedThemedColor& rColor) +{ + css::uno::Reference xPropSet = getPropSet(mxModel); + + if (!xPropSet.is()) + { + SAL_WARN("chart2", "Invalid reference to xPropSet"); + return; + } + + xPropSet->setPropertyValue(maPropertyName, css::uno::Any(rColor.m_aColor)); +} + +void ChartColorWrapper::updateModel(const rtl::Reference<::chart::ChartModel>& xModel) +{ + mxModel = xModel; +} + +void ChartColorWrapper::updateData() +{ + static constexpr OUStringLiteral aLineColor = u"LineColor"; + static const std::u16string_view aCommands[2] = {u".uno:XLineColor", u".uno:FillColor"}; + + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::util::URL aUrl; + aUrl.Complete = (maPropertyName == aLineColor) ? aCommands[0] : aCommands[1]; + + css::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aUrl; + aEvent.IsEnabled = true; + aEvent.State = xPropSet->getPropertyValue(maPropertyName); + mpControl->statusChanged(aEvent); + + SfxViewShell* pViewShell = SfxViewShell::Current(); + if (comphelper::LibreOfficeKit::isActive() && pViewShell && (maPropertyName == aLineColor)) + { + std::string sCommand = OUStringToOString(aUrl.Complete, RTL_TEXTENCODING_ASCII_US).getStr(); + sal_Int32 nColor = -1; + aEvent.State >>= nColor; + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + (sCommand + "=" + std::to_string(nColor)).c_str()); + } +} + +ChartLineStyleWrapper::ChartLineStyleWrapper( + rtl::Reference<::chart::ChartModel> const & xModel, + SvxLineStyleToolBoxControl* pControl) + : mxModel(xModel) + , mpControl(pControl) +{ +} + +void ChartLineStyleWrapper::updateModel(const rtl::Reference<::chart::ChartModel>& xModel) +{ + mxModel = xModel; +} + +namespace +{ + css::uno::Any getLineDash( + const css::uno::Reference& xModel, const OUString& rDashName) + { + css::uno::Reference xFact(xModel, css::uno::UNO_QUERY); + css::uno::Reference xNameAccess( + xFact->createInstance("com.sun.star.drawing.DashTable"), + css::uno::UNO_QUERY ); + if(xNameAccess.is()) + { + if (!xNameAccess->hasByName(rDashName)) + return css::uno::Any(); + + return xNameAccess->getByName(rDashName); + } + + return css::uno::Any(); + } +} + +void ChartLineStyleWrapper::updateData() +{ + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + css::util::URL aUrl; + aUrl.Complete = ".uno:XLineStyle"; + + css::frame::FeatureStateEvent aEvent; + aEvent.IsEnabled = true; + + aEvent.FeatureURL = aUrl; + aEvent.State = xPropSet->getPropertyValue("LineStyle"); + mpControl->statusChanged(aEvent); + + aUrl.Complete = ".uno:LineDash"; + + auto aLineDashName = xPropSet->getPropertyValue("LineDashName"); + OUString aDashName; + aLineDashName >>= aDashName; + css::uno::Any aLineDash = getLineDash(mxModel, aDashName); + XLineDashItem aDashItem; + aDashItem.PutValue(aLineDash, MID_LINEDASH); + + aEvent.FeatureURL = aUrl; + aDashItem.QueryValue(aEvent.State); + mpControl->statusChanged(aEvent); +} + +bool ChartLineStyleWrapper::operator()(std::u16string_view rCommand, const css::uno::Any& rValue) +{ + css::uno::Reference xPropSet = getPropSet(mxModel); + + if (!xPropSet.is()) + { + SAL_WARN("chart2", "Invalid reference to xPropSet"); + return false; + } + + if (rCommand == u".uno:XLineStyle") + { + xPropSet->setPropertyValue("LineStyle", rValue); + return true; + } + else if (rCommand == u".uno:LineDash") + { + XLineDashItem aDashItem; + aDashItem.PutValue(rValue, 0); + css::uno::Any aAny; + aDashItem.QueryValue(aAny, MID_LINEDASH); + OUString aDashName = PropertyHelper::addLineDashUniqueNameToTable(aAny, + mxModel, + ""); + xPropSet->setPropertyValue("LineDash", aAny); + xPropSet->setPropertyValue("LineDashName", css::uno::Any(aDashName)); + return true; + } + return false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartColorWrapper.hxx b/chart2/source/controller/sidebar/ChartColorWrapper.hxx new file mode 100644 index 000000000..5237bc9c3 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartColorWrapper.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include +#include + +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } +class SvxColorToolBoxControl; +class SvxLineStyleToolBoxControl; + +namespace chart::sidebar { + +class ChartColorWrapper +{ +public: + ChartColorWrapper(rtl::Reference<::chart::ChartModel> const & xModel, + SvxColorToolBoxControl* pControl, + const OUString& rPropertyName); + + void operator()(const OUString& rCommand, const svx::NamedThemedColor& rColor); + // ColorSelectFunction signature + + void updateModel(const rtl::Reference<::chart::ChartModel>& xModel); + + void updateData(); + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + + SvxColorToolBoxControl* mpControl; + + OUString maPropertyName; +}; + +class ChartLineStyleWrapper +{ +public: + ChartLineStyleWrapper(rtl::Reference<::chart::ChartModel> const & xModel, + SvxLineStyleToolBoxControl* pControl); + + bool operator()(std::u16string_view rCommand, const css::uno::Any& rValue); + + void updateModel(const rtl::Reference<::chart::ChartModel>& xModel); + + void updateData(); + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + + SvxLineStyleToolBoxControl* mpControl; +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartElementsPanel.cxx b/chart2/source/controller/sidebar/ChartElementsPanel.cxx new file mode 100644 index 000000000..75dc7ed96 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartElementsPanel.cxx @@ -0,0 +1,662 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include "ChartElementsPanel.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +enum class GridType +{ + VERT_MAJOR, + VERT_MINOR, + HOR_MAJOR, + HOR_MINOR +}; + +enum class AxisType +{ + X_MAIN, + Y_MAIN, + Z_MAIN, + X_SECOND, + Y_SECOND +}; + +ChartModel* getChartModel(const css::uno::Reference& xModel) +{ + ChartModel* pModel = dynamic_cast(xModel.get()); + + return pModel; +} + +bool isLegendVisible(const css::uno::Reference& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return false; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if( xLegendProp.is()) + { + try + { + bool bShow = false; + if( xLegendProp->getPropertyValue( "Show") >>= bShow ) + { + return bShow; + } + } + catch(const uno::Exception &) + { + } + } + + return false; +} + +void setLegendVisible(const css::uno::Reference& xModel, bool bVisible) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + if (bVisible) + LegendHelper::showLegend(*pModel, comphelper::getProcessComponentContext()); + else + LegendHelper::hideLegend(*pModel); +} + +bool isLegendOverlay(const css::uno::Reference& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return false; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if( xLegendProp.is()) + { + try + { + bool bOverlay = false; + if(xLegendProp->getPropertyValue("Overlay") >>= bOverlay) + { + return bOverlay; + } + } + catch(const uno::Exception &) + { + } + } + + return false; +} + +void setLegendOverlay(const css::uno::Reference& xModel, bool bOverlay) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + rtl::Reference xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return; + + xLegendProp->setPropertyValue("Overlay", css::uno::Any(bOverlay)); +} + +bool isTitleVisible(const rtl::Reference<::chart::ChartModel>& xModel, TitleHelper::eTitleType eTitle) +{ + css::uno::Reference xTitle = TitleHelper::getTitle(eTitle, xModel); + if (!xTitle.is()) + return false; + + css::uno::Reference xPropSet(xTitle, css::uno::UNO_QUERY_THROW); + css::uno::Any aAny = xPropSet->getPropertyValue("Visible"); + bool bVisible = aAny.get(); + return bVisible; +} + +bool isGridVisible(const rtl::Reference<::chart::ChartModel>& xModel, GridType eType) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(xDiagram.is()) + { + sal_Int32 nDimensionIndex = 0; + if (eType == GridType::HOR_MAJOR || eType == GridType::HOR_MINOR) + nDimensionIndex = 1; + + bool bMajor = (eType == GridType::HOR_MAJOR || eType == GridType::VERT_MAJOR); + + bool bHasGrid = AxisHelper::isGridShown(nDimensionIndex, 0, bMajor, xDiagram); + return bHasGrid; + } + return false; +} + +void setGridVisible(const rtl::Reference<::chart::ChartModel>& xModel, GridType eType, bool bVisible) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(!xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + if (eType == GridType::HOR_MAJOR || eType == GridType::HOR_MINOR) + nDimensionIndex = 1; + sal_Int32 nCooSysIndex = 0; + + bool bMajor = (eType == GridType::HOR_MAJOR || eType == GridType::VERT_MAJOR); + + if (bVisible) + AxisHelper::showGrid(nDimensionIndex, nCooSysIndex, bMajor, + xDiagram); + else + AxisHelper::hideGrid(nDimensionIndex, nCooSysIndex, bMajor, xDiagram); +} + +bool isAxisVisible(const rtl::Reference<::chart::ChartModel>& xModel, AxisType eType) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(xDiagram.is()) + { + sal_Int32 nDimensionIndex = 0; + if (eType == AxisType::Y_MAIN || eType == AxisType::Y_SECOND) + nDimensionIndex = 1; + else if (eType == AxisType::Z_MAIN) + nDimensionIndex = 2; + + bool bMajor = (eType != AxisType::X_SECOND && eType != AxisType::Y_SECOND); + + bool bHasAxis = AxisHelper::isAxisShown(nDimensionIndex, bMajor, xDiagram); + return bHasAxis; + } + return false; +} + +void setAxisVisible(const rtl::Reference<::chart::ChartModel>& xModel, AxisType eType, bool bVisible) +{ + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(xModel)); + if(!xDiagram.is()) + return; + + sal_Int32 nDimensionIndex = 0; + if (eType == AxisType::Y_MAIN || eType == AxisType::Y_SECOND) + nDimensionIndex = 1; + else if (eType == AxisType::Z_MAIN) + nDimensionIndex = 2; + + bool bMajor = (eType != AxisType::X_SECOND && eType != AxisType::Y_SECOND); + + if (bVisible) + AxisHelper::showAxis(nDimensionIndex, bMajor, xDiagram, comphelper::getProcessComponentContext()); + else + AxisHelper::hideAxis(nDimensionIndex, bMajor, xDiagram); +} + +sal_Int32 getLegendPos(const css::uno::Reference& xModel) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return -1; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return -1; + + chart2::LegendPosition eLegendPos = chart2::LegendPosition_LINE_END; + xLegendProp->getPropertyValue("AnchorPosition") >>= eLegendPos; + switch(eLegendPos) + { + case chart2::LegendPosition_LINE_START: + return 3; + case chart2::LegendPosition_LINE_END: + return 0; + case chart2::LegendPosition_PAGE_START: + return 1; + case chart2::LegendPosition_PAGE_END: + return 2; + default: + return -1; + } +} + +void setLegendPos(const css::uno::Reference& xModel, sal_Int32 nPos) +{ + ChartModel* pModel = getChartModel(xModel); + if (!pModel) + return; + + rtl::Reference< Legend > xLegendProp = LegendHelper::getLegend(*pModel); + if (!xLegendProp.is()) + return; + + chart2::LegendPosition eLegendPos = chart2::LegendPosition_LINE_END; + css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH; + switch(nPos) + { + case 1: + eLegendPos = chart2::LegendPosition_PAGE_START; + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + case 3: + eLegendPos = chart2::LegendPosition_LINE_START; + break; + case 0: + eLegendPos = chart2::LegendPosition_LINE_END; + break; + case 2: + eLegendPos = chart2::LegendPosition_PAGE_END; + eExpansion = css::chart::ChartLegendExpansion_WIDE; + break; + default: + assert(false); + } + + xLegendProp->setPropertyValue("AnchorPosition", css::uno::Any(eLegendPos)); + xLegendProp->setPropertyValue("Expansion", css::uno::Any(eExpansion)); + xLegendProp->setPropertyValue("RelativePosition", uno::Any()); +} + +} + +ChartElementsPanel::ChartElementsPanel( + weld::Widget* pParent, ChartController* pController) + : PanelLayout(pParent, "ChartElementsPanel", "modules/schart/ui/sidebarelements.ui") + , mxCBTitle(m_xBuilder->weld_check_button("checkbutton_title")) + , mxEditTitle(m_xBuilder->weld_entry("edit_title")) + , mxCBSubtitle(m_xBuilder->weld_check_button("checkbutton_subtitle")) + , mxEditSubtitle(m_xBuilder->weld_entry("edit_subtitle")) + , mxCBXAxis(m_xBuilder->weld_check_button("checkbutton_x_axis")) + , mxCBXAxisTitle(m_xBuilder->weld_check_button("checkbutton_x_axis_title")) + , mxCBYAxis(m_xBuilder->weld_check_button("checkbutton_y_axis")) + , mxCBYAxisTitle(m_xBuilder->weld_check_button("checkbutton_y_axis_title")) + , mxCBZAxis(m_xBuilder->weld_check_button("checkbutton_z_axis")) + , mxCBZAxisTitle(m_xBuilder->weld_check_button("checkbutton_z_axis_title")) + , mxCB2ndXAxis(m_xBuilder->weld_check_button("checkbutton_2nd_x_axis")) + , mxCB2ndXAxisTitle(m_xBuilder->weld_check_button("checkbutton_2nd_x_axis_title")) + , mxCB2ndYAxis(m_xBuilder->weld_check_button("checkbutton_2nd_y_axis")) + , mxCB2ndYAxisTitle(m_xBuilder->weld_check_button("checkbutton_2nd_y_axis_title")) + , mxCBLegend(m_xBuilder->weld_check_button("checkbutton_legend")) + , mxCBLegendNoOverlay(m_xBuilder->weld_check_button("checkbutton_no_overlay")) + , mxCBGridVerticalMajor(m_xBuilder->weld_check_button("checkbutton_gridline_vertical_major")) + , mxCBGridHorizontalMajor(m_xBuilder->weld_check_button("checkbutton_gridline_horizontal_major")) + , mxCBGridVerticalMinor(m_xBuilder->weld_check_button("checkbutton_gridline_vertical_minor")) + , mxCBGridHorizontalMinor(m_xBuilder->weld_check_button("checkbutton_gridline_horizontal_minor")) + , mxTextTitle(m_xBuilder->weld_label("text_title")) + , mxTextSubTitle(m_xBuilder->weld_label("text_subtitle")) + , mxLBAxis(m_xBuilder->weld_label("label_axes")) + , mxLBGrid(m_xBuilder->weld_label("label_gri")) + , mxLBLegendPosition(m_xBuilder->weld_combo_box("comboboxtext_legend")) + , mxBoxLegend(m_xBuilder->weld_widget("box_legend")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) +{ + maTextTitle = mxTextTitle->get_label(); + maTextSubTitle = mxTextSubTitle->get_label(); + + Initialize(); +} + +ChartElementsPanel::~ChartElementsPanel() +{ + doUpdateModel(nullptr); + + mxCBTitle.reset(); + mxEditTitle.reset(); + mxCBSubtitle.reset(); + mxEditSubtitle.reset(); + mxCBXAxis.reset(); + mxCBXAxisTitle.reset(); + mxCBYAxis.reset(); + mxCBYAxisTitle.reset(); + mxCBZAxis.reset(); + mxCBZAxisTitle.reset(); + mxCB2ndXAxis.reset(); + mxCB2ndXAxisTitle.reset(); + mxCB2ndYAxis.reset(); + mxCB2ndYAxisTitle.reset(); + mxCBLegend.reset(); + mxCBLegendNoOverlay.reset(); + mxCBGridVerticalMajor.reset(); + mxCBGridHorizontalMajor.reset(); + mxCBGridVerticalMinor.reset(); + mxCBGridHorizontalMinor.reset(); + + mxLBLegendPosition.reset(); + mxBoxLegend.reset(); + + mxLBAxis.reset(); + mxLBGrid.reset(); + + mxTextTitle.reset(); + mxTextSubTitle.reset(); +} + +void ChartElementsPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + updateData(); + + Link aLink = LINK(this, ChartElementsPanel, CheckBoxHdl); + mxCBTitle->connect_toggled(aLink); + mxCBSubtitle->connect_toggled(aLink); + mxCBXAxis->connect_toggled(aLink); + mxCBXAxisTitle->connect_toggled(aLink); + mxCBYAxis->connect_toggled(aLink); + mxCBYAxisTitle->connect_toggled(aLink); + mxCBZAxis->connect_toggled(aLink); + mxCBZAxisTitle->connect_toggled(aLink); + mxCB2ndXAxis->connect_toggled(aLink); + mxCB2ndXAxisTitle->connect_toggled(aLink); + mxCB2ndYAxis->connect_toggled(aLink); + mxCB2ndYAxisTitle->connect_toggled(aLink); + mxCBLegend->connect_toggled(aLink); + mxCBLegendNoOverlay->connect_toggled(aLink); + mxCBGridVerticalMajor->connect_toggled(aLink); + mxCBGridHorizontalMajor->connect_toggled(aLink); + mxCBGridVerticalMinor->connect_toggled(aLink); + mxCBGridHorizontalMinor->connect_toggled(aLink); + + mxLBLegendPosition->connect_changed(LINK(this, ChartElementsPanel, LegendPosHdl)); + + Link aEditLink = LINK(this, ChartElementsPanel, EditHdl); + mxEditTitle->connect_changed(aEditLink); + mxEditSubtitle->connect_changed(aEditLink); +} + +namespace { + +rtl::Reference getChartType(const rtl::Reference& xModel) +{ + rtl::Reference xDiagram = xModel->getFirstChartDiagram(); + if (!xDiagram.is()) + return nullptr; + + const std::vector> & xCooSysSequence(xDiagram->getBaseCoordinateSystems()); + + if (xCooSysSequence.empty()) + return nullptr; + + const std::vector> & xChartTypeSequence(xCooSysSequence[0]->getChartTypes2()); + + if (xChartTypeSequence.empty()) + return nullptr; + + return xChartTypeSequence[0]; +} + +} + +void ChartElementsPanel::updateData() +{ + if (!mbModelValid) + return; + + rtl::Reference< Diagram > xDiagram(ChartModelHelper::findDiagram(mxModel)); + sal_Int32 nDimension = DiagramHelper::getDimension(xDiagram); + SolarMutexGuard aGuard; + + mxCBLegend->set_active(isLegendVisible(mxModel)); + mxCBLegendNoOverlay->set_sensitive(isLegendVisible(mxModel)); + mxCBLegendNoOverlay->set_active(!isLegendOverlay(mxModel)); + mxBoxLegend->set_sensitive(isLegendVisible(mxModel)); + + bool hasTitle = isTitleVisible(mxModel, TitleHelper::MAIN_TITLE); + mxCBTitle->set_active(hasTitle); + + OUString title = mxEditTitle->get_text(); + OUString newTitle = TitleHelper::getCompleteString(TitleHelper::getTitle(TitleHelper::MAIN_TITLE, mxModel)); + if (title != newTitle) + mxEditTitle->set_text(newTitle); + if (mxEditTitle->get_sensitive() != hasTitle) + mxEditTitle->set_sensitive(hasTitle); + + bool hasSubtitle = isTitleVisible(mxModel, TitleHelper::SUB_TITLE); + mxCBSubtitle->set_active(hasSubtitle); + + OUString subtitle = mxEditSubtitle->get_text(); + OUString newSubtitle = TitleHelper::getCompleteString(TitleHelper::getTitle(TitleHelper::SUB_TITLE, mxModel)); + if (subtitle != newSubtitle) + mxEditSubtitle->set_text(newSubtitle); + if (mxEditSubtitle->get_sensitive() != hasSubtitle) + mxEditSubtitle->set_sensitive(hasSubtitle); + + mxCBXAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::X_AXIS_TITLE)); + mxCBYAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::Y_AXIS_TITLE)); + mxCBZAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::Z_AXIS_TITLE)); + mxCB2ndXAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::SECONDARY_X_AXIS_TITLE)); + mxCB2ndYAxisTitle->set_active(isTitleVisible(mxModel, TitleHelper::SECONDARY_Y_AXIS_TITLE)); + mxCBGridVerticalMajor->set_active(isGridVisible(mxModel, GridType::VERT_MAJOR)); + mxCBGridHorizontalMajor->set_active(isGridVisible(mxModel, GridType::HOR_MAJOR)); + mxCBGridVerticalMinor->set_active(isGridVisible(mxModel, GridType::VERT_MINOR)); + mxCBGridHorizontalMinor->set_active(isGridVisible(mxModel, GridType::HOR_MINOR)); + mxCBXAxis->set_active(isAxisVisible(mxModel, AxisType::X_MAIN)); + mxCBYAxis->set_active(isAxisVisible(mxModel, AxisType::Y_MAIN)); + mxCBZAxis->set_active(isAxisVisible(mxModel, AxisType::Z_MAIN)); + mxCB2ndXAxis->set_active(isAxisVisible(mxModel, AxisType::X_SECOND)); + mxCB2ndYAxis->set_active(isAxisVisible(mxModel, AxisType::Y_SECOND)); + + bool bSupportsMainAxis = ChartTypeHelper::isSupportingMainAxis( + getChartType(mxModel), 0, 0); + if (bSupportsMainAxis) + { + mxCBXAxis->show(); + mxCBYAxis->show(); + mxCBZAxis->show(); + mxCBXAxisTitle->show(); + mxCBYAxisTitle->show(); + mxCBZAxisTitle->show(); + mxCBGridVerticalMajor->show(); + mxCBGridVerticalMinor->show(); + mxCBGridHorizontalMajor->show(); + mxCBGridHorizontalMinor->show(); + mxLBAxis->show(); + mxLBGrid->show(); + } + else + { + mxCBXAxis->hide(); + mxCBYAxis->hide(); + mxCBZAxis->hide(); + mxCBXAxisTitle->hide(); + mxCBYAxisTitle->hide(); + mxCBZAxisTitle->hide(); + mxCBGridVerticalMajor->hide(); + mxCBGridVerticalMinor->hide(); + mxCBGridHorizontalMajor->hide(); + mxCBGridHorizontalMinor->hide(); + mxLBAxis->hide(); + mxLBGrid->hide(); + } + + if (nDimension == 3) + { + mxCBZAxis->set_sensitive(true); + mxCBZAxisTitle->set_sensitive(true); + } + else + { + mxCBZAxis->set_sensitive(false); + mxCBZAxisTitle->set_sensitive(false); + } + + mxLBLegendPosition->set_active(getLegendPos(mxModel)); +} + +std::unique_ptr ChartElementsPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartElementsPanel::Create", nullptr, 0); + return std::make_unique(pParent, pController); +} + +void ChartElementsPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartElementsPanel::HandleContextChange( + const vcl::EnumContext& rContext) +{ + if(maContext == rContext) + { + // Nothing to do. + return; + } + + maContext = rContext; + updateData(); +} + +void ChartElementsPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartElementsPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); +} + +void ChartElementsPanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +IMPL_LINK(ChartElementsPanel, CheckBoxHdl, weld::Toggleable&, rCheckBox, void) +{ + bool bChecked = rCheckBox.get_active(); + if (&rCheckBox == mxCBTitle.get()) + setTitleVisible(TitleHelper::MAIN_TITLE, bChecked); + else if (&rCheckBox == mxCBSubtitle.get()) + setTitleVisible(TitleHelper::SUB_TITLE, bChecked); + else if (&rCheckBox == mxCBXAxis.get()) + setAxisVisible(mxModel, AxisType::X_MAIN, bChecked); + else if (&rCheckBox == mxCBXAxisTitle.get()) + setTitleVisible(TitleHelper::X_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBYAxis.get()) + setAxisVisible(mxModel, AxisType::Y_MAIN, bChecked); + else if (&rCheckBox == mxCBYAxisTitle.get()) + setTitleVisible(TitleHelper::Y_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBZAxis.get()) + setAxisVisible(mxModel, AxisType::Z_MAIN, bChecked); + else if (&rCheckBox == mxCBZAxisTitle.get()) + setTitleVisible(TitleHelper::Z_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCB2ndXAxis.get()) + setAxisVisible(mxModel, AxisType::X_SECOND, bChecked); + else if (&rCheckBox == mxCB2ndXAxisTitle.get()) + setTitleVisible(TitleHelper::SECONDARY_X_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCB2ndYAxis.get()) + setAxisVisible(mxModel, AxisType::Y_SECOND, bChecked); + else if (&rCheckBox == mxCB2ndYAxisTitle.get()) + setTitleVisible(TitleHelper::SECONDARY_Y_AXIS_TITLE, bChecked); + else if (&rCheckBox == mxCBLegend.get()) + { + mxBoxLegend->set_sensitive(bChecked); + mxCBLegendNoOverlay->set_sensitive(bChecked); + setLegendVisible(mxModel, bChecked); + } + else if (&rCheckBox == mxCBLegendNoOverlay.get()) + setLegendOverlay(mxModel, !bChecked); + else if (&rCheckBox == mxCBGridVerticalMajor.get()) + setGridVisible(mxModel, GridType::VERT_MAJOR, bChecked); + else if (&rCheckBox == mxCBGridHorizontalMajor.get()) + setGridVisible(mxModel, GridType::HOR_MAJOR, bChecked); + else if (&rCheckBox == mxCBGridVerticalMinor.get()) + setGridVisible(mxModel, GridType::VERT_MINOR, bChecked); + else if (&rCheckBox == mxCBGridHorizontalMinor.get()) + setGridVisible(mxModel, GridType::HOR_MINOR, bChecked); + + updateData(); +} + +IMPL_LINK(ChartElementsPanel, EditHdl, weld::Entry&, rEdit, void) +{ + // title or subtitle? + TitleHelper::eTitleType aTitleType = TitleHelper::MAIN_TITLE; + if (&rEdit == mxEditSubtitle.get()) + aTitleType = TitleHelper::SUB_TITLE; + + // set it + OUString aText(rEdit.get_text()); + TitleHelper::setCompleteString(aText, TitleHelper::getTitle(aTitleType, mxModel), comphelper::getProcessComponentContext()); +} + +IMPL_LINK_NOARG(ChartElementsPanel, LegendPosHdl, weld::ComboBox&, void) +{ + sal_Int32 nPos = mxLBLegendPosition->get_active(); + setLegendPos(mxModel, nPos); +} + +void ChartElementsPanel::setTitleVisible(TitleHelper::eTitleType eTitle, bool bVisible) +{ + if (bVisible) + { + OUString aText = eTitle == TitleHelper::SUB_TITLE ? maTextSubTitle : maTextTitle; + TitleHelper::createOrShowTitle(eTitle, aText, mxModel, comphelper::getProcessComponentContext()); + } + else + { + TitleHelper::hideTitle(eTitle, mxModel); + } +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartElementsPanel.hxx b/chart2/source/controller/sidebar/ChartElementsPanel.hxx new file mode 100644 index 000000000..07c7ee19c --- /dev/null +++ b/chart2/source/controller/sidebar/ChartElementsPanel.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include "ChartSidebarModifyListener.hxx" +#include + +namespace com::sun::star::util { class XModifyListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartElementsPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + // constructor/destructor + ChartElementsPanel( + weld::Widget* pParent, + ChartController* pController); + + virtual ~ChartElementsPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference xModel) override; + +private: + //ui controls + std::unique_ptr mxCBTitle; + std::unique_ptr mxEditTitle; + std::unique_ptr mxCBSubtitle; + std::unique_ptr mxEditSubtitle; + std::unique_ptr mxCBXAxis; + std::unique_ptr mxCBXAxisTitle; + std::unique_ptr mxCBYAxis; + std::unique_ptr mxCBYAxisTitle; + std::unique_ptr mxCBZAxis; + std::unique_ptr mxCBZAxisTitle; + std::unique_ptr mxCB2ndXAxis; + std::unique_ptr mxCB2ndXAxisTitle; + std::unique_ptr mxCB2ndYAxis; + std::unique_ptr mxCB2ndYAxisTitle; + std::unique_ptr mxCBLegend; + std::unique_ptr mxCBLegendNoOverlay; + std::unique_ptr mxCBGridVerticalMajor; + std::unique_ptr mxCBGridHorizontalMajor; + std::unique_ptr mxCBGridVerticalMinor; + std::unique_ptr mxCBGridHorizontalMinor; + std::unique_ptr mxTextTitle; + std::unique_ptr mxTextSubTitle; + std::unique_ptr mxLBAxis; + std::unique_ptr mxLBGrid; + + std::unique_ptr mxLBLegendPosition; + std::unique_ptr mxBoxLegend; + + vcl::EnumContext maContext; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxListener; + + bool mbModelValid; + + OUString maTextTitle; + OUString maTextSubTitle; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + void setTitleVisible(TitleHelper::eTitleType eTitle, bool bVisible); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(EditHdl, weld::Entry&, void); + DECL_LINK(LegendPosHdl, weld::ComboBox&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx b/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx new file mode 100644 index 000000000..e86fdf0fe --- /dev/null +++ b/chart2/source/controller/sidebar/ChartErrorBarPanel.cxx @@ -0,0 +1,425 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "ChartErrorBarPanel.hxx" +#include +#include +#include +#include + + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +enum class ErrorBarDirection +{ + POSITIVE, + NEGATIVE +}; + +css::uno::Reference getErrorBarPropSet( + const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + return ObjectIdentifier::getObjectPropertySet(rCID, xModel); +} + +bool showPositiveError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return false; + + css::uno::Any aAny = xPropSet->getPropertyValue("ShowPositiveError"); + + if (!aAny.hasValue()) + return false; + + bool bShow = false; + aAny >>= bShow; + return bShow; +} + +bool showNegativeError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return false; + + css::uno::Any aAny = xPropSet->getPropertyValue("ShowNegativeError"); + + if (!aAny.hasValue()) + return false; + + bool bShow = false; + aAny >>= bShow; + return bShow; +} + +void setShowPositiveError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bShow) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("ShowPositiveError", css::uno::Any(bShow)); +} + +void setShowNegativeError(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bShow) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + xPropSet->setPropertyValue("ShowNegativeError", css::uno::Any(bShow)); +} + +struct ErrorBarTypeMap +{ + sal_Int32 nPos; + sal_Int32 nApi; +}; + +ErrorBarTypeMap const aErrorBarType[] = { + { 0, css::chart::ErrorBarStyle::ABSOLUTE }, + { 1, css::chart::ErrorBarStyle::RELATIVE }, + { 2, css::chart::ErrorBarStyle::FROM_DATA }, + { 3, css::chart::ErrorBarStyle::STANDARD_DEVIATION }, + { 4, css::chart::ErrorBarStyle::STANDARD_ERROR }, + { 5, css::chart::ErrorBarStyle::VARIANCE}, + { 6, css::chart::ErrorBarStyle::ERROR_MARGIN }, +}; + +sal_Int32 getTypePos(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return 0; + + css::uno::Any aAny = xPropSet->getPropertyValue("ErrorBarStyle"); + + if (!aAny.hasValue()) + return 0; + + sal_Int32 nApi = 0; + aAny >>= nApi; + + for (ErrorBarTypeMap const & i : aErrorBarType) + { + if (i.nApi == nApi) + return i.nPos; + } + + return 0; +} + +void setTypePos(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + sal_Int32 nApi = 0; + for (ErrorBarTypeMap const & i : aErrorBarType) + { + if (i.nPos == nPos) + nApi = i.nApi; + } + + xPropSet->setPropertyValue("ErrorBarStyle", css::uno::Any(nApi)); +} + +double getValue(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, ErrorBarDirection eDir) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return 0; + + OUString aName = "PositiveError"; + if (eDir == ErrorBarDirection::NEGATIVE) + aName = "NegativeError"; + + css::uno::Any aAny = xPropSet->getPropertyValue(aName); + + if (!aAny.hasValue()) + return 0; + + double nVal = 0; + aAny >>= nVal; + + return nVal; +} + +void setValue(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, double nVal, ErrorBarDirection eDir) +{ + css::uno::Reference xPropSet = + getErrorBarPropSet(xModel, rCID); + + if (!xPropSet.is()) + return; + + OUString aName = "PositiveError"; + if (eDir == ErrorBarDirection::NEGATIVE) + aName = "NegativeError"; + + xPropSet->setPropertyValue(aName, css::uno::Any(nVal)); +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + assert(aAny.hasValue()); + OUString aCID; + aAny >>= aCID; +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_ERRORS_X && + eType != OBJECTTYPE_DATA_ERRORS_Y && + eType != OBJECTTYPE_DATA_ERRORS_Z) + SAL_WARN("chart2","Selected item is not an error bar"); + +#endif + + return aCID; +} + +} + +ChartErrorBarPanel::ChartErrorBarPanel(weld::Widget* pParent, ChartController* pController) + : PanelLayout(pParent, "ChartErrorBarPanel", "modules/schart/ui/sidebarerrorbar.ui") + , mxRBPosAndNeg(m_xBuilder->weld_radio_button("radiobutton_positive_negative")) + , mxRBPos(m_xBuilder->weld_radio_button("radiobutton_positive")) + , mxRBNeg(m_xBuilder->weld_radio_button("radiobutton_negative")) + , mxLBType(m_xBuilder->weld_combo_box("comboboxtext_type")) + , mxMFPos(m_xBuilder->weld_spin_button("spinbutton_pos")) + , mxMFNeg(m_xBuilder->weld_spin_button("spinbutton_neg")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartErrorBarPanel::~ChartErrorBarPanel() +{ + doUpdateModel(nullptr); + + mxRBPosAndNeg.reset(); + mxRBPos.reset(); + mxRBNeg.reset(); + + mxLBType.reset(); + + mxMFPos.reset(); + mxMFNeg.reset(); +} + +void ChartErrorBarPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + mxRBNeg->set_active(false); + mxRBPos->set_active(false); + mxRBPosAndNeg->set_active(false); + + updateData(); + + Link aLink = LINK(this, ChartErrorBarPanel, RadioBtnHdl); + mxRBPosAndNeg->connect_toggled(aLink); + mxRBPos->connect_toggled(aLink); + mxRBNeg->connect_toggled(aLink); + + mxLBType->connect_changed(LINK(this, ChartErrorBarPanel, ListBoxHdl)); + + Link aLink2 = LINK(this, ChartErrorBarPanel, NumericFieldHdl); + mxMFPos->connect_value_changed(aLink2); + mxMFNeg->connect_value_changed(aLink2); +} + +void ChartErrorBarPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_ERRORS_X && + eType != OBJECTTYPE_DATA_ERRORS_Y && + eType != OBJECTTYPE_DATA_ERRORS_Z) + return; + + bool bPos = showPositiveError(mxModel, aCID); + bool bNeg = showNegativeError(mxModel, aCID); + + SolarMutexGuard aGuard; + + if (bPos && bNeg) + mxRBPosAndNeg->set_active(true); + else if (bPos) + mxRBPos->set_active(true); + else if (bNeg) + mxRBNeg->set_active(true); + + sal_Int32 nTypePos = getTypePos(mxModel, aCID); + mxLBType->set_active(nTypePos); + + if (nTypePos <= 1) + { + if (bPos) + mxMFPos->set_sensitive(true); + else + mxMFPos->set_sensitive(false); + + if (bNeg) + mxMFNeg->set_sensitive(true); + else + mxMFNeg->set_sensitive(false); + + double nValPos = getValue(mxModel, aCID, ErrorBarDirection::POSITIVE); + double nValNeg = getValue(mxModel, aCID, ErrorBarDirection::NEGATIVE); + + mxMFPos->set_value(nValPos); + mxMFNeg->set_value(nValNeg); + } + else + { + mxMFPos->set_sensitive(false); + mxMFNeg->set_sensitive(false); + } +} + +std::unique_ptr ChartErrorBarPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartErrorBarPanel::Create", nullptr, 0); + return std::make_unique(pParent, pController); +} + +void ChartErrorBarPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartErrorBarPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartErrorBarPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartErrorBarPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartErrorBarPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); +} + +void ChartErrorBarPanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +IMPL_LINK_NOARG(ChartErrorBarPanel, RadioBtnHdl, weld::Toggleable&, void) +{ + OUString aCID = getCID(mxModel); + bool bPos = mxRBPosAndNeg->get_active() || mxRBPos->get_active(); + bool bNeg = mxRBPosAndNeg->get_active() || mxRBNeg->get_active(); + + setShowPositiveError(mxModel, aCID, bPos); + setShowNegativeError(mxModel, aCID, bNeg); +} + +IMPL_LINK_NOARG(ChartErrorBarPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + sal_Int32 nPos = mxLBType->get_active(); + + setTypePos(mxModel, aCID, nPos); +} + +IMPL_LINK(ChartErrorBarPanel, NumericFieldHdl, weld::SpinButton&, rMetricField, void) +{ + OUString aCID = getCID(mxModel); + double nVal = rMetricField.get_value(); + if (&rMetricField == mxMFPos.get()) + setValue(mxModel, aCID, nVal, ErrorBarDirection::POSITIVE); + else if (&rMetricField == mxMFNeg.get()) + setValue(mxModel, aCID, nVal, ErrorBarDirection::NEGATIVE); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx b/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx new file mode 100644 index 000000000..1613006b7 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartErrorBarPanel.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include +#include +#include +#include "ChartSidebarModifyListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } + +namespace chart { + +class ChartController; +class ChartModel; + +namespace sidebar { + +class ChartErrorBarPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartErrorBarPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartErrorBarPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference xModel) override; + +private: + //ui controls + std::unique_ptr mxRBPosAndNeg; + std::unique_ptr mxRBPos; + std::unique_ptr mxRBNeg; + + std::unique_ptr mxLBType; + + std::unique_ptr mxMFPos; + std::unique_ptr mxMFNeg; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(RadioBtnHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); + DECL_LINK(NumericFieldHdl, weld::SpinButton&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartLinePanel.cxx b/chart2/source/controller/sidebar/ChartLinePanel.cxx new file mode 100644 index 000000000..d9da9a298 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartLinePanel.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "ChartLinePanel.hxx" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace chart::sidebar { + +namespace { + +SvxLineStyleToolBoxControl* getLineStyleToolBoxControl(const ToolbarUnoDispatcher& rToolBoxColor) +{ + css::uno::Reference xController = rToolBoxColor.GetControllerForCommand(".uno:XLineStyle"); + SvxLineStyleToolBoxControl* pToolBoxLineStyleControl = dynamic_cast(xController.get()); + return pToolBoxLineStyleControl; +} + +SvxColorToolBoxControl* getColorToolBoxControl(const ToolbarUnoDispatcher& rToolBoxLineStyle) +{ + css::uno::Reference xController = rToolBoxLineStyle.GetControllerForCommand(".uno:XLineColor"); + SvxColorToolBoxControl* pToolBoxColorControl = dynamic_cast(xController.get()); + return pToolBoxColorControl; +} + +OUString getCID(const rtl::Reference<::chart::ChartModel>& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + { + xSelectionSupplier->select(css::uno::Any(OUString("CID/Page="))); + aAny = xSelectionSupplier->getSelection(); + } + + OUString aCID; + aAny >>= aCID; + + return aCID; +} + +css::uno::Reference getPropSet( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + OUString aCID = getCID(xModel); + css::uno::Reference xPropSet = + ObjectIdentifier::getObjectPropertySet(aCID, xModel); + + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType == OBJECTTYPE_DIAGRAM) + { + css::uno::Reference xDiagram( + xPropSet, css::uno::UNO_QUERY); + if (!xDiagram.is()) + return xPropSet; + + xPropSet.set(xDiagram->getWall()); + } + + return xPropSet; +} + +class PreventUpdate +{ +public: + explicit PreventUpdate(bool& bUpdate): + mbUpdate(bUpdate) + { + mbUpdate = false; + } + + ~PreventUpdate() + { + mbUpdate = true; + } + +private: + bool& mbUpdate; +}; + +} + +std::unique_ptr ChartLinePanel::Create( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw css::lang::IllegalArgumentException("no parent Window given to ChartAxisPanel::Create", nullptr, 0); + if (!rxFrame.is()) + throw css::lang::IllegalArgumentException("no XFrame given to ChartAxisPanel::Create", nullptr, 1); + + return std::make_unique(pParent, rxFrame, pController); +} + +ChartLinePanel::ChartLinePanel(weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController): + svx::sidebar::LinePropertyPanelBase(pParent, rxFrame), + mxModel(pController->getChartModel()), + mxListener(new ChartSidebarModifyListener(this)), + mxSelectionListener(new ChartSidebarSelectionListener(this)), + mbUpdate(true), + mbModelValid(true), + maLineColorWrapper(mxModel, getColorToolBoxControl(*mxColorDispatch), "LineColor"), + maLineStyleWrapper(mxModel, getLineStyleToolBoxControl(*mxLineStyleDispatch)) +{ + disableArrowHead(); + std::vector aAcceptedTypes { OBJECTTYPE_PAGE, OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DATA_SERIES, OBJECTTYPE_DATA_POINT, + OBJECTTYPE_TITLE, OBJECTTYPE_LEGEND, OBJECTTYPE_DATA_CURVE, + OBJECTTYPE_DATA_AVERAGE_LINE, OBJECTTYPE_AXIS}; + mxSelectionListener->setAcceptedTypes(std::move(aAcceptedTypes)); + Initialize(); +} + +ChartLinePanel::~ChartLinePanel() +{ + doUpdateModel(nullptr); +} + +void ChartLinePanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + SvxColorToolBoxControl* pToolBoxColor = getColorToolBoxControl(*mxColorDispatch); + pToolBoxColor->setColorSelectFunction(maLineColorWrapper); + + SvxLineStyleToolBoxControl* pToolBoxLineStyle = getLineStyleToolBoxControl(*mxLineStyleDispatch); + pToolBoxLineStyle->setLineStyleSelectFunction(maLineStyleWrapper); + + setMapUnit(MapUnit::Map100thMM); + updateData(); +} + +void ChartLinePanel::updateData() +{ + if (!mbUpdate || !mbModelValid) + return; + + SolarMutexGuard aGuard; + css::uno::Reference xPropSet = getPropSet(mxModel); + if (!xPropSet.is()) + return; + + sal_uInt16 nLineTransparence = 0; + xPropSet->getPropertyValue("LineTransparence") >>= nLineTransparence; + XLineTransparenceItem aLineTransparenceItem(nLineTransparence); + updateLineTransparence(false, true, &aLineTransparenceItem); + + sal_uInt32 nWidth = 0; + xPropSet->getPropertyValue("LineWidth") >>= nWidth; + XLineWidthItem aWidthItem(nWidth); + updateLineWidth(false, true, &aWidthItem); + + maLineStyleWrapper.updateData(); + maLineColorWrapper.updateData(); +} + +void ChartLinePanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartLinePanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +void ChartLinePanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + + css::uno::Reference oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + maLineStyleWrapper.updateModel(mxModel); + maLineColorWrapper.updateModel(mxModel); + + mxModel->addModifyListener(mxListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartLinePanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartLinePanel::setLineJoint(const XLineJointItem* pItem) +{ + css::uno::Reference xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + if (pItem) + xPropSet->setPropertyValue("LineJoint", css::uno::Any(pItem->GetValue())); +} + +void ChartLinePanel::setLineCap(const XLineCapItem* /*pItem*/) +{ +} + +void ChartLinePanel::setLineTransparency(const XLineTransparenceItem& rItem) +{ + css::uno::Reference xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + xPropSet->setPropertyValue("LineTransparence", css::uno::Any(rItem.GetValue())); +} + +void ChartLinePanel::setLineWidth(const XLineWidthItem& rItem) +{ + css::uno::Reference xPropSet = + getPropSet(mxModel); + + if (!xPropSet.is()) + return; + + PreventUpdate aPreventUpdate(mbUpdate); + xPropSet->setPropertyValue("LineWidth", css::uno::Any(rItem.GetValue())); +} + +void ChartLinePanel::updateLineWidth(bool bDisabled, bool bSetOrDefault, const SfxPoolItem* pItem) +{ + LinePropertyPanelBase::updateLineWidth(bDisabled, bSetOrDefault, pItem); + + SfxViewShell* pViewShell = SfxViewShell::Current(); + if (comphelper::LibreOfficeKit::isActive() && pViewShell) + { + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + (".uno:LineWidth=" + std::to_string(mnWidthCoreValue)).c_str()); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartLinePanel.hxx b/chart2/source/controller/sidebar/ChartLinePanel.hxx new file mode 100644 index 000000000..10bfd5a4c --- /dev/null +++ b/chart2/source/controller/sidebar/ChartLinePanel.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" +#include "ChartColorWrapper.hxx" + +class XLineCapItem; +class XLineDashItem; +class XLineEndItem; +class XLineJointItem; +class XLineStartItem; +class XLineStyleItem; +class XLineTransparenceItem; +class XLineWidthItem; + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartLinePanel : public svx::sidebar::LinePropertyPanelBase, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController); + + // constructor/destructor + ChartLinePanel( + weld::Widget* pParent, + const css::uno::Reference& rxFrame, + ChartController* pController); + + virtual ~ChartLinePanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference xModel) override; + + virtual void setLineWidth(const XLineWidthItem& rItem) override; + +protected: + + virtual void setLineTransparency(const XLineTransparenceItem& rItem) override; + virtual void setLineJoint(const XLineJointItem* pItem) override; + virtual void setLineCap(const XLineCapItem* pItem) override; + + virtual void updateLineWidth(bool bDisabled, bool bSetOrDefault, const SfxPoolItem* pItem) override; + +private: + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxListener; + rtl::Reference mxSelectionListener; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + bool mbUpdate; + bool mbModelValid; + ChartColorWrapper maLineColorWrapper; + ChartLineStyleWrapper maLineStyleWrapper; +}; + +} } // end of namespace svx::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSeriesPanel.cxx b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx new file mode 100644 index 000000000..c5b21ed5a --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSeriesPanel.cxx @@ -0,0 +1,474 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include "ChartSeriesPanel.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar { + +namespace { + +bool isDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return DataSeriesHelper::hasDataLabelsAtSeries(xSeries); +} + +void setDataLabelVisible(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID, bool bVisible) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + DataSeriesHelper::insertDataLabelsToSeriesAndAllPoints(xSeries); + else + DataSeriesHelper::deleteDataLabelsFromSeriesAndAllPoints(xSeries); +} + +struct LabelPlacementMap +{ + sal_Int32 nPos; + sal_Int32 nApi; +}; + +LabelPlacementMap const aLabelPlacementMap[] = { + { 0, css::chart::DataLabelPlacement::TOP }, + { 1, css::chart::DataLabelPlacement::BOTTOM }, + { 2, css::chart::DataLabelPlacement::CENTER }, + { 3, css::chart::DataLabelPlacement::OUTSIDE }, + { 4, css::chart::DataLabelPlacement::INSIDE }, + { 5, css::chart::DataLabelPlacement::NEAR_ORIGIN } +}; + +sal_Int32 getDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return 0; + + css::uno::Any aAny = xSeries->getPropertyValue("LabelPlacement"); + if (!aAny.hasValue()) + return 0; + + sal_Int32 nPlacement = 0; + aAny >>= nPlacement; + + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nApi == nPlacement) + return i.nPos; + } + + return 0; +} + +void setDataLabelPlacement(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, sal_Int32 nPos) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + sal_Int32 nApi = 0; + for (LabelPlacementMap const & i : aLabelPlacementMap) + { + if (i.nPos == nPos) + { + nApi = i.nApi; + break; + } + } + + xSeries->setPropertyValue("LabelPlacement", css::uno::Any(nApi)); +} + +bool isTrendlineVisible(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID) +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xRegressionCurveContainer.is()) + return false; + + return xRegressionCurveContainer->getRegressionCurves().hasElements(); +} + +void setTrendlineVisible(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bVisible) +{ + rtl::Reference< DataSeries > xRegressionCurveContainer = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xRegressionCurveContainer.is()) + return; + + if (bVisible) + { + RegressionCurveHelper::addRegressionCurve( + SvxChartRegress::Linear, + xRegressionCurveContainer); + } + else + RegressionCurveHelper::removeAllExceptMeanValueLine( + xRegressionCurveContainer ); + +} + +bool isErrorBarVisible(const rtl::Reference<::chart::ChartModel>& xModel, + const OUString& rCID, bool bYError) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return false; + + return StatisticsHelper::hasErrorBars(xSeries, bYError); +} + +void setErrorBarVisible(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bYError, bool bVisible) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return; + + if (bVisible) + { + StatisticsHelper::addErrorBars( xSeries, + css::chart::ErrorBarStyle::STANDARD_DEVIATION, + bYError); + } + else + { + StatisticsHelper::removeErrorBars( xSeries, bYError ); + } +} + +bool isPrimaryAxis(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return true; + + return DataSeriesHelper::getAttachedAxisIndex(xSeries) == 0; +} + +void setAttachedAxisType(const rtl::Reference<::chart::ChartModel>& + xModel, const OUString& rCID, bool bPrimary) +{ + const rtl::Reference xDataSeries = ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xDataSeries.is()) + return; + + rtl::Reference xDiagram = xModel->getFirstChartDiagram(); + DiagramHelper::attachSeriesToAxis(bPrimary, xDataSeries, xDiagram, comphelper::getProcessComponentContext()); +} + +rtl::Reference getChartType( + const rtl::Reference<::chart::ChartModel>& xModel) +{ + rtl::Reference xDiagram = xModel->getFirstChartDiagram(); + const std::vector< rtl::Reference< BaseCoordinateSystem > > & xCooSysSequence( xDiagram->getBaseCoordinateSystems()); + return xCooSysSequence[0]->getChartTypes2()[0]; +} + +OUString getSeriesLabel(const rtl::Reference<::chart::ChartModel>& xModel, const OUString& rCID) +{ + rtl::Reference< DataSeries > xSeries = + ObjectIdentifier::getDataSeriesForCID(rCID, xModel); + + if (!xSeries.is()) + return OUString(); + + rtl::Reference xChartType = getChartType(xModel); + return DataSeriesHelper::getDataSeriesLabel(xSeries, xChartType->getRoleOfSequenceForSeriesLabel()); +} + +OUString getCID(const css::uno::Reference& xModel) +{ + css::uno::Reference xController(xModel->getCurrentController()); + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return OUString(); + + uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + return OUString(); + + OUString aCID; + aAny >>= aCID; + + if (aCID.isEmpty()) + return OUString(); + +#if defined DBG_UTIL && !defined NDEBUG + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType != OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + SAL_WARN("chart2","Selected item is not a chart series"); +#endif + + return aCID; +} + +} + +ChartSeriesPanel::ChartSeriesPanel( + weld::Widget* pParent, + ChartController* pController) + : PanelLayout(pParent, "ChartSeriesPanel", "modules/schart/ui/sidebarseries.ui") + , mxCBLabel(m_xBuilder->weld_check_button("checkbutton_label")) + , mxCBTrendline(m_xBuilder->weld_check_button("checkbutton_trendline")) + , mxCBXError(m_xBuilder->weld_check_button("checkbutton_x_error")) + , mxCBYError(m_xBuilder->weld_check_button("checkbutton_y_error")) + , mxRBPrimaryAxis(m_xBuilder->weld_radio_button("radiobutton_primary_axis")) + , mxRBSecondaryAxis(m_xBuilder->weld_radio_button("radiobutton_secondary_axis")) + , mxBoxLabelPlacement(m_xBuilder->weld_widget("datalabel_box")) + , mxLBLabelPlacement(m_xBuilder->weld_combo_box("comboboxtext_label")) + , mxFTSeriesName(m_xBuilder->weld_label("label_series_name")) + , mxFTSeriesTemplate(m_xBuilder->weld_label("label_series_tmpl")) + , mxModel(pController->getChartModel()) + , mxListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this, OBJECTTYPE_DATA_SERIES)) + , mbModelValid(true) +{ + Initialize(); +} + +ChartSeriesPanel::~ChartSeriesPanel() +{ + doUpdateModel(nullptr); + + mxCBLabel.reset(); + mxCBTrendline.reset(); + mxCBXError.reset(); + mxCBYError.reset(); + + mxRBPrimaryAxis.reset(); + mxRBSecondaryAxis.reset(); + + mxBoxLabelPlacement.reset(); + mxLBLabelPlacement.reset(); + + mxFTSeriesName.reset(); + mxFTSeriesTemplate.reset(); +} + +void ChartSeriesPanel::Initialize() +{ + mxModel->addModifyListener(mxListener); + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + updateData(); + + Link aLink = LINK(this, ChartSeriesPanel, CheckBoxHdl); + mxCBLabel->connect_toggled(aLink); + mxCBTrendline->connect_toggled(aLink); + mxCBXError->connect_toggled(aLink); + mxCBYError->connect_toggled(aLink); + + Link aLink2 = LINK(this, ChartSeriesPanel, RadioBtnHdl); + mxRBPrimaryAxis->connect_toggled(aLink2); + mxRBSecondaryAxis->connect_toggled(aLink2); + + mxLBLabelPlacement->connect_changed(LINK(this, ChartSeriesPanel, ListBoxHdl)); +} + +void ChartSeriesPanel::updateData() +{ + if (!mbModelValid) + return; + + OUString aCID = getCID(mxModel); + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + if (eType!=OBJECTTYPE_DATA_SERIES && + eType != OBJECTTYPE_DATA_POINT && + eType != OBJECTTYPE_DATA_CURVE) + return; + + SolarMutexGuard aGuard; + bool bLabelVisible = isDataLabelVisible(mxModel, aCID); + mxCBLabel->set_active(bLabelVisible); + mxCBTrendline->set_active(isTrendlineVisible(mxModel, aCID)); + mxCBXError->set_active(isErrorBarVisible(mxModel, aCID, false)); + mxCBYError->set_active(isErrorBarVisible(mxModel, aCID, true)); + + bool bPrimaryAxis = isPrimaryAxis(mxModel, aCID); + mxRBPrimaryAxis->set_active(bPrimaryAxis); + mxRBSecondaryAxis->set_active(!bPrimaryAxis); + + mxBoxLabelPlacement->set_sensitive(bLabelVisible); + mxLBLabelPlacement->set_active(getDataLabelPlacement(mxModel, aCID)); + + OUString aFrameLabel = mxFTSeriesTemplate->get_label(); + aFrameLabel = aFrameLabel.replaceFirst("%1", getSeriesLabel(mxModel, aCID)); + mxFTSeriesName->set_label(aFrameLabel); +} + +std::unique_ptr ChartSeriesPanel::Create ( + weld::Widget* pParent, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException("no parent Window given to ChartSeriesPanel::Create", nullptr, 0); + + return std::make_unique(pParent, pController); +} + +void ChartSeriesPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartSeriesPanel::HandleContextChange( + const vcl::EnumContext& ) +{ + updateData(); +} + +void ChartSeriesPanel::NotifyItemUpdate( + sal_uInt16 /*nSID*/, + SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/ ) +{ +} + +void ChartSeriesPanel::modelInvalid() +{ + mbModelValid = false; +} + +void ChartSeriesPanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxListener); + } + + css::uno::Reference oldSelectionSupplier( + mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (oldSelectionSupplier.is()) { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxModel->addModifyListener(mxListener); + + css::uno::Reference xSelectionSupplier(mxModel->getCurrentController(), css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartSeriesPanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartSeriesPanel::selectionChanged(bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +IMPL_LINK(ChartSeriesPanel, CheckBoxHdl, weld::Toggleable&, rCheckBox, void) +{ + bool bChecked = rCheckBox.get_active(); + OUString aCID = getCID(mxModel); + if (&rCheckBox == mxCBLabel.get()) + setDataLabelVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBTrendline.get()) + setTrendlineVisible(mxModel, aCID, bChecked); + else if (&rCheckBox == mxCBXError.get()) + setErrorBarVisible(mxModel, aCID, false, bChecked); + else if (&rCheckBox == mxCBYError.get()) + setErrorBarVisible(mxModel, aCID, true, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, RadioBtnHdl, weld::Toggleable&, void) +{ + OUString aCID = getCID(mxModel); + bool bChecked = mxRBPrimaryAxis->get_active(); + + setAttachedAxisType(mxModel, aCID, bChecked); +} + +IMPL_LINK_NOARG(ChartSeriesPanel, ListBoxHdl, weld::ComboBox&, void) +{ + OUString aCID = getCID(mxModel); + + sal_Int32 nPos = mxLBLabelPlacement->get_active(); + setDataLabelPlacement(mxModel, aCID, nPos); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSeriesPanel.hxx b/chart2/source/controller/sidebar/ChartSeriesPanel.hxx new file mode 100644 index 000000000..b457667ec --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSeriesPanel.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" + +namespace com::sun::star::util { class XModifyListener; } +namespace com::sun::star::view { class XSelectionChangeListener; } + +namespace chart { + +class ChartController; + +namespace sidebar { + +class ChartSeriesPanel : public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static std::unique_ptr Create( + weld::Widget* pParent, + ChartController* pController); + + virtual void DataChanged( + const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange( + const vcl::EnumContext& rContext) override; + + virtual void NotifyItemUpdate( + const sal_uInt16 nSId, + const SfxItemState eState, + const SfxPoolItem* pState) override; + + virtual void GetControlState( + const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override {}; + + // constructor/destructor + ChartSeriesPanel( + weld::Widget* pParent, + ChartController* pController); + virtual ~ChartSeriesPanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void selectionChanged(bool bCorrectType) override; + + virtual void updateModel(css::uno::Reference xModel) override; + +private: + //ui controls + std::unique_ptr mxCBLabel; + std::unique_ptr mxCBTrendline; + std::unique_ptr mxCBXError; + std::unique_ptr mxCBYError; + + std::unique_ptr mxRBPrimaryAxis; + std::unique_ptr mxRBSecondaryAxis; + + std::unique_ptr mxBoxLabelPlacement; + std::unique_ptr mxLBLabelPlacement; + + std::unique_ptr mxFTSeriesName; + std::unique_ptr mxFTSeriesTemplate; + + rtl::Reference<::chart::ChartModel> mxModel; + css::uno::Reference mxListener; + css::uno::Reference mxSelectionListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(RadioBtnHdl, weld::Toggleable&, void); + DECL_LINK(ListBoxHdl, weld::ComboBox&, void); +}; + +} } // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx b/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx new file mode 100644 index 000000000..adee06ddd --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarModifyListener.cxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "ChartSidebarModifyListener.hxx" + +namespace chart::sidebar +{ +ChartSidebarModifyListenerParent::~ChartSidebarModifyListenerParent() {} + +ChartSidebarModifyListener::ChartSidebarModifyListener(ChartSidebarModifyListenerParent* pParent) + : mpParent(pParent) +{ +} + +ChartSidebarModifyListener::~ChartSidebarModifyListener() {} + +void ChartSidebarModifyListener::modified(const css::lang::EventObject& /*rEvent*/) +{ + if (mpParent) + mpParent->updateData(); +} + +void ChartSidebarModifyListener::disposing(const css::lang::EventObject& /*rEvent*/) +{ + if (!mpParent) + return; + + mpParent->modelInvalid(); + mpParent = nullptr; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx b/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx new file mode 100644 index 000000000..afcbbdab5 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarModifyListener.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +namespace chart::sidebar +{ +class ChartSidebarModifyListenerParent +{ +public: + virtual ~ChartSidebarModifyListenerParent(); + + virtual void updateData() = 0; + + virtual void modelInvalid() = 0; +}; + +class ChartSidebarModifyListener : public cppu::WeakImplHelper +{ +public: + explicit ChartSidebarModifyListener(ChartSidebarModifyListenerParent* pParent); + virtual ~ChartSidebarModifyListener() override; + + virtual void SAL_CALL modified(const css::lang::EventObject& rEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + +private: + ChartSidebarModifyListenerParent* mpParent; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx new file mode 100644 index 000000000..c3757a3b8 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "ChartSidebarSelectionListener.hxx" + +#include +#include + +#include + +namespace chart::sidebar { + +ChartSidebarSelectionListenerParent::~ChartSidebarSelectionListenerParent() +{ +} + +ChartSidebarSelectionListener::ChartSidebarSelectionListener( + ChartSidebarSelectionListenerParent* pParent): + mpParent(pParent) +{ +} + +ChartSidebarSelectionListener::ChartSidebarSelectionListener( + ChartSidebarSelectionListenerParent* pParent, + ObjectType eType): + mpParent(pParent) +{ + maTypes.push_back(eType); +} + +ChartSidebarSelectionListener::~ChartSidebarSelectionListener() +{ +} + +void ChartSidebarSelectionListener::selectionChanged(const css::lang::EventObject& rEvent) +{ + if (!mpParent) + return; + + bool bCorrectObjectSelected = false; + + css::uno::Reference xController(rEvent.Source, css::uno::UNO_QUERY); + if (xController.is()) + { + css::uno::Reference xSelectionSupplier(xController, css::uno::UNO_QUERY); + if (xSelectionSupplier.is()) + { + css::uno::Any aAny = xSelectionSupplier->getSelection(); + if (aAny.hasValue()) + { + OUString aCID; + aAny >>= aCID; + ObjectType eType = ObjectIdentifier::getObjectType(aCID); + bCorrectObjectSelected = std::any_of(maTypes.begin(), maTypes.end(), + [eType](const ObjectType& eTypeInVector) { return eType == eTypeInVector; }); + } + } + } + + mpParent->selectionChanged(bCorrectObjectSelected); +} + +void ChartSidebarSelectionListener::disposing(const css::lang::EventObject& /*rEvent*/) +{ + if (!mpParent) + return; + + mpParent = nullptr; +} + +void ChartSidebarSelectionListener::setAcceptedTypes(std::vector&& aTypes) +{ + maTypes = std::move(aTypes); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx new file mode 100644 index 000000000..e8cea5003 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartSidebarSelectionListener.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace chart::sidebar +{ +class ChartSidebarSelectionListenerParent +{ +public: + virtual ~ChartSidebarSelectionListenerParent(); + + virtual void selectionChanged(bool bSelected) = 0; +}; + +class ChartSidebarSelectionListener + : public cppu::WeakImplHelper +{ +public: + // listen to all chart selection changes + explicit ChartSidebarSelectionListener(ChartSidebarSelectionListenerParent* pParent); + // only listen to the changes of eType + ChartSidebarSelectionListener(ChartSidebarSelectionListenerParent* pParent, ObjectType eType); + virtual ~ChartSidebarSelectionListener() override; + + virtual void SAL_CALL selectionChanged(const css::lang::EventObject& rEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + + void setAcceptedTypes(std::vector&& aTypes); + +private: + ChartSidebarSelectionListenerParent* mpParent; + + std::vector maTypes; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartTypePanel.cxx b/chart2/source/controller/sidebar/ChartTypePanel.cxx new file mode 100644 index 000000000..9c5a7ba43 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartTypePanel.cxx @@ -0,0 +1,437 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartTypePanel.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace css; +using namespace css::uno; + +namespace chart::sidebar +{ +ChartTypePanel::ChartTypePanel(weld::Widget* pParent, ::chart::ChartController* pController) + : PanelLayout(pParent, "ChartTypePanel", "modules/schart/ui/sidebartype.ui") + , mxListener(new ChartSidebarModifyListener(this)) + , mbModelValid(true) + , m_pDim3DLookResourceGroup(new Dim3DLookResourceGroup(m_xBuilder.get())) + , m_pStackingResourceGroup(new StackingResourceGroup(m_xBuilder.get())) + , m_pSplineResourceGroup( + new SplineResourceGroup(m_xBuilder.get(), pController->GetChartFrame())) + , m_pGeometryResourceGroup(new GeometryResourceGroup(m_xBuilder.get())) + , m_pSortByXValuesResourceGroup(new SortByXValuesResourceGroup(m_xBuilder.get())) + , m_xChartModel(pController->getChartModel()) + , m_aChartTypeDialogControllerList(0) + , m_pCurrentMainType(nullptr) + , m_nChangingCalls(0) + , m_aTimerTriggeredControllerLock(m_xChartModel) + , m_xMainTypeList(m_xBuilder->weld_combo_box("cmb_chartType")) + , m_xSubTypeList(new ValueSet(m_xBuilder->weld_scrolled_window("subtypewin", true))) + , m_xSubTypeListWin(new weld::CustomWeld(*m_xBuilder, "subtype", *m_xSubTypeList)) +{ + Size aSize(m_xSubTypeList->GetDrawingArea()->get_ref_device().LogicToPixel( + Size(120, 40), MapMode(MapUnit::MapAppFont))); + m_xSubTypeListWin->set_size_request(aSize.Width(), aSize.Height()); + + m_xMainTypeList->connect_changed(LINK(this, ChartTypePanel, SelectMainTypeHdl)); + m_xSubTypeList->SetSelectHdl(LINK(this, ChartTypePanel, SelectSubTypeHdl)); + + m_xSubTypeList->SetStyle(m_xSubTypeList->GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER + | WB_NAMEFIELD | WB_FLATVALUESET | WB_3DLOOK); + m_xSubTypeList->SetColCount(4); + m_xSubTypeList->SetLineCount(1); + + bool bEnableComplexChartTypes = true; + uno::Reference xProps(static_cast(m_xChartModel.get()), + uno::UNO_QUERY); + if (xProps.is()) + { + try + { + xProps->getPropertyValue("EnableComplexChartTypes") >>= bEnableComplexChartTypes; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + } + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + if (bEnableComplexChartTypes) + { + m_aChartTypeDialogControllerList.push_back(std::make_unique()); + } + m_aChartTypeDialogControllerList.push_back( + std::make_unique()); + + for (auto const& elem : m_aChartTypeDialogControllerList) + { + m_xMainTypeList->append("", elem->getName(), elem->getImage()); + elem->setChangeListener(this); + } + + m_pDim3DLookResourceGroup->setChangeListener(this); + m_pStackingResourceGroup->setChangeListener(this); + m_pSplineResourceGroup->setChangeListener(this); + m_pGeometryResourceGroup->setChangeListener(this); + m_pSortByXValuesResourceGroup->setChangeListener(this); + + Initialize(); +} + +ChartTypePanel::~ChartTypePanel() +{ + doUpdateModel(nullptr); + + //delete all dialog controller + m_aChartTypeDialogControllerList.clear(); + + //delete all resource helpers + m_pDim3DLookResourceGroup.reset(); + m_pStackingResourceGroup.reset(); + m_pSplineResourceGroup.reset(); + m_pGeometryResourceGroup.reset(); + m_pSortByXValuesResourceGroup.reset(); + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); + + m_xSubTypeListWin.reset(); + m_xSubTypeList.reset(); + m_xMainTypeList.reset(); +} + +IMPL_LINK_NOARG(ChartTypePanel, SelectMainTypeHdl, weld::ComboBox&, void) { selectMainType(); } + +IMPL_LINK_NOARG(ChartTypePanel, SelectSubTypeHdl, ValueSet*, void) +{ + if (m_pCurrentMainType) + { + ChartTypeParameter aParameter(getCurrentParameter()); + m_pCurrentMainType->adjustParameterToSubType(aParameter); + fillAllControls(aParameter, false); + commitToModel(aParameter); + } +} + +void ChartTypePanel::Initialize() +{ + if (!m_xChartModel.is()) + return; + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + DiagramHelper::tTemplateWithServiceName aTemplate + = DiagramHelper::getTemplateForDiagram(xDiagram, xChartTypeManager); + OUString aServiceName(aTemplate.sServiceName); + + bool bFound = false; + + sal_uInt16 nM = 0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if (elem->isSubType(aServiceName)) + { + bFound = true; + + m_xMainTypeList->set_active(nM); + showAllControls(*elem); + uno::Reference xTemplateProps( + static_cast(aTemplate.xChartTypeTemplate.get()), + uno::UNO_QUERY); + ChartTypeParameter aParameter + = elem->getChartTypeParameterForService(aServiceName, xTemplateProps); + m_pCurrentMainType = getSelectedMainType(); + + //set ThreeDLookScheme + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) + >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls(aParameter); + if (m_pCurrentMainType) + m_pCurrentMainType->fillExtraControls(m_xChartModel, xTemplateProps); + break; + } + ++nM; + } + + if (!bFound) + { + m_xSubTypeList->Hide(); + m_pDim3DLookResourceGroup->showControls(false); + m_pStackingResourceGroup->showControls(false); + m_pSplineResourceGroup->showControls(false); + m_pGeometryResourceGroup->showControls(false); + m_pSortByXValuesResourceGroup->showControls(false); + } +} + +void ChartTypePanel::updateData() +{ + // Chart Type related + if (!m_xChartModel.is()) + return; + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager = m_xChartModel->getTypeManager(); + rtl::Reference xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + DiagramHelper::tTemplateWithServiceName aTemplate + = DiagramHelper::getTemplateForDiagram(xDiagram, xChartTypeManager); + OUString aServiceName(aTemplate.sServiceName); + + //sal_uInt16 nM = 0; + for (auto const& elem : m_aChartTypeDialogControllerList) + { + if (elem->isSubType(aServiceName)) + { + //m_pMainTypeList->SelectEntryPos(nM); + //m_pMainTypeList->select_entry_region(nM, nM); + break; + } + //++nM; + } +} + +void ChartTypePanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartTypePanel::HandleContextChange(const vcl::EnumContext& rContext) +{ + if (maContext == rContext) + { + // Nothing to do. + return; + } + + maContext = rContext; + updateData(); +} + +void ChartTypePanel::modelInvalid() { mbModelValid = false; } + +void ChartTypePanel::doUpdateModel(rtl::Reference<::chart::ChartModel> xModel) +{ + if (mbModelValid) + { + m_xChartModel->removeModifyListener(mxListener); + } + + m_xChartModel = xModel; + mbModelValid = m_xChartModel.is(); + + if (!mbModelValid) + return; + + m_xChartModel->addModifyListener(mxListener); +} + +void ChartTypePanel::updateModel(css::uno::Reference xModel) +{ + ::chart::ChartModel* pModel = dynamic_cast<::chart::ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +rtl::Reference<::chart::ChartTypeTemplate> ChartTypePanel::getCurrentTemplate() const +{ + if (m_pCurrentMainType && m_xChartModel.is()) + { + ChartTypeParameter aParameter(getCurrentParameter()); + m_pCurrentMainType->adjustParameterToSubType(aParameter); + rtl::Reference<::chart::ChartTypeManager> xChartTypeManager + = m_xChartModel->getTypeManager(); + return m_pCurrentMainType->getCurrentTemplate(aParameter, xChartTypeManager); + } + return nullptr; +} + +ChartTypeDialogController* ChartTypePanel::getSelectedMainType() +{ + ChartTypeDialogController* pTypeController = nullptr; + auto nM = static_cast::size_type>( + m_xMainTypeList->get_active()); + if (nM < m_aChartTypeDialogControllerList.size()) + pTypeController = m_aChartTypeDialogControllerList[nM].get(); + return pTypeController; +} + +void ChartTypePanel::showAllControls(ChartTypeDialogController& rTypeController) +{ + m_xMainTypeList->show(); + m_xSubTypeList->Show(); + + bool bShow = rTypeController.shouldShow_3DLookControl(); + m_pDim3DLookResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_StackingControl(); + m_pStackingResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_SplineControl(); + m_pSplineResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_GeometryControl(); + m_pGeometryResourceGroup->showControls(bShow); + bShow = rTypeController.shouldShow_SortByXValuesResourceGroup(); + m_pSortByXValuesResourceGroup->showControls(bShow); + rTypeController.showExtraControls(m_xBuilder.get()); +} + +void ChartTypePanel::fillAllControls(const ChartTypeParameter& rParameter, + bool bAlsoResetSubTypeList) +{ + m_nChangingCalls++; + if (m_pCurrentMainType && bAlsoResetSubTypeList) + { + m_pCurrentMainType->fillSubTypeList(*m_xSubTypeList, rParameter); + } + m_xSubTypeList->SelectItem(static_cast(rParameter.nSubTypeIndex)); + m_pDim3DLookResourceGroup->fillControls(rParameter); + m_pStackingResourceGroup->fillControls(rParameter); + m_pSplineResourceGroup->fillControls(rParameter); + m_pGeometryResourceGroup->fillControls(rParameter); + m_pSortByXValuesResourceGroup->fillControls(rParameter); + m_nChangingCalls--; +} + +ChartTypeParameter ChartTypePanel::getCurrentParameter() const +{ + ChartTypeParameter aParameter; + aParameter.nSubTypeIndex = static_cast(m_xSubTypeList->GetSelectedItemId()); + m_pDim3DLookResourceGroup->fillParameter(aParameter); + m_pStackingResourceGroup->fillParameter(aParameter); + m_pSplineResourceGroup->fillParameter(aParameter); + m_pGeometryResourceGroup->fillParameter(aParameter); + m_pSortByXValuesResourceGroup->fillParameter(aParameter); + return aParameter; +} + +void ChartTypePanel::stateChanged() +{ + if (m_nChangingCalls) + return; + m_nChangingCalls++; + + ChartTypeParameter aParameter(getCurrentParameter()); + if (m_pCurrentMainType) + { + m_pCurrentMainType->adjustParameterToSubType(aParameter); + m_pCurrentMainType->adjustSubTypeAndEnableControls(aParameter); + } + commitToModel(aParameter); + + //detect the new ThreeDLookScheme + rtl::Reference xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + aParameter.eThreeDLookScheme = ThreeDHelper::detectScheme(xDiagram); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + //the controls have to be enabled/disabled accordingly + fillAllControls(aParameter); + + m_nChangingCalls--; +} + +void ChartTypePanel::commitToModel(const ChartTypeParameter& rParameter) +{ + if (!m_pCurrentMainType) + return; + + m_aTimerTriggeredControllerLock.startTimer(); + m_pCurrentMainType->commitToModel(rParameter, m_xChartModel); +} + +void ChartTypePanel::selectMainType() +{ + ChartTypeParameter aParameter(getCurrentParameter()); + + if (m_pCurrentMainType) + { + m_pCurrentMainType->adjustParameterToSubType(aParameter); + m_pCurrentMainType->hideExtraControls(); + } + + m_pCurrentMainType = getSelectedMainType(); + if (!m_pCurrentMainType) + return; + + showAllControls(*m_pCurrentMainType); + + m_pCurrentMainType->adjustParameterToMainType(aParameter); + commitToModel(aParameter); + //detect the new ThreeDLookScheme + aParameter.eThreeDLookScheme + = ThreeDHelper::detectScheme(ChartModelHelper::findDiagram(m_xChartModel)); + if (!aParameter.b3DLook + && aParameter.eThreeDLookScheme != ThreeDLookScheme::ThreeDLookScheme_Realistic) + aParameter.eThreeDLookScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + + rtl::Reference xDiagram = ChartModelHelper::findDiagram(m_xChartModel); + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= aParameter.bSortByXValues; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + fillAllControls(aParameter); + uno::Reference xTemplateProps( + static_cast(getCurrentTemplate().get()), uno::UNO_QUERY); + m_pCurrentMainType->fillExtraControls(m_xChartModel, xTemplateProps); +} +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartTypePanel.hxx b/chart2/source/controller/sidebar/ChartTypePanel.hxx new file mode 100644 index 000000000..5555eba2f --- /dev/null +++ b/chart2/source/controller/sidebar/ChartTypePanel.hxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include "ChartSidebarModifyListener.hxx" +#include +#include +#include + +namespace com::sun::star::util +{ +class XModifyListener; +} + +namespace weld +{ +class CustomWeld; +} + +namespace chart +{ +class ChartController; +class Dim3DLookResourceGroup; +class StackingResourceGroup; +class SplineResourceGroup; +class GeometryResourceGroup; +class ChartTypeParameter; +class SortByXValuesResourceGroup; + +namespace sidebar +{ +class ChartTypePanel : public ResourceChangeListener, + public PanelLayout, + public ::sfx2::sidebar::IContextChangeReceiver, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartTypeTemplateProvider +{ +public: + virtual void DataChanged(const DataChangedEvent& rEvent) override; + + virtual void HandleContextChange(const vcl::EnumContext& rContext) override; + + // constructor/destructor + ChartTypePanel(weld::Widget* pParent, ::chart::ChartController* pController); + + virtual ~ChartTypePanel() override; + + virtual void updateData() override; + virtual void modelInvalid() override; + + virtual void updateModel(css::uno::Reference xModel) override; + + virtual rtl::Reference<::chart::ChartTypeTemplate> getCurrentTemplate() const override; + +private: + ChartTypeDialogController* getSelectedMainType(); + void showAllControls(ChartTypeDialogController& rTypeController); + void fillAllControls(const ChartTypeParameter& rParameter, bool bAlsoResetSubTypeList = true); + ChartTypeParameter getCurrentParameter() const; + + virtual void stateChanged() override; + + void commitToModel(const ChartTypeParameter& rParameter); + void selectMainType(); + + DECL_LINK(SelectMainTypeHdl, weld::ComboBox&, void); + DECL_LINK(SelectSubTypeHdl, ValueSet*, void); + + vcl::EnumContext maContext; + + css::uno::Reference mxListener; + + bool mbModelValid; + + void Initialize(); + void doUpdateModel(rtl::Reference<::chart::ChartModel> xModel); + + std::unique_ptr m_pDim3DLookResourceGroup; + std::unique_ptr m_pStackingResourceGroup; + std::unique_ptr m_pSplineResourceGroup; + std::unique_ptr m_pGeometryResourceGroup; + std::unique_ptr m_pSortByXValuesResourceGroup; + + rtl::Reference<::chart::ChartModel> m_xChartModel; + + std::vector> m_aChartTypeDialogControllerList; + ChartTypeDialogController* m_pCurrentMainType; + + sal_Int32 m_nChangingCalls; + + TimerTriggeredControllerLock m_aTimerTriggeredControllerLock; + + std::unique_ptr m_xMainTypeList; + std::unique_ptr m_xSubTypeList; + std::unique_ptr m_xSubTypeListWin; +}; +} +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/uitest/uiobject.cxx b/chart2/source/controller/uitest/uiobject.cxx new file mode 100644 index 000000000..5081f00c7 --- /dev/null +++ b/chart2/source/controller/uitest/uiobject.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +ChartUIObject::ChartUIObject(const VclPtr& xChartWindow, + const OUString& rCID): + maCID(rCID), + mxChartWindow(xChartWindow) +{ +} + +StringMap ChartUIObject::get_state() +{ + StringMap aMap; + aMap["CID"] = maCID; + + return aMap; +} + +void ChartUIObject::execute(const OUString& rAction, + const StringMap& rParameters) +{ + if (rAction == "SELECT") + { + std::unique_ptr pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + StringMap aParams; + aParams["NAME"] = maCID; + pWindow->execute(rAction, aParams); + } + else if (rAction == "COMMAND") + { + // first select object + std::unique_ptr pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + StringMap aParams; + aParams["NAME"] = maCID; + pWindow->execute("SELECT", aParams); + + auto itr = rParameters.find("COMMAND"); + if (itr == rParameters.end()) + throw css::uno::RuntimeException("missing COMMAND parameter"); + + maCommands.emplace_back(new OUString(itr->second)); + OUString* pCommand = maCommands.rbegin()->get(); + + Application::PostUserEvent(LINK(this, ChartUIObject, PostCommand), pCommand); + } +} + +IMPL_LINK(ChartUIObject, PostCommand, void*, pCommand, void) +{ + css::util::URL aURL; + aURL.Path = *static_cast(pCommand); + mxChartWindow->GetController()->dispatch(aURL, css::uno::Sequence()); +} + +std::unique_ptr ChartUIObject::get_child(const OUString& rID) +{ + std::unique_ptr pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + return pWindow->get_child(rID); +} + +std::set ChartUIObject::get_children() const +{ + std::unique_ptr pWindow = mxChartWindow->GetUITestFactory()(mxChartWindow.get()); + + return pWindow->get_children(); +} + +OUString ChartUIObject::get_type() const +{ + return "ChartUIObject for type: "; +} + +ChartWindowUIObject::ChartWindowUIObject(const VclPtr& xChartWindow): + WindowUIObject(xChartWindow), + mxChartWindow(xChartWindow) +{ +} + +StringMap ChartWindowUIObject::get_state() +{ + StringMap aMap = WindowUIObject::get_state(); + + chart::ChartController* pController = mxChartWindow->GetController(); + if (pController) + { + css::uno::Any aAny = pController->getSelection(); + OUString aSelectedObject; + aAny >>= aSelectedObject; + aMap["SelectedObject"] = aSelectedObject; + } + + return aMap; +} + +void ChartWindowUIObject::execute(const OUString& rAction, + const StringMap& rParameters) +{ + if (rAction == "SELECT") + { + auto itr = rParameters.find("NAME"); + if (itr == rParameters.end()) + throw css::uno::RuntimeException("Missing Parameter 'NAME' for action 'SELECT'"); + + + const OUString& rName = itr->second; + css::uno::Any aAny; + aAny <<= rName; + + chart::ChartController* pController = mxChartWindow->GetController(); + pController->select(aAny); + } + else + WindowUIObject::execute(rAction, rParameters); +} + +std::unique_ptr ChartWindowUIObject::get_child(const OUString& rID) +{ + if (chart::ObjectIdentifier::isCID(rID)) + return std::unique_ptr(new ChartUIObject(mxChartWindow, rID)); + + throw css::uno::RuntimeException("unknown child"); +} + +namespace { + +void recursiveAdd(chart::ObjectIdentifier const & rID, std::set& rChildren, const chart::ObjectHierarchy& rHierarchy) +{ + std::vector aChildIdentifiers = rHierarchy.getChildren(rID); + std::transform(aChildIdentifiers.begin(), aChildIdentifiers.end(), std::inserter(rChildren, rChildren.begin()), + [](const chart::ObjectIdentifier& rObject) + { + return rObject.getObjectCID(); + } + ); + + for (const chart::ObjectIdentifier& ID: aChildIdentifiers) + recursiveAdd(ID, rChildren, rHierarchy); +} + +} + +std::set ChartWindowUIObject::get_children() const +{ + std::set aChildren; + + chart::ChartController* pController = mxChartWindow->GetController(); + if (!pController) + return aChildren; + + rtl::Reference<::chart::ChartModel> xChartDoc( pController->getChartModel() ); + + css::uno::Reference xChartView = pController->getChartView(); + chart::ExplicitValueProvider* pValueProvider = comphelper::getFromUnoTunnel( xChartView ); + chart::ObjectHierarchy aHierarchy(xChartDoc, pValueProvider); + chart::ObjectIdentifier aIdentifier = chart::ObjectHierarchy::getRootNodeOID(); + aChildren.insert(aIdentifier.getObjectCID()); + + recursiveAdd(aIdentifier, aChildren, aHierarchy); + + return aChildren; +} + +std::unique_ptr ChartWindowUIObject::create(vcl::Window* pWindow) +{ + chart::ChartWindow* pChartWindow = dynamic_cast(pWindow); + assert(pChartWindow); + + return std::unique_ptr(new ChartWindowUIObject(pChartWindow)); +} + +OUString ChartWindowUIObject::get_name() const +{ + return "ChartWindowUIObject"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/Axis.hxx b/chart2/source/inc/Axis.hxx new file mode 100644 index 000000000..7b5ce75fa --- /dev/null +++ b/chart2/source/inc/Axis.hxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" +#include "charttoolsdllapi.hxx" + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XAxis, + css::chart2::XTitled, + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + Axis_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS Axis final : + public cppu::BaseMutex, + public impl::Axis_Base, + public ::property::OPropertySet +{ +public: + explicit Axis(); + virtual ~Axis() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +private: + explicit Axis( const Axis & rOther ); + + // late initialization to call after copy-constructing + void Init(); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + +public: + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XAxis ____ + virtual void SAL_CALL setScaleData( const css::chart2::ScaleData& rScaleData ) override; + virtual css::chart2::ScaleData SAL_CALL getScaleData() override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getGridProperties() override; + virtual css::uno::Sequence< css::uno::Reference< css::beans::XPropertySet > > SAL_CALL getSubGridProperties() override; + virtual css::uno::Sequence< css::uno::Reference< css::beans::XPropertySet > > SAL_CALL getSubTickProperties() override; + + // ____ XTitled ____ + virtual css::uno::Reference< css::chart2::XTitle > SAL_CALL getTitleObject() override; + virtual void SAL_CALL setTitleObject( + const css::uno::Reference< css::chart2::XTitle >& Title ) override; + + // ____ XCloneable ____ + // Note: the coordinate systems are not cloned! + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + + void AllocateSubGrids(); + + rtl::Reference m_xModifyEventForwarder; + + css::chart2::ScaleData m_aScaleData; + + css::uno::Reference< css::beans::XPropertySet > m_xGrid; + + css::uno::Sequence< css::uno::Reference< css::beans::XPropertySet > > m_aSubGridProperties; + + css::uno::Reference< css::chart2::XTitle > m_xTitle; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/AxisHelper.hxx b/chart2/source/inc/AxisHelper.hxx new file mode 100644 index 000000000..cd51d5adb --- /dev/null +++ b/chart2/source/inc/AxisHelper.hxx @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" +#include +#include + +#include + +namespace chart { class ChartModel; } +namespace chart { class ExplicitCategoriesProvider; } +namespace chart { class ReferenceSizeProvider; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XScaling; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class Axis; +class BaseCoordinateSystem; +class ChartType; +class Diagram; + +class OOO_DLLPUBLIC_CHARTTOOLS AxisHelper +{ +public: + static css::uno::Reference< css::chart2::XScaling > createLinearScaling(); + static css::uno::Reference< css::chart2::XScaling > createLogarithmicScaling( double fBase = 10.0 ); + + static css::chart2::ScaleData createDefaultScale(); + + static void removeExplicitScaling( css::chart2::ScaleData& rScaleData ); + + static bool isLogarithmic( const css::uno::Reference< css::chart2::XScaling >& xScaling ); + + static void checkDateAxis( css::chart2::ScaleData& rScale, ExplicitCategoriesProvider* pExplicitCategoriesProvider, bool bChartTypeAllowsDateAxis ); + static css::chart2::ScaleData getDateCheckedScale( const rtl::Reference< ::chart::Axis >& xAxis, ChartModel& rModel ); + + static sal_Int32 getExplicitNumberFormatKeyForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCorrespondingCoordinateSystem + , const rtl::Reference< ::chart::ChartModel>& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ); + static sal_Int32 getExplicitNumberFormatKeyForAxis( + const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCorrespondingCoordinateSystem + , const rtl::Reference< ::chart::ChartModel>& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ); + + static rtl::Reference< ::chart::Axis > + createAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram + , const css::uno::Reference< css::uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider = nullptr ); + + static rtl::Reference< ::chart::Axis > + createAxis( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex // 0==main or 1==secondary axis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , const css::uno::Reference< css::uno::XComponentContext > & xContext + , ReferenceSizeProvider * pRefSizeProvider = nullptr ); + + static void showAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram + , const css::uno::Reference< css::uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider = nullptr ); + + static void showGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static void hideAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + static void hideGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static bool isAxisShown( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + static bool isGridShown( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static void makeAxisVisible( const rtl::Reference< ::chart::Axis >& xAxis ); + static void makeGridVisible( const css::uno::Reference< css::beans::XPropertySet >& xGridProperties ); + + static void makeAxisInvisible( const rtl::Reference< ::chart::Axis >& xAxis ); + static void makeGridInvisible( const css::uno::Reference< css::beans::XPropertySet >& xGridProperties ); + + static void hideAxisIfNoDataIsAttached( const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram); + + SAL_DLLPRIVATE static bool areAxisLabelsVisible( const css::uno::Reference< css::beans::XPropertySet >& xAxisProperties ); + static bool isAxisVisible( const css::uno::Reference< css::chart2::XAxis >& xAxis ); + static bool isGridVisible( const css::uno::Reference< css::beans::XPropertySet >& xGridProperties ); + + static rtl::Reference< ::chart::BaseCoordinateSystem > + getCoordinateSystemByIndex( + const rtl::Reference< ::chart::Diagram >& xDiagram + , sal_Int32 nIndex ); + + static rtl::Reference< ::chart::BaseCoordinateSystem > + getCoordinateSystemOfAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + static rtl::Reference< ::chart::BaseCoordinateSystem > + getCoordinateSystemOfAxis( + const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static rtl::Reference< ::chart::Axis > + getAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + static rtl::Reference< ::chart::Axis > + getAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + + static rtl::Reference< ::chart::Axis > + getCrossingMainAxis( const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + static rtl::Reference< ::chart::Axis > + getCrossingMainAxis( const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + + static rtl::Reference< ::chart::Axis > + getParallelAxis( const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static css::uno::Reference< css::beans::XPropertySet > + getGridProperties( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex //0: Primary axis, 1: secondary axis + , sal_Int32 nSubGridIndex //-1: Main Grid; 0: First SubGrid etc + ); + + static sal_Int32 getDimensionIndexOfAxis( + const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static bool getIndicesForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ); + static bool getIndicesForAxis( + const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ); + + static bool getIndicesForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ); + static bool getIndicesForAxis( + const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ); + + /** @param bOnlyVisible if , only axes with property "Show" set to + are returned + */ + static std::vector< rtl::Reference< ::chart::Axis > > + getAllAxesOfDiagram( const rtl::Reference< ::chart::Diagram >& xDiagram + , bool bOnlyVisible = false ); + + /** @param bOnlyVisible if
, only axes with property "Show" set to + are returned + */ + SAL_DLLPRIVATE static std::vector< rtl::Reference< ::chart::Axis > > + getAllAxesOfCoordinateSystem( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , bool bOnlyVisible = false ); + + static css::uno::Sequence< css::uno::Reference< css::beans::XPropertySet > > + getAllGrids( const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static void getAxisOrGridPossibilities( css::uno::Sequence< sal_Bool >& rPossibilityList + , const rtl::Reference< ::chart::Diagram>& xDiagram, bool bAxis=true ); + + static void getAxisOrGridExistence( css::uno::Sequence< sal_Bool >& rExistenceList + , const rtl::Reference< ::chart::Diagram>& xDiagram, bool bAxis=true ); + + static bool changeVisibilityOfGrids( const rtl::Reference< ::chart::Diagram>& xDiagram + , const css::uno::Sequence< sal_Bool >& rOldExistenceList + , const css::uno::Sequence< sal_Bool >& rNewExistenceList ); + + static bool changeVisibilityOfAxes( const rtl::Reference< ::chart::Diagram>& xDiagram + , const css::uno::Sequence< sal_Bool >& rOldExistenceList + , const css::uno::Sequence< sal_Bool >& rNewExistenceList + , const css::uno::Reference< css::uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ); + + static bool shouldAxisBeDisplayed( const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + static bool isSecondaryYAxisNeeded( const rtl::Reference< + ::chart::BaseCoordinateSystem >& xCooSys ); + + static rtl::Reference< ::chart::ChartType > + getChartTypeByIndex( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys, + sal_Int32 nIndex ); + + static void setRTLAxisLayout( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + + static rtl::Reference< ::chart::ChartType > + getFirstChartTypeWithSeriesAttachedToAxisIndex( const rtl::Reference< ::chart::Diagram >& xDiagram, const sal_Int32 nAttachedAxisIndex ); + + static bool isAxisPositioningEnabled(); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/AxisIndexDefines.hxx b/chart2/source/inc/AxisIndexDefines.hxx new file mode 100644 index 000000000..5e6d32d69 --- /dev/null +++ b/chart2/source/inc/AxisIndexDefines.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +const sal_Int32 MAIN_AXIS_INDEX = 0; +const sal_Int32 SECONDARY_AXIS_INDEX = 1; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/BaseCoordinateSystem.hxx b/chart2/source/inc/BaseCoordinateSystem.hxx new file mode 100644 index 000000000..89c5eca50 --- /dev/null +++ b/chart2/source/inc/BaseCoordinateSystem.hxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" + +#include + +namespace chart +{ +class Axis; +class ChartType; + +namespace impl +{ +typedef ::cppu::WeakImplHelper + < css::lang::XServiceInfo, + css::chart2::XCoordinateSystem, + css::chart2::XChartTypeContainer, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + BaseCoordinateSystem_Base; +} + +class SAL_DLLPUBLIC_RTTI BaseCoordinateSystem : + public impl::BaseCoordinateSystem_Base, + public cppu::BaseMutex, + public ::property::OPropertySet +{ +public: + BaseCoordinateSystem( sal_Int32 nDimensionCount ); + explicit BaseCoordinateSystem( const BaseCoordinateSystem & rSource ); + virtual ~BaseCoordinateSystem() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + + // ____ XCoordinateSystem ____ + virtual ::sal_Int32 SAL_CALL getDimension() override; + virtual void SAL_CALL setAxisByDimension( + ::sal_Int32 nDimension, + const css::uno::Reference< css::chart2::XAxis >& xAxis, + ::sal_Int32 nIndex ) override; + virtual css::uno::Reference< css::chart2::XAxis > SAL_CALL getAxisByDimension( + ::sal_Int32 nDimension, ::sal_Int32 nIndex ) override; + virtual ::sal_Int32 SAL_CALL getMaximumAxisIndexByDimension( ::sal_Int32 nDimension ) override; + + // ____ XChartTypeContainer ____ + virtual void SAL_CALL addChartType( + const css::uno::Reference< css::chart2::XChartType >& aChartType ) override; + virtual void SAL_CALL removeChartType( + const css::uno::Reference< css::chart2::XChartType >& aChartType ) override; + virtual css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > > SAL_CALL getChartTypes() override; + virtual void SAL_CALL setChartTypes( + const css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > >& aChartTypes ) final override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + void setAxisByDimension( sal_Int32 nDimension, const rtl::Reference< ::chart::Axis >& xAxis, sal_Int32 nIndex ); + const rtl::Reference< ::chart::Axis > & getAxisByDimension2(sal_Int32 nDimension, sal_Int32 nIndex ) const; + + void setChartTypes( const std::vector< rtl::Reference< ::chart::ChartType > >& aChartTypes ); + const std::vector< rtl::Reference<::chart::ChartType > > & getChartTypes2() const { return m_aChartTypes; } + +protected: + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + +protected: + rtl::Reference m_xModifyEventForwarder; + +private: + sal_Int32 m_nDimensionCount; + typedef std::vector< std::vector< rtl::Reference< ::chart::Axis > > > tAxisVecVecType; + tAxisVecVecType m_aAllAxis; //outer sequence is the dimension; inner sequence is the axis index that indicates main or secondary axis + std::vector< rtl::Reference<::chart::ChartType > > m_aChartTypes; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/BaseGFXHelper.hxx b/chart2/source/inc/BaseGFXHelper.hxx new file mode 100644 index 000000000..18481031e --- /dev/null +++ b/chart2/source/inc/BaseGFXHelper.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::awt { struct Rectangle; } +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } + +namespace chart::BaseGFXHelper +{ + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DRange getBoundVolume( const css::drawing::PolyPolygonShape3D& rPolyPoly ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DRange getBoundVolume( const std::vector>& rPolyPoly ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B2IRectangle makeRectangle( + const css::awt::Point& rPosition, + const css::awt::Size& rSize ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B2IRectangle makeRectangle( const css::awt::Rectangle& rRect ); + +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Point B2IRectangleToAWTPoint( + const ::basegfx::B2IRectangle& rB2IRectangle ); + +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Size B2IRectangleToAWTSize( + const ::basegfx::B2IRectangle& rB2IRectangle ); + +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Rectangle toAwtRectangle(const basegfx::B2IRectangle& rB2IRectangle); + +::basegfx::B3DVector Direction3DToB3DVector( + const css::drawing::Direction3D& rDirection ); + +css::drawing::Direction3D B3DVectorToDirection3D( + const ::basegfx::B3DVector& rB3DVector ); + +::basegfx::B3DVector Position3DToB3DVector( + const css::drawing::Position3D& rPosition ); + +css::drawing::Position3D B3DVectorToPosition3D( + const ::basegfx::B3DVector& rB3DVector ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DHomMatrix HomogenMatrixToB3DHomMatrix( + const css::drawing::HomogenMatrix & rHomogenMatrix ); + +OOO_DLLPUBLIC_CHARTTOOLS +css::drawing::HomogenMatrix B3DHomMatrixToHomogenMatrix( + const ::basegfx::B3DHomMatrix & rB3DMatrix ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DTuple GetRotationFromMatrix( + const ::basegfx::B3DHomMatrix & rB3DMatrix ); + +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DTuple GetScaleFromMatrix( + const ::basegfx::B3DHomMatrix & rB3DMatrix ); + +void ReduceToRotationMatrix( ::basegfx::B3DHomMatrix & rB3DMatrix ); + +} // namespace chart::BaseGFXHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/CachedDataSequence.hxx b/chart2/source/inc/CachedDataSequence.hxx new file mode 100644 index 000000000..e9c1b9d50 --- /dev/null +++ b/chart2/source/inc/CachedDataSequence.hxx @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +// helper classes +#include +#include +#include +#include +#include + +// interfaces and types +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::chart2::data::XDataSequence, + css::chart2::data::XNumericalDataSequence, + css::chart2::data::XTextualDataSequence, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::lang::XInitialization, + css::lang::XServiceInfo > + CachedDataSequence_Base; +} + +/** + * This sequence object does store actual values within, hence "cached". + */ +class CachedDataSequence final : + public ::comphelper::OMutexAndBroadcastHelper, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper< CachedDataSequence >, + public impl::CachedDataSequence_Base +{ +public: + /** constructs an empty sequence + */ + CachedDataSequence(); + + explicit CachedDataSequence( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + + /** creates a sequence and initializes it with the given string. This is + especially useful for labels, which only have one element. + */ + explicit CachedDataSequence( const OUString & rSingleText ); + + /// Copy CTOR + explicit CachedDataSequence( const CachedDataSequence & rSource ); + + virtual ~CachedDataSequence() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +private: + // ____ XPropertySet ____ + /// @see css::beans::XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + /// @see ::comphelper::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + /// @see ::comphelper::OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // ____ XDataSequence ____ + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getData() override; + virtual OUString SAL_CALL getSourceRangeRepresentation() override; + virtual css::uno::Sequence< OUString > SAL_CALL generateLabel( + css::chart2::data::LabelOrigin nLabelOrigin ) override; + virtual ::sal_Int32 SAL_CALL getNumberFormatKeyByIndex( ::sal_Int32 nIndex ) override; + + // ____ XNumericalDataSequence ____ + /// @see css::chart::data::XNumericalDataSequence + virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override; + + // ____ XTextualDataSequence ____ + /// @see css::chart::data::XTextualDataSequence + virtual css::uno::Sequence< OUString > SAL_CALL getTextualData() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // css::lang::XInitialization: + virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override; + + // + sal_Int32 m_nNumberFormatKey; + OUString m_sRole; + // + + enum DataType + { + NUMERICAL, + TEXTUAL, + MIXED + }; + + /** This method registers all properties. It should be called by all + constructors. + */ + void registerProperties(); + + /** is used by interface method getNumericalData(). + */ + css::uno::Sequence< double > Impl_getNumericalData() const; + /** is used by interface method getTextualData(). + */ + css::uno::Sequence< OUString > Impl_getTextualData() const; + /** is used by interface method getData(). + */ + css::uno::Sequence< css::uno::Any > Impl_getMixedData() const; + + enum DataType m_eCurrentDataType; + + css::uno::Sequence< double > m_aNumericalSequence; + css::uno::Sequence< OUString > m_aTextualSequence; + css::uno::Sequence< css::uno::Any > m_aMixedSequence; + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChangingResource.hxx b/chart2/source/inc/ChangingResource.hxx new file mode 100644 index 000000000..bde5b0923 --- /dev/null +++ b/chart2/source/inc/ChangingResource.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +namespace chart +{ +class ChangingResource; +class ResourceChangeListener +{ +public: + virtual void stateChanged() = 0; + virtual ~ResourceChangeListener(); +}; + +class ChangingResource +{ +public: + ChangingResource(); + virtual ~ChangingResource(); + + void setChangeListener(ResourceChangeListener* pListener); + +protected: + ResourceChangeListener* m_pChangeListener; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/CharacterProperties.hxx b/chart2/source/inc/CharacterProperties.hxx new file mode 100644 index 000000000..4dd7a4fbd --- /dev/null +++ b/chart2/source/inc/CharacterProperties.hxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyHelper.hxx" +#include "FastPropertyIdRanges.hxx" +#include "charttoolsdllapi.hxx" +#include + +#include + +namespace com::sun::star::beans { class XMultiPropertySet; } +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements services +// com.sun.star.style.CharacterProperties +// com.sun.star.style.CharacterPropertiesAsian +// com.sun.star.style.CharacterPropertiesComplex +namespace CharacterProperties +{ + // FastProperty Ids for properties + enum + { + // com.sun.star.style.CharacterProperties + PROP_CHAR_FONT_NAME = FAST_PROPERTY_ID_START_CHAR_PROP, // ? + PROP_CHAR_FONT_STYLE_NAME, + PROP_CHAR_FONT_FAMILY, + PROP_CHAR_FONT_CHAR_SET, + PROP_CHAR_FONT_PITCH, + PROP_CHAR_COLOR, +// PROP_CHAR_BACKGROUND_COLOR, +// PROP_CHAR_BACKGROUND_TRANSPARENCY, alpha channel in COLOR + PROP_CHAR_ESCAPEMENT, + PROP_CHAR_CHAR_HEIGHT, + PROP_CHAR_UNDERLINE, + PROP_CHAR_UNDERLINE_COLOR, + PROP_CHAR_UNDERLINE_HAS_COLOR, + PROP_CHAR_OVERLINE, + PROP_CHAR_OVERLINE_COLOR, + PROP_CHAR_OVERLINE_HAS_COLOR, + PROP_CHAR_WEIGHT, + PROP_CHAR_POSTURE, + PROP_CHAR_AUTO_KERNING, + PROP_CHAR_KERNING, +// PROP_CHAR_CASE_MAPPING, +// PROP_CHAR_ROTATION, +//-- PROP_CHAR_ROTATION_IS_FIT_TO_LINE, +// PROP_CHAR_SCALE_WIDTH, + PROP_CHAR_ESCAPEMENT_HEIGHT, + +// PROP_CHAR_CROSSED_OUT, + PROP_CHAR_STRIKE_OUT, + PROP_CHAR_WORD_MODE, +// PROP_CHAR_FLASH, + PROP_CHAR_LOCALE, +//-- PROP_CHAR_KEEP_TOGETHER, +//-- PROP_CHAR_NO_LINE_BREAK, + PROP_CHAR_SHADOWED, + PROP_CHAR_CONTOURED, + PROP_CHAR_RELIEF, +//-- PROP_CHAR_COMBINE_IS_ON, +//-- PROP_CHAR_COMBINE_PREFIX, +//-- PROP_CHAR_COMBINE_SUFFIX, + + PROP_CHAR_EMPHASIS, +// PROP_CHAR_RUBY_TEXT, +// PROP_CHAR_RUBY_ADJUST, +// PROP_CHAR_RUBY_STYLE_NAME, +// PROP_CHAR_RUBY_IS_ABOVE, +// PROP_CHAR_INHIBIT_HYPHENATION, + + // Asian (com.sun.star.style.CharacterPropertiesAsian) + PROP_CHAR_ASIAN_FONT_NAME, + PROP_CHAR_ASIAN_FONT_STYLE_NAME, + PROP_CHAR_ASIAN_FONT_FAMILY, + PROP_CHAR_ASIAN_CHAR_SET, + PROP_CHAR_ASIAN_FONT_PITCH, + PROP_CHAR_ASIAN_CHAR_HEIGHT, + PROP_CHAR_ASIAN_WEIGHT, + PROP_CHAR_ASIAN_POSTURE, + PROP_CHAR_ASIAN_LOCALE, +//-- PROP_CHAR_ASIAN_USE_SCRIPT_TYPE_DISTANCE, +//-- PROP_CHAR_ASIAN_USE_FORBIDDEN_RULES, +//-- PROP_CHAR_ASIAN_HANGING_PUNCTUATION_ALLOWED, + + // Complex Text Layout (com.sun.star.style.CharacterPropertiesComplex) + PROP_CHAR_COMPLEX_FONT_NAME, + PROP_CHAR_COMPLEX_FONT_STYLE_NAME, + PROP_CHAR_COMPLEX_FONT_FAMILY, + PROP_CHAR_COMPLEX_CHAR_SET, + PROP_CHAR_COMPLEX_FONT_PITCH, + PROP_CHAR_COMPLEX_CHAR_HEIGHT, + PROP_CHAR_COMPLEX_WEIGHT, + PROP_CHAR_COMPLEX_POSTURE, + PROP_CHAR_COMPLEX_LOCALE, + PROP_PARA_IS_CHARACTER_DISTANCE, + + PROP_WRITING_MODE, + + // don't use + FAST_PROPERTY_ID_END_CHAR_PROP + }; + + OOO_DLLPUBLIC_CHARTTOOLS void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + OOO_DLLPUBLIC_CHARTTOOLS void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); + + OOO_DLLPUBLIC_CHARTTOOLS bool IsCharacterPropertyHandle( sal_Int32 nHandle ); + + OOO_DLLPUBLIC_CHARTTOOLS css::awt::FontDescriptor createFontDescriptorFromPropertySet( + const css::uno::Reference< css::beans::XMultiPropertySet > & xMultiPropSet ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartModelHelper.hxx b/chart2/source/inc/ChartModelHelper.hxx new file mode 100644 index 000000000..c15b9a95a --- /dev/null +++ b/chart2/source/inc/ChartModelHelper.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "charttoolsdllapi.hxx" +#include + +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2::data { class XDataProvider; } +namespace com::sun::star::chart2::data { class XRangeHighlighter; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ +class BaseCoordinateSystem; +class ChartType; +class DataSeries; +class Diagram; +class InternalDataProvider; + +class OOO_DLLPUBLIC_CHARTTOOLS ChartModelHelper +{ +public: + static css::uno::Reference< css::chart2::data::XRangeHighlighter > createRangeHighlighter( + const rtl::Reference< ::chart::ChartModel >& xSelectionSupplier ); + + static rtl::Reference< InternalDataProvider > createInternalDataProvider( + const rtl::Reference<::chart::ChartModel>& xChartDoc, bool bConnectToModel ); + + static rtl::Reference< Diagram > + findDiagram( const rtl::Reference< ::chart::ChartModel >& xModel ); + + static rtl::Reference< ::chart::BaseCoordinateSystem > + getFirstCoordinateSystem( const rtl::Reference<::chart::ChartModel>& xModel ); + + static std::vector< rtl::Reference< ::chart::DataSeries > > + getDataSeries( const rtl::Reference< ::chart::ChartModel > & xModel ); + + static rtl::Reference< ChartType > + getChartTypeOfSeries( + const rtl::Reference<::chart::ChartModel>& xModel + , const css::uno::Reference< css::chart2::XDataSeries >& xGivenDataSeries ); + + static rtl::Reference< ChartType > + getChartTypeOfSeries( + const rtl::Reference<::chart::ChartModel>& xModel + , const rtl::Reference< ::chart::DataSeries >& xGivenDataSeries ); + + static css::awt::Size getDefaultPageSize(); + + static css::awt::Size getPageSize( const rtl::Reference<::chart::ChartModel>& xModel ); + + static void triggerRangeHighlighting( const rtl::Reference<::chart::ChartModel>& xModel ); + + static bool isIncludeHiddenCells( const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static bool setIncludeHiddenCells( bool bIncludeHiddenCells, ChartModel& rModel); + +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartResourceGroupDlgs.hxx b/chart2/source/inc/ChartResourceGroupDlgs.hxx new file mode 100644 index 000000000..e54585488 --- /dev/null +++ b/chart2/source/inc/ChartResourceGroupDlgs.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace chart +{ +class ChartTypeParameter; + +class SplinePropertiesDialog final : public weld::GenericDialogController +{ +public: + explicit SplinePropertiesDialog(weld::Window* pParent); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter, bool bSmoothLines); + +private: + DECL_LINK(SplineTypeListBoxHdl, weld::ComboBox&, void); + +private: + std::unique_ptr m_xLB_Spline_Type; + std::unique_ptr m_xMF_SplineResolution; + std::unique_ptr m_xFT_SplineOrder; + std::unique_ptr m_xMF_SplineOrder; +}; + +class SteppedPropertiesDialog final : public weld::GenericDialogController +{ +public: + explicit SteppedPropertiesDialog(weld::Window* pParent); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter, bool bSteppedLines); + +private: + std::unique_ptr m_xRB_Start; + std::unique_ptr m_xRB_End; + std::unique_ptr m_xRB_CenterX; + std::unique_ptr m_xRB_CenterY; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartResourceGroups.hxx b/chart2/source/inc/ChartResourceGroups.hxx new file mode 100644 index 000000000..8c263a7a6 --- /dev/null +++ b/chart2/source/inc/ChartResourceGroups.hxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "res_BarGeometry.hxx" +#include "ChangingResource.hxx" +#include "ChartTypeDialogController.hxx" +#include "ChartResourceGroupDlgs.hxx" + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +class SplinePropertiesDialog; +class SteppedPropertiesDialog; + +enum +{ + POS_3DSCHEME_SIMPLE = 0, + POS_3DSCHEME_REALISTIC = 1 +}; + +class Dim3DLookResourceGroup final : public ChangingResource +{ +public: + explicit Dim3DLookResourceGroup(weld::Builder* pBuilder); + + void showControls(bool bShow); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter); + +private: + DECL_LINK(Dim3DLookCheckHdl, weld::Toggleable&, void); + DECL_LINK(SelectSchemeHdl, weld::ComboBox&, void); + +private: + std::unique_ptr m_xCB_3DLook; + std::unique_ptr m_xLB_Scheme; +}; + +class SortByXValuesResourceGroup final : public ChangingResource +{ +public: + explicit SortByXValuesResourceGroup(weld::Builder* pBuilder); + + void showControls(bool bShow); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter); + +private: + DECL_LINK(SortByXValuesCheckHdl, weld::Toggleable&, void); + +private: + std::unique_ptr m_xCB_XValueSorting; +}; + +class StackingResourceGroup final : public ChangingResource +{ +public: + explicit StackingResourceGroup(weld::Builder* pBuilder); + + void showControls(bool bShow); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter); + +private: + DECL_LINK(StackingChangeHdl, weld::Toggleable&, void); + DECL_LINK(StackingEnableHdl, weld::Toggleable&, void); + +private: + std::unique_ptr m_xCB_Stacked; + std::unique_ptr m_xRB_Stack_Y; + std::unique_ptr m_xRB_Stack_Y_Percent; + std::unique_ptr m_xRB_Stack_Z; +}; + +#define POS_LINETYPE_STRAIGHT 0 +#define POS_LINETYPE_SMOOTH 1 +#define POS_LINETYPE_STEPPED 2 + +class SplineResourceGroup final : public ChangingResource +{ +public: + explicit SplineResourceGroup(weld::Builder* pBuilder, weld::Window* pParent); + + void showControls(bool bShow); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter); + +private: + DECL_LINK(LineTypeChangeHdl, weld::ComboBox&, void); + DECL_LINK(SplineDetailsDialogHdl, weld::Button&, void); + DECL_LINK(SteppedDetailsDialogHdl, weld::Button&, void); + SplinePropertiesDialog& getSplinePropertiesDialog(); + SteppedPropertiesDialog& getSteppedPropertiesDialog(); + +private: + weld::Window* m_pParent; + std::unique_ptr m_xFT_LineType; + std::unique_ptr m_xLB_LineType; + std::unique_ptr m_xPB_DetailsDialog; + std::unique_ptr m_xSplinePropertiesDialog; + std::unique_ptr m_xSteppedPropertiesDialog; +}; + +class GeometryResourceGroup final : public ChangingResource +{ +public: + explicit GeometryResourceGroup(weld::Builder* pBuilder); + + void showControls(bool bShow); + + void fillControls(const ChartTypeParameter& rParameter); + void fillParameter(ChartTypeParameter& rParameter); + +private: + DECL_LINK(GeometryChangeHdl, weld::TreeView&, void); + +private: + BarGeometryResources m_aGeometryResources; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartType.hxx b/chart2/source/inc/ChartType.hxx new file mode 100644 index 000000000..9821fdb6f --- /dev/null +++ b/chart2/source/inc/ChartType.hxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "charttoolsdllapi.hxx" + +namespace chart +{ +class BaseCoordinateSystem; +class DataSeries; +class ModifyEventForwarder; + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::chart2::XChartType, + css::chart2::XDataSeriesContainer, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + ChartType_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS ChartType : + public cppu::BaseMutex, + public impl::ChartType_Base, + public ::property::OPropertySet +{ +public: + explicit ChartType(); + virtual ~ChartType() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + + explicit ChartType( const ChartType & rOther ); + + // ____ XChartType ____ + // still abstract ! implement ! + virtual OUString SAL_CALL getChartType() override = 0; + virtual css::uno::Reference< css::chart2::XCoordinateSystem > SAL_CALL + createCoordinateSystem( ::sal_Int32 DimensionCount ) final override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedMandatoryRoles() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedOptionalRoles() override; + virtual OUString SAL_CALL getRoleOfSequenceForSeriesLabel() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedPropertyRoles() override; + + // ____ XDataSeriesContainer ____ + virtual void SAL_CALL addDataSeries( + const css::uno::Reference< css::chart2::XDataSeries >& aDataSeries ) override; + virtual void SAL_CALL removeDataSeries( + const css::uno::Reference< css::chart2::XDataSeries >& aDataSeries ) override; + virtual css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > > SAL_CALL getDataSeries() override; + virtual void SAL_CALL setDataSeries( + const css::uno::Sequence< css::uno::Reference< css::chart2::XDataSeries > >& aDataSeries ) override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + virtual rtl::Reference cloneChartType() const = 0; + + void addDataSeries( + const rtl::Reference< ::chart::DataSeries >& aDataSeries ); + void removeDataSeries( + const rtl::Reference< ::chart::DataSeries >& aDataSeries ); + void setDataSeries( + const std::vector< rtl::Reference< ::chart::DataSeries > >& aDataSeries ); + const std::vector< rtl::Reference< ::chart::DataSeries > > & getDataSeries2() const { return m_aDataSeries; } + + virtual rtl::Reference< ::chart::BaseCoordinateSystem > + createCoordinateSystem2( sal_Int32 DimensionCount ); + +protected: + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + void fireModifyEvent(); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + rtl::Reference m_xModifyEventForwarder; + +private: + void impl_addDataSeriesWithoutNotification( + const rtl::Reference< ::chart::DataSeries >& aDataSeries ); + +private: + typedef + std::vector< rtl::Reference< ::chart::DataSeries > > tDataSeriesContainerType; + + // --- mutable members: the following members need mutex guard --- + + tDataSeriesContainerType m_aDataSeries; + + bool m_bNotifyChanges; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartTypeDialogController.hxx b/chart2/source/inc/ChartTypeDialogController.hxx new file mode 100644 index 000000000..4c03ff269 --- /dev/null +++ b/chart2/source/inc/ChartTypeDialogController.hxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include "ChangingResource.hxx" +#include "ThreeDHelper.hxx" + +#include +#include + +namespace com::sun::star::beans +{ +class XPropertySet; +} +namespace com::sun::star::chart2 +{ +class XChartDocument; +} +namespace com::sun::star::lang +{ +class XMultiServiceFactory; +} + +class ValueSet; + +namespace chart +{ +class ChartModel; +class ChartTypeTemplate; +class ChartTypeManager; + +enum GlobalStackMode +{ + GlobalStackMode_NONE, + GlobalStackMode_STACK_Y, + GlobalStackMode_STACK_Y_PERCENT, + GlobalStackMode_STACK_Z +}; + +class ChartTypeParameter +{ +public: + ChartTypeParameter(sal_Int32 nSubTypeIndex, bool bXAxisWithValues = false, bool b3DLook = false, + GlobalStackMode eStackMode = GlobalStackMode_NONE, bool _bSymbols = true, + bool _bLines = true, + css::chart2::CurveStyle eCurveStyle = css::chart2::CurveStyle_LINES); + ChartTypeParameter(); + + bool mapsToSameService(const ChartTypeParameter& rParameter) const; + bool mapsToSimilarService(const ChartTypeParameter& rParameter, + sal_Int32 nTheHigherTheLess) const; + + sal_Int32 nSubTypeIndex; //starting with 1 + + bool bXAxisWithValues; + bool b3DLook; + bool bSymbols; + bool bLines; + + GlobalStackMode eStackMode; + css::chart2::CurveStyle eCurveStyle; + + sal_Int32 nCurveResolution; + sal_Int32 nSplineOrder; + + sal_Int32 nGeometry3D; + + ThreeDLookScheme eThreeDLookScheme; + bool bSortByXValues; + + bool mbRoundedEdge; +}; + +typedef std::map tTemplateServiceChartTypeParameterMap; + +class ChartTypeDialogController : public ChangingResource +{ +public: + ChartTypeDialogController(); + virtual ~ChartTypeDialogController() override; + + virtual OUString getName() = 0; + virtual OUString getImage() = 0; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const = 0; + virtual void fillSubTypeList(ValueSet& rSubTypeList, const ChartTypeParameter& rParameter); + + virtual bool shouldShow_3DLookControl() const; + virtual bool shouldShow_StackingControl() const; + virtual bool shouldShow_SplineControl() const; + virtual bool shouldShow_GeometryControl() const; + virtual bool shouldShow_SortByXValuesResourceGroup() const; + + virtual void showExtraControls(weld::Builder* pBuilder); + virtual void hideExtraControls() const; + virtual void + fillExtraControls(const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& xTemplateProps) const; + /// @throws css::uno::RuntimeException + virtual void setTemplateProperties( + const css::uno::Reference& xTemplateProps) const; + + bool isSubType(const OUString& rServiceName); + ChartTypeParameter getChartTypeParameterForService( + const OUString& rServiceName, + const css::uno::Reference& xTemplateProps); + virtual void adjustSubTypeAndEnableControls( + ChartTypeParameter& + rParameter); //if you have different counts of subtypes you may need to adjust the index + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter); + virtual void adjustParameterToMainType(ChartTypeParameter& rParameter); + OUString getServiceNameForParameter(const ChartTypeParameter& rParameter) const; + void commitToModel(const ChartTypeParameter& rParameter, + const rtl::Reference<::chart::ChartModel>& xChartModel); + rtl::Reference<::chart::ChartTypeTemplate> + getCurrentTemplate(const ChartTypeParameter& rParameter, + const rtl::Reference<::chart::ChartTypeManager>& xTemplateManager) const; + +protected: + bool bSupportsXAxisWithValues; + bool bSupports3D; +}; + +class ColumnOrBarChartDialogController_Base : public ChartTypeDialogController +{ +public: + ColumnOrBarChartDialogController_Base(); + virtual ~ColumnOrBarChartDialogController_Base() override; + + virtual bool shouldShow_3DLookControl() const override; + virtual bool shouldShow_GeometryControl() const override; + + virtual void adjustSubTypeAndEnableControls(ChartTypeParameter& rParameter) override; +}; + +class ColumnChartDialogController final : public ColumnOrBarChartDialogController_Base +{ +public: + ColumnChartDialogController(); + virtual ~ColumnChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; +}; + +class BarChartDialogController final : public ColumnOrBarChartDialogController_Base +{ +public: + BarChartDialogController(); + virtual ~BarChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; +}; + +class PieChartDialogController final : public ChartTypeDialogController +{ +public: + PieChartDialogController(); + virtual ~PieChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + + virtual bool shouldShow_3DLookControl() const override; +}; + +class LineChartDialogController final : public ChartTypeDialogController +{ +public: + LineChartDialogController(); + virtual ~LineChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + virtual void adjustParameterToMainType(ChartTypeParameter& rParameter) override; + + virtual bool shouldShow_StackingControl() const override; + virtual bool shouldShow_SplineControl() const override; +}; + +class XYChartDialogController final : public ChartTypeDialogController +{ +public: + XYChartDialogController(); + virtual ~XYChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + + virtual bool shouldShow_SplineControl() const override; + virtual bool shouldShow_SortByXValuesResourceGroup() const override; +}; + +class AreaChartDialogController final : public ChartTypeDialogController +{ +public: + AreaChartDialogController(); + virtual ~AreaChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + virtual void adjustParameterToMainType(ChartTypeParameter& rParameter) override; + + virtual bool shouldShow_3DLookControl() const override; +}; + +class NetChartDialogController final : public ChartTypeDialogController +{ +public: + NetChartDialogController(); + virtual ~NetChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + + virtual bool shouldShow_StackingControl() const override; +}; + +class StockChartDialogController final : public ChartTypeDialogController +{ +public: + StockChartDialogController(); + virtual ~StockChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; +}; + +class CombiColumnLineChartDialogController final : public ChartTypeDialogController +{ +public: + CombiColumnLineChartDialogController(); + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; + + virtual void showExtraControls(weld::Builder* pBuilder) override; + virtual void hideExtraControls() const override; + virtual void fillExtraControls( + const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::uno::Reference& xTemplateProps) const override; + + virtual void setTemplateProperties( + const css::uno::Reference& xTemplateProps) const override; + +private: + DECL_LINK(ChangeLineCountHdl, weld::SpinButton&, void); + +private: + std::unique_ptr m_xFT_NumberOfLines; + std::unique_ptr m_xMF_NumberOfLines; +}; + +class BubbleChartDialogController final : public ChartTypeDialogController +{ +public: + BubbleChartDialogController(); + virtual ~BubbleChartDialogController() override; + + virtual OUString getName() override; + virtual OUString getImage() override; + virtual const tTemplateServiceChartTypeParameterMap& getTemplateMap() const override; + virtual void fillSubTypeList(ValueSet& rSubTypeList, + const ChartTypeParameter& rParameter) override; + virtual void adjustParameterToSubType(ChartTypeParameter& rParameter) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartTypeHelper.hxx b/chart2/source/inc/ChartTypeHelper.hxx new file mode 100644 index 000000000..cd5985f9a --- /dev/null +++ b/chart2/source/inc/ChartTypeHelper.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "charttoolsdllapi.hxx" +#include + +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } + +namespace chart +{ +class ChartType; + +class OOO_DLLPUBLIC_CHARTTOOLS ChartTypeHelper +{ +public: + static bool isSupportingGeometryProperties( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingStatisticProperties( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingRegressionProperties(const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingMainAxis( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount, sal_Int32 nDimensionIndex ); + static bool isSupportingSecondaryAxis( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingAreaProperties( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingSymbolProperties( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingOverlapAndGapWidthProperties( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingBarConnectors( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingRightAngledAxes( const rtl::Reference< ::chart::ChartType >& xChartType ); + static bool isSupportingAxisSideBySide( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool isSupportingStartingAngle( const rtl::Reference< ::chart::ChartType >& xChartType ); + //starting value for bars or baseline for areas for example + static bool isSupportingBaseValue( const rtl::Reference< ::chart::ChartType >& xChartType ); + static bool isSupportingAxisPositioning( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount, sal_Int32 nDimensionIndex ); + static bool isSupportingDateAxis( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionIndex ); + static bool isSupportingComplexCategory( const rtl::Reference< ::chart::ChartType >& xChartType ); + static bool isSupportingCategoryPositioning( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ); + static bool shiftCategoryPosAtXAxisPerDefault( const rtl::Reference< ::chart::ChartType >& xChartType ); + + //returns sequence of css::chart::DataLabelPlacement + static css::uno::Sequence < sal_Int32 > getSupportedLabelPlacements( + const rtl::Reference< ::chart::ChartType >& xChartType, bool bSwapXAndY + , const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + + //returns sequence of css::chart::MissingValueTreatment + static css::uno::Sequence < sal_Int32 > getSupportedMissingValueTreatments( + const rtl::Reference< ::chart::ChartType >& xChartType ); + + SAL_DLLPRIVATE static css::drawing::Direction3D getDefaultSimpleLightDirection( const rtl::Reference< ::chart::ChartType >& xChartType ); + SAL_DLLPRIVATE static css::drawing::Direction3D getDefaultRealisticLightDirection( const rtl::Reference< ::chart::ChartType >& xChartType ); + SAL_DLLPRIVATE static sal_Int32 getDefaultDirectLightColor( bool bSimple, const rtl::Reference< ::chart::ChartType >& xChartType ); + SAL_DLLPRIVATE static sal_Int32 getDefaultAmbientLightColor( bool bSimple, const rtl::Reference< ::chart::ChartType >& xChartType ); + static sal_Int32 getNumberOfDisplayedSeries( const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nNumberOfSeries ); + SAL_DLLPRIVATE static bool noBordersForSimpleScheme( const rtl::Reference< ::chart::ChartType >& xChartType ); + + static bool isSeriesInFrontOfAxisLine( const rtl::Reference< ::chart::ChartType >& xChartType ); + + static sal_Int32 //one of css::chart2::AxisType + getAxisType( const rtl::Reference< ::chart::ChartType >& xChartType + , sal_Int32 nDimensionIndex ); + + static OUString getRoleOfSequenceForYAxisNumberFormatDetection( const rtl::Reference< + ::chart::ChartType >& xChartType ); + + static OUString getRoleOfSequenceForDataLabelNumberFormatDetection( const rtl::Reference< + ::chart::ChartType >& xChartType ); + + static bool isSupportingOnlyDeepStackingFor3D( const rtl::Reference< ::chart::ChartType >& xChartType ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartTypeTemplate.hxx b/chart2/source/inc/ChartTypeTemplate.hxx new file mode 100644 index 000000000..b90340ae4 --- /dev/null +++ b/chart2/source/inc/ChartTypeTemplate.hxx @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "DataInterpreter.hxx" +#include "StackMode.hxx" +#include +#include +#include "charttoolsdllapi.hxx" +#include +#include + +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XCoordinateSystemContainer; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class BaseCoordinateSystem; +class ChartType; +class DataSeries; +class Diagram; +class LabeledDataSequence; + +/** For creating diagrams and modifying existing diagrams. A base class that + implements XChartTypeTemplate and offers some tooling for classes that + derive from this class. + + createDiagramByDataSource + + This does the following steps using some virtual helper-methods, that may be + overridden by derived classes: + + * creates an XDiagram via service-factory. + + * convert the given XDataSource to a sequence of XDataSeries using the + method createDataSeries(). In this class the DataInterpreter helper class + is used to create a standard interpretation (just y-values). + + * call applyDefaultStyle() for all XDataSeries in order to apply default + styles. In this class the series get the system-wide default colors as + "Color" property. + + * call applyStyle() for applying chart-type specific styles to all series. + The default implementation is empty. + + * call createCoordinateSystems() and apply them to the diagram. As + default one cartesian system with Scales using a linear Scaling is + created. + + * createChartTypes() is called in order to define the structure of the + diagram. For details see comment of this function. As default this + method creates a tree where all series appear in one branch with the chart + type determined by getChartTypeForNewSeries(). The stacking is determined + via the method getStackMode(). + + * create an XLegend via the global service factory, set it at the diagram. + */ +class OOO_DLLPUBLIC_CHARTTOOLS ChartTypeTemplate : public ::cppu::WeakImplHelper< + css::chart2::XChartTypeTemplate, + css::lang::XServiceName > +{ +public: + explicit ChartTypeTemplate( css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName ); + virtual ~ChartTypeTemplate() override; + + rtl::Reference< ::chart::Diagram > createDiagramByDataSource2( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ); + + // ____ XChartTypeTemplate ____ + virtual css::uno::Reference< css::chart2::XDiagram > SAL_CALL createDiagramByDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) override final; + /// denotes if the chart needs categories at the first scale + virtual sal_Bool SAL_CALL supportsCategories() override; + virtual void SAL_CALL changeDiagram( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) override final; + virtual void SAL_CALL changeDiagramData( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram, + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) override final; + virtual sal_Bool SAL_CALL matchesTemplate( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram, + sal_Bool bAdaptProperties ) override final; + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getDataInterpreter() override final; + virtual css::uno::Reference< ::css::chart2::XChartType > SAL_CALL getChartTypeForNewSeries( + const css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > >& aFormerlyUsedChartTypes ) override final; + virtual void SAL_CALL applyStyle( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override final; + virtual void SAL_CALL resetStyles( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) override final; + + void changeDiagram( + const rtl::Reference< ::chart::Diagram >& xDiagram ); + void changeDiagramData( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ); + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ); + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) = 0; + virtual rtl::Reference< ::chart::DataInterpreter > getDataInterpreter2(); + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ); + virtual void resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ); + + /// @throws css::uno::RuntimeException + void applyStyles( + const rtl::Reference< ::chart::Diagram >& xDiagram ); + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + + // Methods to override for automatic creation + + /// returns 2 by default. Supported are 2 and 3 + virtual sal_Int32 getDimension() const; + + /** returns StackMode::NONE by default. This is a global flag used for all + series of a specific chart type. If percent stacking is supported, the + percent stacking mode is retrieved from the first chart type (index 0) + + @param nChartTypeIndex denotes the index of the charttype in means + defined by the template creation order, i.e., 0 means the first + chart type that a template creates. + */ + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const; + + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) = 0; + + virtual bool isSwapXAndY() const; + + // Methods for creating the diagram piecewise + + /** Allows derived classes to manipulate the diagrams whole, like changing + the wall color. The default implementation is empty. It is called by + FillDiagram which is called by createDiagramByDataSource and + changeDiagram + */ + virtual void adaptDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + /** Creates a 2d or 3d cartesian coordinate system with mathematically + oriented, linear scales with auto-min/max. If the given + CoordinateSystemContainer is not empty, those coordinate system should + be reused. + +

The dimension depends on the value returned by getDimension().

+ */ + virtual void createCoordinateSystems( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + /** Sets categories at the scales of dimension 0 and the percent stacking at + the scales of dimension 1 of all given coordinate systems. + +

Called by FillDiagram.

+ */ + virtual void adaptScales( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > & aCooSysSeq, + const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xCategories ); + + /** create a data series tree, that fits the requirements of the chart type. + +

As default, this creates a tree with the following structure:

+ +
+          root
+           |
+           +-- chart type (determined by getChartTypeForNewSeries())
+                   |
+                   +-- category (DiscreteStackableScaleGroup using scale 0)
+                          |
+                          +-- values (ContinuousStackableScaleGroup using scale 1)
+                                |
+                                +-- series 0
+                                |
+                                +-- series 1
+                                |
+                                ...
+                                |
+                                +.. series n-1
+        
+ +

If there are less than two scales available the returned tree is + empty.

+ */ + virtual void createChartTypes( + const std::vector< + std::vector< + rtl::Reference< + ::chart::DataSeries > > > & aSeriesSeq, + const std::vector< + rtl::Reference< + ::chart::BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > > & aOldChartTypesSeq + ); + + /** create axes and add them to the given container. If there are already + compatible axes in the container these should be maintained. + +

As default, this method creates as many axes as there are dimensions + in the given first coordinate system. Each of the axis + represents one of the dimensions of the coordinate systems. If there are series + requesting a secondary axes a secondary y axes is added

+ */ + void createAxes( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > & rCoordSys ); + + /** Give the number of requested axis per dimension here. Default is one + axis for each dimension + */ + virtual sal_Int32 getAxisCountByDimension( sal_Int32 nDimension ); + + /** adapt properties of existing axes and remove superfluous axes + */ + virtual void adaptAxes( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > & rCoordSys ); + + const css::uno::Reference< css::uno::XComponentContext >& + GetComponentContext() const { return m_xContext;} + + static void copyPropertiesFromOldToNewCoordinateSystem( + const std::vector< rtl::Reference< ChartType > > & rOldChartTypesSeq, + const rtl::Reference< ChartType > & xNewChartType ); + +protected: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + mutable rtl::Reference< ::chart::DataInterpreter > m_xDataInterpreter; + +private: + const OUString m_aServiceName; + +private: + /** modifies the given diagram + */ + void FillDiagram( const rtl::Reference< ::chart::Diagram >& xDiagram, + const std::vector< + std::vector< + rtl::Reference< + ::chart::DataSeries > > > & aSeriesSeq, + const css::uno::Reference< css::chart2::data::XLabeledDataSequence >& xCategories, + const std::vector< rtl::Reference< ChartType > > & aOldChartTypesSeq); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartTypeTemplateProvider.hxx b/chart2/source/inc/ChartTypeTemplateProvider.hxx new file mode 100644 index 000000000..400b1c8e2 --- /dev/null +++ b/chart2/source/inc/ChartTypeTemplateProvider.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace chart +{ +class ChartTypeTemplate; + +class ChartTypeTemplateProvider +{ +public: + virtual rtl::Reference<::chart::ChartTypeTemplate> getCurrentTemplate() const = 0; + virtual ~ChartTypeTemplateProvider() {} +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartViewHelper.hxx b/chart2/source/inc/ChartViewHelper.hxx new file mode 100644 index 000000000..54d23e810 --- /dev/null +++ b/chart2/source/inc/ChartViewHelper.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::uno +{ +template class Reference; +} +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +class OOO_DLLPUBLIC_CHARTTOOLS ChartViewHelper +{ +public: + static void setViewToDirtyState(const css::uno::Reference& xChartModel); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/CloneHelper.hxx b/chart2/source/inc/CloneHelper.hxx new file mode 100644 index 000000000..c0896efb5 --- /dev/null +++ b/chart2/source/inc/CloneHelper.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace chart::CloneHelper +{ + +/// functor that clones a UNO-Reference +template< class Interface > + struct CreateRefClone +{ + css::uno::Reference operator() ( const css::uno::Reference & xOther ) + { + css::uno::Reference xResult; + css::uno::Reference< css::util::XCloneable > + xCloneable( xOther, css::uno::UNO_QUERY ); + if( xCloneable.is()) + xResult.set( xCloneable->createClone(), css::uno::UNO_QUERY ); + + return xResult; + } +}; + +/// clones a vector of UNO-References +template< class Interface > + void CloneRefVector( + const std::vector< css::uno::Reference< Interface > > & rSource, + std::vector< css::uno::Reference< Interface > > & rDestination ) +{ + std::transform( rSource.begin(), rSource.end(), + std::back_inserter( rDestination ), + CreateRefClone< Interface >()); +} + +template< class T > + void CloneRefVector( + const std::vector< rtl::Reference< T > > & rSource, + std::vector< rtl::Reference< T > > & rDestination ) +{ + for (const auto & rSourceItem : rSource) + rDestination.push_back(static_cast(rSourceItem->createClone().get())); +} + +/// clones a UNO-sequence of UNO-References +template< class Interface > + void CloneRefSequence( + const css::uno::Sequence< css::uno::Reference > & rSource, + css::uno::Sequence< css::uno::Reference > & rDestination ) +{ + rDestination.realloc( rSource.getLength()); + std::transform( rSource.begin(), rSource.end(), + rDestination.getArray(), + CreateRefClone< Interface >()); +} + +} // namespace chart::CloneHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ColorPerPointHelper.hxx b/chart2/source/inc/ColorPerPointHelper.hxx new file mode 100644 index 000000000..f1665123b --- /dev/null +++ b/chart2/source/inc/ColorPerPointHelper.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::uno { template class Reference; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS ColorPerPointHelper +{ +public: + static bool hasPointOwnColor( + const css::uno::Reference< css::beans::XPropertySet >& xDataSeriesProperties + , sal_Int32 nPointIndex + , const css::uno::Reference< css::beans::XPropertySet >& xDataPointProperties //may be NULL this is just for performance + ); + + // returns true if AttributedDataPoints contains nPointIndex and the + // property Color is DEFAULT + SAL_DLLPRIVATE static bool hasPointOwnProperties( + const css::uno::Reference< css::beans::XPropertySet >& xSeriesProperties + , sal_Int32 nPointIndex ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/CommonConverters.hxx b/chart2/source/inc/CommonConverters.hxx new file mode 100644 index 000000000..7e8a1b868 --- /dev/null +++ b/chart2/source/inc/CommonConverters.hxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::awt { struct Rectangle; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::drawing { struct PolyPolygonBezierCoords; } + +namespace chart +{ + +/** +diverse methods for class conversions; e.g. ::basegfx::B3DHomMatrix to HomogenMatrix +and operations e.g drawing::Position3D + drawing::Direction3D +*/ + +/** ::basegfx::B3DHomMatrix -> HomogenMatrix +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::HomogenMatrix + B3DHomMatrixToHomogenMatrix( const ::basegfx::B3DHomMatrix& rM ); + +/** HomogenMatrix -> ::basegfx::B3DHomMatrix +*/ +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DHomMatrix HomogenMatrixToB3DHomMatrix( const css::drawing::HomogenMatrix& rHM ); + +/** ::basegfx::B3DHomMatrix -> B2DHomMatrix +*/ +OOO_DLLPUBLIC_CHARTTOOLS +::basegfx::B2DHomMatrix IgnoreZ( const ::basegfx::B3DHomMatrix& rM ); + +/** B2DHomMatrix <-> HomogenMatrix3 +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::HomogenMatrix3 + B2DHomMatrixToHomogenMatrix3( const ::basegfx::B2DHomMatrix& rM ); + +/** Position3D -> B3DPoint +*/ +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DPoint Position3DToB3DPoint( const css::drawing::Position3D& rPosition ); + +/** B3DVector -> Direction3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Direction3D B3DVectorToDirection3D( const ::basegfx::B3DVector& rVector); + +/** B3DPoint -> Position3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D B3DPointToPosition3D( const ::basegfx::B3DPoint& rPoint); + +/** Direction3D -> B3DVector +*/ +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DVector Direction3DToB3DVector( const css::drawing::Direction3D& rDirection); + +/** PolyPolygonShape3D + drawing::Position3D -> PolyPolygonShape3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS +void AddPointToPoly( css::drawing::PolyPolygonShape3D& rPoly + , const css::drawing::Position3D& rPos + , sal_Int32 nSequenceIndex=0 ); +OOO_DLLPUBLIC_CHARTTOOLS +void AddPointToPoly( std::vector>& rPoly + , const css::drawing::Position3D& rPos + , sal_Int32 nSequenceIndex=0 ); + +/** get a single Point from a Polygon +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D getPointFromPoly( + const std::vector>& rPolygon + , sal_Int32 nPointIndex, sal_Int32 nPolyIndex ); +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D getPointFromPoly( + const css::drawing::PolyPolygonShape3D& rPolygon + , sal_Int32 nPointIndex, sal_Int32 nPolyIndex ); + +OOO_DLLPUBLIC_CHARTTOOLS +void addPolygon( std::vector>& rRet + , const std::vector>& rAdd ); +/** PolyPolygonShape3D + PolyPolygonShape3D -> PolyPolygonShape3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS +void appendPoly( std::vector>& rRet + , const std::vector>& rAdd ); + +/** PolyPolygonBezierCoords -> PolyPolygonShape3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS +css::drawing::PolyPolygonShape3D BezierToPoly( + const css::drawing::PolyPolygonBezierCoords& rBezier ); + +/** PolyPolygonShape3D -> drawing::PointSequenceSequence (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS +css::drawing::PointSequenceSequence PolyToPointSequence( + const css::drawing::PolyPolygonShape3D& rPolyPolygon ); +OOO_DLLPUBLIC_CHARTTOOLS +css::drawing::PointSequenceSequence PolyToPointSequence( + const std::vector>& rPolyPolygon ); + +/** PolyPolygonShape3D -> basegfx::B2DPolyPolygon (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS +basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( + const std::vector>& rPolyPolygon ); + +/** drawing::PointSequenceSequence + drawing::PointSequenceSequence +*/ +OOO_DLLPUBLIC_CHARTTOOLS +void appendPointSequence( css::drawing::PointSequenceSequence& rTarget + , const css::drawing::PointSequenceSequence& rAdd ); + +/** Position3D + Direction3D == Position3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D + operator+( const css::drawing::Position3D& rPos + , const css::drawing::Direction3D& rDirection); + +/** Position3D - Position3D == Direction3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Direction3D + operator-( const css::drawing::Position3D& rPos1 + , const css::drawing::Position3D& rPos2); + +/** awt::Rect --> awt::Point (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Point ToPoint( const css::awt::Rectangle& rRectangle ); + +/** awt::Rect --> awt::Size (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Size ToSize( const css::awt::Rectangle& rRectangle ); + +/** Position3D --> awt::Point (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Point Position3DToAWTPoint( const css::drawing::Position3D& rPos ); + +/** Direction3D --> awt::Size (2D) +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::awt::Size Direction3DToAWTSize( const css::drawing::Direction3D& rDirection ); + +/** Sequence -> drawing::Position3D +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D + SequenceToPosition3D( const css::uno::Sequence< double >& rSeq ); + +/** chart2::XDataSequence -> uno::Sequence< double > +*/ + +OOO_DLLPUBLIC_CHARTTOOLS +css::uno::Sequence< double > DataSequenceToDoubleSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence ); + +OOO_DLLPUBLIC_CHARTTOOLS +css::uno::Sequence< OUString > DataSequenceToStringSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence ); + +/** std::vector< std::vector< T > > -> std::vector< T > + */ +template< typename T > +std::vector< T > + FlattenSequence( const std::vector< std::vector< T > > & aSeqSeq ) +{ + sal_Int32 nOuter, nInner, nCount = 0, + nResultSize = 0; + const sal_Int32 nOuterSize = aSeqSeq.size(); + for( nOuter=0; nOuter aResult( nResultSize ); + + for( nOuter=0; nOuter +#include +#include +#include +#include "charttoolsdllapi.hxx" + +#include + +namespace chart::CommonFunctors +{ + +/** unary function to convert any type T into a css::uno::Any. + +

uno::makeAny is an inline function. Thus is cannot be taken directly + (via mem_fun_ptr)

+*/ +template< typename T > + struct makeAny +{ + css::uno::Any operator() ( const T & aVal ) + { + return css::uno::Any( aVal ); + } +}; + +/** unary function to convert css::uno::Any into a double number. + +

In case no number can be generated from the Any, NaN is returned.

+*/ +struct OOO_DLLPUBLIC_CHARTTOOLS AnyToDouble +{ + double operator() ( const css::uno::Any & rAny ) + { + double fResult = std::numeric_limits::quiet_NaN(); + rAny >>= fResult; + return fResult; + } +}; + +/** unary function to convert css::uno::Any into an + OUString. +*/ +struct OOO_DLLPUBLIC_CHARTTOOLS AnyToString +{ + OUString operator() ( const css::uno::Any & rAny ) + { + if( auto pDouble = o3tl::tryAccess(rAny) ) + { + if( std::isnan(*pDouble) ) + return OUString(); + return ::rtl::math::doubleToUString( + * pDouble, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, // use maximum decimal places available + '.', // decimal separator + true // remove trailing zeros + ); + } + else if( auto s = o3tl::tryAccess(rAny) ) + { + return *s; + } + + return OUString(); + } +}; + +/** unary function to convert an OUString into a double number. + +

For conversion rtl::math::StringToDouble is used.

+ */ +struct OOO_DLLPUBLIC_CHARTTOOLS OUStringToDouble +{ + double operator() ( std::u16string_view rStr ) + { + rtl_math_ConversionStatus eConversionStatus; + double fResult = ::rtl::math::stringToDouble( rStr, '.', ',', & eConversionStatus ); + + if( eConversionStatus != rtl_math_ConversionStatus_Ok ) + return std::numeric_limits::quiet_NaN(); + + return fResult; + } +}; + +/** unary function to convert a double number into an OUString. + +

For conversion rtl::math::DoubleToOUString is used.

+ */ +struct OOO_DLLPUBLIC_CHARTTOOLS DoubleToOUString +{ + OUString operator() ( double fNumber ) + { + return ::rtl::math::doubleToUString( + fNumber, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, // use maximum decimal places available + '.', + true + ); + } +}; + +} // namespace chart::CommonFunctors + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ConfigColorScheme.hxx b/chart2/source/inc/ConfigColorScheme.hxx new file mode 100644 index 000000000..0cf65d030 --- /dev/null +++ b/chart2/source/inc/ConfigColorScheme.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" +#include +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::XColorScheme > createConfigColorScheme( + const css::uno::Reference< css::uno::XComponentContext > & xContext ); + +namespace impl +{ +class ChartConfigItem; +} + +class ConfigColorScheme final : + public ::cppu::WeakImplHelper< + css::chart2::XColorScheme, + css::lang::XServiceInfo > +{ +public: + explicit ConfigColorScheme( const css::uno::Reference< css::uno::XComponentContext > & xContext ); + virtual ~ConfigColorScheme() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ ConfigItemListener ____ + void notify( std::u16string_view rPropertyName ); + +protected: + // ____ XColorScheme ____ + virtual ::sal_Int32 SAL_CALL getColorByIndex( ::sal_Int32 nIndex ) override; + +private: + void retrieveConfigColors(); + + // member variables + css::uno::Reference< css::uno::XComponentContext > m_xContext; + std::unique_ptr< impl::ChartConfigItem > m_apChartConfigItem; + mutable css::uno::Sequence< sal_Int64 > m_aColorSequence; + mutable sal_Int32 m_nNumberOfColors; + bool m_bNeedsUpdate; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ControllerLockGuard.hxx b/chart2/source/inc/ControllerLockGuard.hxx new file mode 100644 index 000000000..393c8fec1 --- /dev/null +++ b/chart2/source/inc/ControllerLockGuard.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" +#include + +namespace chart +{ +class ChartModel; +} +namespace com::sun::star::frame +{ +class XModel; +} + +namespace chart +{ +/** This guard calls lockControllers at the given Model in the CTOR and + unlockControllers in the DTOR. Using this ensures that controllers do not + remain locked when leaving a function even in case an exception is thrown. + */ +class OOO_DLLPUBLIC_CHARTTOOLS ControllerLockGuardUNO +{ +public: + explicit ControllerLockGuardUNO(const rtl::Reference<::chart::ChartModel>& xModel); + ~ControllerLockGuardUNO(); + +private: + rtl::Reference<::chart::ChartModel> mxModel; +}; + +class ControllerLockGuard +{ +public: + explicit ControllerLockGuard(ChartModel& rModel); + ~ControllerLockGuard(); + +private: + ChartModel& mrModel; +}; + +/** This helper class can be used to pass a locking mechanism to other objects + without exposing the full XModel to it. + + Use the ControllerLockHelperGuard to lock/unlock the model during a block of + instructions. + */ +class OOO_DLLPUBLIC_CHARTTOOLS ControllerLockHelper +{ +public: + explicit ControllerLockHelper(const rtl::Reference<::chart::ChartModel>& xModel); + ~ControllerLockHelper(); + + SAL_DLLPRIVATE void lockControllers(); + SAL_DLLPRIVATE void unlockControllers(); + +private: + rtl::Reference<::chart::ChartModel> m_xModel; +}; + +/** This guard calls lockControllers at the given ControllerLockHelper in the + CTOR and unlockControllers in the DTOR. Using this ensures that controllers + do not remain locked when leaving a function even in case an exception is + thrown. + */ +class OOO_DLLPUBLIC_CHARTTOOLS ControllerLockHelperGuard +{ +public: + explicit ControllerLockHelperGuard(ControllerLockHelper& rHelper); + ~ControllerLockHelperGuard(); + +private: + ControllerLockHelper& m_rHelper; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DataInterpreter.hxx b/chart2/source/inc/DataInterpreter.hxx new file mode 100644 index 000000000..7638e5cce --- /dev/null +++ b/chart2/source/inc/DataInterpreter.hxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "DataSeries.hxx" +#include +#include +#include +#include +#include +#include + +namespace chart +{ +class DataSeries; +class DataSource; +class LabeledDataSequence; + +/** offers tooling to interpret different data sources in a structural + and chart-type-dependent way. + */ +struct InterpretedData +{ + std::vector< std::vector< rtl::Reference<::chart::DataSeries> > > Series; + css::uno::Reference< css::chart2::data::XLabeledDataSequence > Categories; +}; + +/** offers tooling to interpret different data sources in a structural + and chart-type-dependent way. + */ +class SAL_DLLPUBLIC_RTTI DataInterpreter : public ::cppu::WeakImplHelper< + css::lang::XServiceInfo > +{ +public: + explicit DataInterpreter(); + virtual ~DataInterpreter() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // convenience methods + static OUString GetRole( const css::uno::Reference< css::chart2::data::XDataSequence > & xSeq ); + + static void SetRole( + const css::uno::Reference< css::chart2::data::XDataSequence > & xSeq, + const OUString & rRole ); + + static css::uno::Any GetProperty( + const css::uno::Sequence & aArguments, + std::u16string_view rName ); + + static bool HasCategories( + const css::uno::Sequence< css::beans::PropertyValue > & rArguments, + const std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > & rData ); + + static bool UseCategoriesAsX( + const css::uno::Sequence< css::beans::PropertyValue > & rArguments ); + + static std::vector> getDataSequences( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource); + + // ____ DataInterpreter ____ + /** Interprets the given data. + + @param xSource + the data source. + + @param aArguments + Arguments that tell the template how to slice the given + range. The properties should be defined in a separate + service. + +

For standard parameters that may be used, see the + service StandardDiagramCreationParameters. +

+ + @param aSeriesToReUse + use all the data series given here for the result before + creating new ones. + */ + virtual InterpretedData interpretDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< ::chart::DataSeries > >& aSeriesToReUse ); + + /** Re-interprets the data given in aInterpretedData + while keeping the number of data series and the categories. + */ + virtual InterpretedData reinterpretDataSeries( + const InterpretedData& aInterpretedData ); + + /** parses the given data and states, if a + reinterpretDataSeries() call can be done + without data loss. + + @return + `TRUE`, if the data given in + aInterpretedData has a similar structure than + the one required is used as output of the data interpreter. + */ + virtual bool isDataCompatible( + const InterpretedData& aInterpretedData ); + + /** Try to reverse the operation done in + interpretDataSource(). + +

In case aInterpretedData is the result of + interpretDataSource()( xSource ), + the result of this method should be xSource.

+ */ + static rtl::Reference< ::chart::DataSource > mergeInterpretedData( + const InterpretedData& aInterpretedData ); + + /** Get chart information that is specific to a particular chart + type, by key. + + @param sKey + name of the piece of data to retrieve. + +

Supported key strings:

+
    +
  • "stock variant": stock chart variant, + with 0 = neither Open Values nor volume, 1 = Open Values, + 2 = volume, 3 = both. Valid for candlestick charts.
  • +
+ + @return + The value requested, or nothing if not present. + */ + virtual css::uno::Any getChartTypeSpecificData( + const OUString& sKey ); +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DataSeries.hxx b/chart2/source/inc/DataSeries.hxx new file mode 100644 index 000000000..f15053262 --- /dev/null +++ b/chart2/source/inc/DataSeries.hxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +// UNO types +#include +#include +#include +#include +#include +#include + +// helper classes +#include +#include +#include +#include "ModifyListenerHelper.hxx" + +// STL +#include +#include + +#include "OPropertySet.hxx" +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::beans { class XPropertySet; } + +namespace chart +{ +class LabeledDataSequence; +class RegressionCurveModel; + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XDataSeries, + css::chart2::data::XDataSink, + css::chart2::data::XDataSource, + css::lang::XServiceInfo, + css::chart2::XRegressionCurveContainer, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + DataSeries_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS DataSeries final : + public cppu::BaseMutex, + public impl::DataSeries_Base, + public ::property::OPropertySet +{ +public: + explicit DataSeries(); + virtual ~DataSeries() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + + explicit DataSeries( const DataSeries & rOther ); + + // ____ XDataSeries ____ + /// @see css::chart2::XDataSeries + virtual css::uno::Reference< css::beans::XPropertySet > + SAL_CALL getDataPointByIndex( sal_Int32 nIndex ) override; + virtual void SAL_CALL resetDataPoint( sal_Int32 nIndex ) override; + virtual void SAL_CALL resetAllDataPoints() override; + +private: + // ____ XDataSink ____ + /// @see css::chart2::data::XDataSink + virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > >& aData ) override; + + // ____ XDataSource ____ + /// @see css::chart2::data::XDataSource + virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override; +public: + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + /// @see css::beans::XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + /// make original interface function visible again + using ::com::sun::star::beans::XFastPropertySet::getFastPropertyValue; + + // ____ XRegressionCurveContainer ____ + /// @see css::chart2::XRegressionCurveContainer + virtual void SAL_CALL addRegressionCurve( + const css::uno::Reference< css::chart2::XRegressionCurve >& aRegressionCurve ) override; + virtual void SAL_CALL removeRegressionCurve( + const css::uno::Reference< css::chart2::XRegressionCurve >& aRegressionCurve ) override; + virtual css::uno::Sequence< css::uno::Reference< css::chart2::XRegressionCurve > > SAL_CALL getRegressionCurves() override; + virtual void SAL_CALL setRegressionCurves( + const css::uno::Sequence< css::uno::Reference< css::chart2::XRegressionCurve > >& aRegressionCurves ) override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + typedef std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > tDataSequenceContainer; + + void setData( const tDataSequenceContainer& aData ); + const tDataSequenceContainer & getDataSequences2() const { return m_aDataSequences; } + + typedef + std::vector< rtl::Reference< ::chart::RegressionCurveModel > > + tRegressionCurveContainerType; + + const tRegressionCurveContainerType & getRegressionCurves2() const { return m_aRegressionCurves; } + +private: + + // late initialization to call after copy-constructing + void Init( const DataSeries & rOther ); + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + + tDataSequenceContainer m_aDataSequences; + + typedef std::map< sal_Int32, + css::uno::Reference< css::beans::XPropertySet > > tDataPointAttributeContainer; + tDataPointAttributeContainer m_aAttributedDataPoints; + + tRegressionCurveContainerType m_aRegressionCurves; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DataSeriesHelper.hxx b/chart2/source/inc/DataSeriesHelper.hxx new file mode 100644 index 000000000..49ef07853 --- /dev/null +++ b/chart2/source/inc/DataSeriesHelper.hxx @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "StackMode.hxx" +#include "charttoolsdllapi.hxx" +#include +#include +#include + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::uno { class Any; } +namespace com::sun::star::uno { template class Sequence; } +namespace chart { class BaseCoordinateSystem; } +namespace chart { class ChartType; } +namespace chart { class DataSource; } +namespace chart { class Diagram; } +namespace chart { class DataSeries; } +namespace chart { class LabeledDataSequence; } + +namespace chart::DataSeriesHelper +{ + +OOO_DLLPUBLIC_CHARTTOOLS OUString + getRole( const css::uno::Reference& xLabeledDataSequence ); + +/** Retrieves the data sequence in the given data source that matches the + given role. If more than one sequences match the role, the first match + is returned. If no sequence matches, an empty reference is returned. + + @param aSource + The data source containing all data sequences to be searched through. + + @param aRole + The role that is to be filtered out. +*/ +OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XLabeledDataSequence > + getDataSequenceByRole( const css::uno::Reference< css::chart2::data::XDataSource > & xSource, + const OUString& aRole, + bool bMatchPrefix = false ); + +/** Retrieves all data sequences in the given data source that match the given + role prefix. + + @param aSource + The data source containing all data sequences to be searched through. + + @param aRole + The role that is to be filtered out. +*/ +OOO_DLLPUBLIC_CHARTTOOLS std::vector< + css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + getAllDataSequencesByRole( const css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > & aDataSequences, + const OUString& aRole ); +OOO_DLLPUBLIC_CHARTTOOLS std::vector< + css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + getAllDataSequencesByRole( const std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > & aDataSequences, + const OUString& aRole ); + +OOO_DLLPUBLIC_CHARTTOOLS +std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > +getAllDataSequences( + const css::uno::Sequence >& aSeries ); +OOO_DLLPUBLIC_CHARTTOOLS +std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > +getAllDataSequences( + const std::vector >& aSeries ); + +/** Retrieves all data sequences found in the given data series and puts them + into a data source. The order of sequences will match the order of the data + series. + */ +OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference< ::chart::DataSource > + getDataSource( const std::vector< rtl::Reference< ::chart::DataSeries > > & aSeries ); + +/** Get the label of a series (e.g. for the legend) + + @param rLabelSequenceRole + The data sequence contained in xSeries that has this role will be used + to take its label. + */ +OOO_DLLPUBLIC_CHARTTOOLS OUString getDataSeriesLabel( + const rtl::Reference< ::chart::DataSeries > & xSeries, + const OUString & rLabelSequenceRole ); + +/** Get the label of a labeled sequence including necessary automatic generation + */ +OOO_DLLPUBLIC_CHARTTOOLS OUString getLabelForLabeledDataSequence( + const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xLabeledSeq ); + +OOO_DLLPUBLIC_CHARTTOOLS void setStackModeAtSeries( + const std::vector< rtl::Reference< ::chart::DataSeries > > & aSeries, + const rtl::Reference< ::chart::BaseCoordinateSystem > & xCorrespondingCoordinateSystem, + StackMode eStackMode ); + +OOO_DLLPUBLIC_CHARTTOOLS sal_Int32 getAttachedAxisIndex( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries ); + +/// @param nAxisIndex, if -1 it is determined by the given data series via getAttachedAxisIndex +OOO_DLLPUBLIC_CHARTTOOLS sal_Int32 getNumberFormatKeyFromAxis( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::BaseCoordinateSystem > & xCorrespondingCoordinateSystem, + sal_Int32 nDimensionIndex, + sal_Int32 nAxisIndex = -1 ); + +OOO_DLLPUBLIC_CHARTTOOLS +rtl::Reference< ::chart::BaseCoordinateSystem > + getCoordinateSystemOfSeries( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + +OOO_DLLPUBLIC_CHARTTOOLS +rtl::Reference< ::chart::ChartType > + getChartTypeOfSeries( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::Diagram > & xDiagram ); + +OOO_DLLPUBLIC_CHARTTOOLS void deleteSeries( + const css::uno::Reference< css::chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType ); + +OOO_DLLPUBLIC_CHARTTOOLS void switchSymbolsOnOrOff( + const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties, + bool bSymbolsOn, sal_Int32 nSeriesIndex ); + +OOO_DLLPUBLIC_CHARTTOOLS void switchLinesOnOrOff( + const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties, + bool bLinesOn ); + +OOO_DLLPUBLIC_CHARTTOOLS +void makeLinesThickOrThin( const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties, bool bThick ); + +OOO_DLLPUBLIC_CHARTTOOLS void setPropertyAlsoToAllAttributedDataPoints( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, + const css::uno::Any& rPropertyValue ); +OOO_DLLPUBLIC_CHARTTOOLS void setPropertyAlsoToAllAttributedDataPoints( + const rtl::Reference< ::chart::DataSeries >& xSeries, + const OUString& rPropertyName, + const css::uno::Any& rPropertyValue ); + + +OOO_DLLPUBLIC_CHARTTOOLS bool hasAttributedDataPointDifferentValue( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, + const css::uno::Any& rPropertyValue ); + +OOO_DLLPUBLIC_CHARTTOOLS bool hasUnhiddenData( const css::uno::Reference< + css::chart2::XDataSeries >& xSeries ); + +OOO_DLLPUBLIC_CHARTTOOLS +sal_Int32 translateIndexFromHiddenToFullSequence( sal_Int32 nClippedIndex, const css::uno::Reference< + css::chart2::data::XDataSequence >& xDataSequence, bool bTranslate ); + +OOO_DLLPUBLIC_CHARTTOOLS bool hasDataLabelsAtSeries( const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + +OOO_DLLPUBLIC_CHARTTOOLS bool hasDataLabelsAtPoints( const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + +OOO_DLLPUBLIC_CHARTTOOLS bool hasDataLabelAtPoint( const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32 nPointIndex ); + +OOO_DLLPUBLIC_CHARTTOOLS void insertDataLabelsToSeriesAndAllPoints( const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + +OOO_DLLPUBLIC_CHARTTOOLS void insertDataLabelToPoint( const css::uno::Reference< css::beans::XPropertySet >& xPointPropertySet ); + +OOO_DLLPUBLIC_CHARTTOOLS void deleteDataLabelsFromSeriesAndAllPoints( const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + +OOO_DLLPUBLIC_CHARTTOOLS void deleteDataLabelsFromPoint( const css::uno::Reference< css::beans::XPropertySet >& xPointPropertySet ); + +} // namespace chart::DataSeriesHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DataSource.hxx b/chart2/source/inc/DataSource.hxx new file mode 100644 index 000000000..6e9b84ed9 --- /dev/null +++ b/chart2/source/inc/DataSource.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace chart +{ +class LabeledDataSequence; + +class OOO_DLLPUBLIC_CHARTTOOLS DataSource final : public + ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::chart2::data::XDataSource, + css::chart2::data::XDataSink > +{ +public: + explicit DataSource(); + explicit DataSource( + const css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > & rSequences ); + explicit DataSource( + const std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > & rSequences ); + + virtual ~DataSource() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XDataSource ____ + virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL + getDataSequences() override; + + // ____ XDataSink ____ + virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > >& aData ) override; + +private: + css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + m_aDataSeq; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DataSourceHelper.hxx b/chart2/source/inc/DataSourceHelper.hxx new file mode 100644 index 000000000..52ed68945 --- /dev/null +++ b/chart2/source/inc/DataSourceHelper.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "charttoolsdllapi.hxx" +#include +#include +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::frame { class XModel; } + +namespace chart +{ +class DataSource; +class Diagram; +class LabeledDataSequence; + +class OOO_DLLPUBLIC_CHARTTOOLS DataSourceHelper +{ +public: + static css::uno::Reference< css::chart2::data::XDataSequence > + createCachedDataSequence(); + + static css::uno::Reference< css::chart2::data::XDataSequence > + createCachedDataSequence( const OUString & rSingleText ); + + static rtl::Reference< LabeledDataSequence > + createLabeledDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence >& xValues , + const css::uno::Reference< css::chart2::data::XDataSequence >& xLabels ); + + static rtl::Reference< LabeledDataSequence > + createLabeledDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence >& xValues ); + + static rtl::Reference< LabeledDataSequence > + createLabeledDataSequence(); + + static css::uno::Sequence< css::beans::PropertyValue > + createArguments( + bool bUseColumns, bool bFirstCellAsLabel, bool bHasCategories ); + + static css::uno::Sequence< + css::beans::PropertyValue > createArguments( + const OUString & rRangeRepresentation, + const css::uno::Sequence< sal_Int32 >& rSequenceMapping, + bool bUseColumns, bool bFirstCellAsLabel, bool bHasCategories ); + + SAL_DLLPRIVATE static void readArguments( const css::uno::Sequence< css::beans::PropertyValue >& rArguments + , OUString & rRangeRepresentation, css::uno::Sequence< sal_Int32 >& rSequenceMapping + , bool& bUseColumns, bool& bFirstCellAsLabel, bool& bHasCategories ); + + static rtl::Reference< ::chart::DataSource > + pressUsedDataIntoRectangularFormat( const rtl::Reference< ::chart::ChartModel >& xChartDoc ); + + SAL_DLLPRIVATE static css::uno::Sequence< OUString > getUsedDataRanges( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + static css::uno::Sequence< OUString > getUsedDataRanges( + const rtl::Reference<::chart::ChartModel> & xChartModel ); + + static rtl::Reference< ::chart::DataSource > getUsedData( + ChartModel& rModel ); + + static bool detectRangeSegmentation( + const rtl::Reference<::chart::ChartModel>& xChartModel + , OUString& rOutRangeString + , css::uno::Sequence< sal_Int32 >& rSequenceMapping + , bool& rOutUseColumns + , bool& rOutFirstCellAsLabel + , bool& rOutHasCategories ); + + static void setRangeSegmentation( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::uno::Sequence< sal_Int32 >& rSequenceMapping + , bool bUseColumns + , bool bFirstCellAsLabel + , bool bUseCategories ); + + /** Returns true, if all arguments necessary for getting all data by a + rectangular region are returned by detectArguments at the given + document's data provider. + + Currently, this is: CellRangeRepresentation, DataRowSource, + HasCategories and FirstCellAsLabel. + */ + static bool allArgumentsForRectRangeDetected( + const rtl::Reference<::chart::ChartModel>& xChartDocument ); + + SAL_DLLPRIVATE static css::uno::Sequence< OUString > getRangesFromLabeledDataSequence( + const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xLSeq ); + + SAL_DLLPRIVATE static OUString getRangeFromValues( + const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xLSeq ); + + SAL_DLLPRIVATE static css::uno::Sequence< OUString > getRangesFromDataSource( + const css::uno::Reference< css::chart2::data::XDataSource > & xSource ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/Diagram.hxx b/chart2/source/inc/Diagram.hxx new file mode 100644 index 000000000..3c0e31d8b --- /dev/null +++ b/chart2/source/inc/Diagram.hxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class BaseCoordinateSystem; +class Legend; +class Wall; + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XDiagram, + css::lang::XServiceInfo, + css::chart2::XCoordinateSystemContainer, + css::chart2::XTitled, + css::chart::X3DDefaultSetter, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::util::XCloneable > + Diagram_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS Diagram final : + public cppu::BaseMutex, + public impl::Diagram_Base, + public ::property::OPropertySet +{ +public: + Diagram( css::uno::Reference< css::uno::XComponentContext > const & xContext ); + virtual ~Diagram() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + + explicit Diagram( const Diagram & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XFastPropertySet ____ + virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + + /// make original interface function visible again + using ::com::sun::star::beans::XFastPropertySet::getFastPropertyValue; + + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, sal_Int32 nHandle ) const override; + + // ____ XDiagram ____ + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getWall() override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getFloor() override; + virtual css::uno::Reference< css::chart2::XLegend > SAL_CALL getLegend() override; + virtual void SAL_CALL setLegend( const css::uno::Reference< + css::chart2::XLegend >& xLegend ) override; + virtual css::uno::Reference< css::chart2::XColorScheme > SAL_CALL getDefaultColorScheme() override; + virtual void SAL_CALL setDefaultColorScheme( + const css::uno::Reference< css::chart2::XColorScheme >& xColorScheme ) override; + virtual void SAL_CALL setDiagramData( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) override; + + // ____ XCoordinateSystemContainer ____ + virtual void SAL_CALL addCoordinateSystem( + const css::uno::Reference< css::chart2::XCoordinateSystem >& aCoordSys ) override; + virtual void SAL_CALL removeCoordinateSystem( + const css::uno::Reference< css::chart2::XCoordinateSystem >& aCoordSys ) override; + virtual css::uno::Sequence< css::uno::Reference< css::chart2::XCoordinateSystem > > SAL_CALL getCoordinateSystems() override; + virtual void SAL_CALL setCoordinateSystems( + const css::uno::Sequence< css::uno::Reference< css::chart2::XCoordinateSystem > >& aCoordinateSystems ) override; + + // ____ XTitled ____ + virtual css::uno::Reference< + css::chart2::XTitle > SAL_CALL getTitleObject() override; + virtual void SAL_CALL setTitleObject( const css::uno::Reference< + css::chart2::XTitle >& Title ) override; + + // ____ X3DDefaultSetter ____ + virtual void SAL_CALL set3DSettingsToDefault() override; + virtual void SAL_CALL setDefaultRotation() override; + virtual void SAL_CALL setDefaultIllumination() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + typedef + std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > + tCoordinateSystemContainerType; + + const tCoordinateSystemContainerType & getBaseCoordinateSystems() { return m_aCoordSystems; } + void setCoordinateSystems( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > >& aCoordinateSystems ); + + const rtl::Reference< ::chart::Legend > & getLegend2() const { return m_xLegend; } + void setLegend(const rtl::Reference< ::chart::Legend > &); + +private: + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + + css::uno::Reference m_xContext; + tCoordinateSystemContainerType m_aCoordSystems; + + rtl::Reference m_xWall; + rtl::Reference m_xFloor; + + css::uno::Reference m_xTitle; + + rtl::Reference<::chart::Legend> m_xLegend; + css::uno::Reference m_xColorScheme; + rtl::Reference m_xModifyEventForwarder; + +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DiagramHelper.hxx b/chart2/source/inc/DiagramHelper.hxx new file mode 100644 index 000000000..f874a1afa --- /dev/null +++ b/chart2/source/inc/DiagramHelper.hxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "StackMode.hxx" +#include "charttoolsdllapi.hxx" +#include "ChartTypeTemplate.hxx" +#include +#include + +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XNumberFormats; } +namespace com::sun::star::util { class XNumberFormatsSupplier; } + +namespace chart +{ +class Axis; +class BaseCoordinateSystem; +class ChartType; +class ChartTypeManager; +class ChartTypeTemplate; +class DataSeries; +class Diagram; +class LabeledDataSequence; + +enum DiagramPositioningMode +{ + DiagramPositioningMode_AUTO, + DiagramPositioningMode_EXCLUDING, + DiagramPositioningMode_INCLUDING +}; + +class OOO_DLLPUBLIC_CHARTTOOLS DiagramHelper +{ +public: + struct tTemplateWithServiceName { + rtl::Reference< ::chart::ChartTypeTemplate > xChartTypeTemplate; + OUString sServiceName; + }; + + /** tries to find a template in the chart-type manager that matches the + given diagram. + + @return + A pair containing a template with the correct properties set as + first entry and the service name of the templates second entry. If + no template was found both elements are empty. + */ + static tTemplateWithServiceName + getTemplateForDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram, + const rtl::Reference< ::chart::ChartTypeManager > & xChartTypeManager); + + /** Sets the "SwapXAndYAxis" property at all coordinate systems found in the + given diagram. + + "vertical==true" for bar charts, "vertical==false" for column charts + */ + static void setVertical( const rtl::Reference< ::chart::Diagram > & xDiagram, + bool bVertical ); + + /** Gets the "SwapXAndYAxis" property at all coordinate systems found in the + given diagram. + + "vertical==true" for bar charts, "vertical==false" for column charts + */ + static bool getVertical( const rtl::Reference< ::chart::Diagram > & xDiagram, + bool& rbOutFoundResult, bool& rbOutAmbiguousResult ); + + static StackMode getStackMode( + const rtl::Reference< ::chart::Diagram > & xDiagram, + bool& rbFound, bool& rbAmbiguous + ); + + /** The stacking mode is only set at the series found inside + the first chart type. This is the standard for all current + templates (the only template that has more than one chart-type and + allows stacking is bar/line combi, and for this the stacking only + applies to the first chart type/the bars) + */ + static void setStackMode( + const rtl::Reference< ::chart::Diagram > & xDiagram, + StackMode eStackMode + ); + + /** Retrieves the stackmode of the first DataSeries or none. If the series have differing stack + modes, rbAmbiguous is set to true. If no series is there rbFound is set to false. + + @param xCorrespondingCoordinateSystem + The coordinate system in which the given chart type xChartType is + located. (This is needed for determining percent stacking. If + omitted, the result will just indicate "not stacked", "stacked" or + "ambiguous") + */ + static StackMode getStackModeFromChartType( + const rtl::Reference< ::chart::ChartType > & xChartType, + bool& rbFound, bool& rbAmbiguous, + const rtl::Reference< ::chart::BaseCoordinateSystem > & xCorrespondingCoordinateSystem + ); + + /** Returns the dimension found for all chart types in the tree. If the + dimension is not unique, 0 is returned. + */ + static sal_Int32 getDimension( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + /** Sets the dimension of the diagram given. + + 1. Sets the dimension of all used ChartTypes + 2. Adapts the DataSeriesTree to reflect the new dimension + 3. If new coordinate-systems have to be created, adapts the + XCoordinateSystemContainer of the diagram. + */ + static void setDimension( + const rtl::Reference< ::chart::Diagram > & xDiagram, + sal_Int32 nNewDimensionCount ); + + /** Replaces all occurrences of xCooSysToReplace in the tree with + xReplacement in the diagram's tree + */ + SAL_DLLPRIVATE static void replaceCoordinateSystem( + const rtl::Reference< ::chart::Diagram > & xDiagram, + const rtl::Reference< ::chart::BaseCoordinateSystem > & xCooSysToReplace, + const rtl::Reference< ::chart::BaseCoordinateSystem > & xReplacement ); + + static bool isSeriesAttachedToMainAxis( + const css::uno::Reference< css::chart2::XDataSeries >& xDataSeries ); + + static bool attachSeriesToAxis( bool bMainAxis, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const rtl::Reference< ::chart::Diagram >& xDiagram, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + bool bAdaptAxes=true ); + + static rtl::Reference< ::chart::Axis > getAttachedAxis( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static rtl::Reference< ::chart::Axis > getAttachedAxis( + const rtl::Reference< ::chart::DataSeries >& xSeries, + const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static rtl::Reference< ChartType > + getChartTypeOfSeries( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries ); + + static std::vector< rtl::Reference< ::chart::DataSeries > > + getDataSeriesFromDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + /** return all data series in this diagram grouped by chart-types + */ + static std::vector< + std::vector< + rtl::Reference< ::chart::DataSeries > > > + getDataSeriesGroups( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + static bool isCategoryDiagram( + const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static void setCategoriesToDiagram( + const css::uno::Reference< css::chart2::data::XLabeledDataSequence >& xCategories, + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bSetAxisType = false, // when this flag is true ... + bool bCategoryAxis = true);// set the AxisType to CATEGORY or back to REALNUMBER + + static css::uno::Reference< css::chart2::data::XLabeledDataSequence > + getCategoriesFromDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + static css::uno::Sequence< OUString > + getExplicitSimpleCategories( ChartModel& rModel ); + + SAL_DLLPRIVATE static css::uno::Sequence< OUString > + generateAutomaticCategoriesFromCooSys( + const rtl::Reference< ::chart::BaseCoordinateSystem > & xCooSys ); + + static void switchToDateCategories( + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + static void switchToTextCategories( + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + static bool isSupportingDateAxis( const rtl::Reference< ::chart::Diagram >& xDiagram ); + static bool isDateNumberFormat( sal_Int32 nNumberFormat, const css::uno::Reference< css::util::XNumberFormats >& xNumberFormats ); + static sal_Int32 getDateNumberFormat( const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + static sal_Int32 getDateTimeInputNumberFormat( const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber ); + + static sal_Int32 getPercentNumberFormat( const css::uno::Reference< + css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + + static rtl::Reference< ChartType > + getChartTypeByIndex( const rtl::Reference< ::chart::Diagram >& xDiagram, sal_Int32 nIndex ); + + static std::vector< rtl::Reference< ChartType > > + getChartTypesFromDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram ); + + SAL_DLLPRIVATE static bool areChartTypesCompatible( + const rtl::Reference< ::chart::ChartType >& xFirstType, + const rtl::Reference< ::chart::ChartType >& xSecondType ); + + /** + * Test if a series can be moved. + * + * @param xDiagram + * Reference to the diagram that contains the series. + * + * @param xGivenDataSeries + * Reference to the series that should be tested for moving. + * + * @param bForward + * Direction of the move to be checked. + * + * @returns if the series can be moved. + * + */ + static bool isSeriesMoveable( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const css::uno::Reference< css::chart2::XDataSeries >& xGivenDataSeries, + bool bForward ); + + /** + * Move a series forward or backward. + * + * @param xDiagram + * Reference to the diagram that contains the series. + * + * @param xGivenDataSeries + * Reference to the series that should be moved. + * + * @param bForward + * Direction in which the series should be moved. + * + * @returns if the series was moved successfully. + * + */ + static bool moveSeries( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const css::uno::Reference< css::chart2::XDataSeries >& xGivenDataSeries, + bool bForward ); + + static bool isSupportingFloorAndWall( const rtl::Reference< ::chart::Diagram > & xDiagram ); + + static bool isPieOrDonutChart( const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static sal_Int32 getGeometry3D( + const rtl::Reference< ::chart::Diagram > & xDiagram, + bool& rbFound, bool& rbAmbiguous ); + + static void setGeometry3D( + const rtl::Reference< ::chart::Diagram > & xDiagram, + sal_Int32 nNewGeometry ); + + //returns integer from constant group css::chart::MissingValueTreatment + static sal_Int32 getCorrectedMissingValueTreatment( + const rtl::Reference< ::chart::Diagram > & xDiagram, + const rtl::Reference< ::chart::ChartType >& xChartType ); + + static DiagramPositioningMode getDiagramPositioningMode( const rtl::Reference< ::chart::Diagram > & xDiagram ); + + static bool setDiagramPositioning( const rtl::Reference<::chart::ChartModel>& xChartModel, + const css::awt::Rectangle& rPosRect /*100th mm*/ ); + + static css::awt::Rectangle getDiagramRectangleFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static bool switchDiagramPositioningToExcludingPositioning( ChartModel& rModel + , bool bResetModifiedState //set model back to unchanged if it was unchanged before + , bool bConvertAlsoFromAutoPositioning ); + +private: + DiagramHelper() = delete; + +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/DisposeHelper.hxx b/chart2/source/inc/DisposeHelper.hxx new file mode 100644 index 000000000..8c9b0b7d4 --- /dev/null +++ b/chart2/source/inc/DisposeHelper.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart::DisposeHelper +{ +template void Dispose(const T& xInterface) +{ + css::uno::Reference xComponent(xInterface, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + +template void DisposeAndClear(css::uno::Reference& rInterface) +{ + Dispose>(rInterface); + rInterface.set(nullptr); +} + +template void DisposeAllElements(Container& rContainer) +{ + for (const auto& rElement : rContainer) + { + Dispose(rElement); + } +} + +} // namespace chart::DisposeHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ErrorBar.hxx b/chart2/source/inc/ErrorBar.hxx new file mode 100644 index 000000000..bf31ed364 --- /dev/null +++ b/chart2/source/inc/ErrorBar.hxx @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "charttoolsdllapi.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" + + +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::chart2::data::XDataSource, + css::chart2::data::XDataSink, + css::beans::XPropertySet, + css::beans::XPropertyState > + ErrorBar_Base; +} + +class ErrorBar final : + public cppu::BaseMutex, + public impl::ErrorBar_Base +{ +private: + OUString maDashName; + css::drawing::LineDash maLineDash; + sal_Int32 mnLineWidth; + css::drawing::LineStyle meLineStyle; + css::util::Color maLineColor; + sal_Int16 mnLineTransparence; + css::drawing::LineJoint meLineJoint; + bool mbShowPositiveError; + bool mbShowNegativeError; + double mfPositiveError; + double mfNegativeError; + double mfWeight; + sal_Int32 meStyle; + +public: + OOO_DLLPUBLIC_CHARTTOOLS explicit ErrorBar(); + virtual ~ErrorBar() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + // XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& rPropName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( + const css::uno::Sequence< OUString >& rPropNames ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& rPropName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& rPropName ) override; + +private: + ErrorBar( const ErrorBar & rOther ); + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ XDataSink ____ + virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > >& aData ) override; + + // ____ XDataSource ____ + virtual css::uno::Sequence< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > SAL_CALL getDataSequences() override; + + typedef std::vector< css::uno::Reference< + css::chart2::data::XLabeledDataSequence > > tDataSequenceContainer; + tDataSequenceContainer m_aDataSequences; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/EventListenerHelper.hxx b/chart2/source/inc/EventListenerHelper.hxx new file mode 100644 index 000000000..a042c0067 --- /dev/null +++ b/chart2/source/inc/EventListenerHelper.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace com::sun::star::lang { class XEventListener; } + +namespace chart +{ +namespace EventListenerHelper +{ + +namespace impl +{ + +template< class InterfaceRef > +struct addListenerFunctor +{ + explicit addListenerFunctor( const css::uno::Reference< css::lang::XEventListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const InterfaceRef & xObject ) + { + css::uno::Reference< css::lang::XComponent > + xBroadcaster( xObject, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->addEventListener( m_xListener ); + } +private: + css::uno::Reference< css::lang::XEventListener > m_xListener; +}; + +template< class InterfaceRef > +struct removeListenerFunctor +{ + explicit removeListenerFunctor( const css::uno::Reference< css::lang::XEventListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const InterfaceRef & xObject ) + { + css::uno::Reference< css::lang::XComponent > + xBroadcaster( xObject, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->removeEventListener( m_xListener ); + } +private: + css::uno::Reference< css::lang::XEventListener > m_xListener; +}; + +} // namespace impl + +template< class InterfaceRef > +void addListener( + const InterfaceRef & xObject, + const css::uno::Reference< css::lang::XEventListener > & xListener ) +{ + if( xListener.is()) + { + impl::addListenerFunctor< InterfaceRef > aFunctor( xListener ); + aFunctor( xObject ); + } +} + +template< class Container > +void addListenerToAllElements( + const Container & rContainer, + const css::uno::Reference< css::lang::XEventListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::addListenerFunctor< typename Container::value_type >( xListener )); +} + +template< class InterfaceRef > +void removeListener( + const InterfaceRef & xObject, + const css::uno::Reference< css::lang::XEventListener > & xListener ) +{ + if( xListener.is()) + { + impl::removeListenerFunctor< InterfaceRef > aFunctor( xListener ); + aFunctor( xObject ); + } +} + +template< class Container > +void removeListenerFromAllElements( + const Container & rContainer, + const css::uno::Reference< css::lang::XEventListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::removeListenerFunctor< typename Container::value_type >( xListener )); +} + +} // namespace EventListenerHelper +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ExplicitCategoriesProvider.hxx b/chart2/source/inc/ExplicitCategoriesProvider.hxx new file mode 100644 index 000000000..6b68f8d2d --- /dev/null +++ b/chart2/source/inc/ExplicitCategoriesProvider.hxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" +#include +#include +#include + +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::uno { class Any; } + +namespace chart +{ +class BaseCoordinateSystem; +class LabeledDataSequence; + +struct OOO_DLLPUBLIC_CHARTTOOLS ComplexCategory +{ + OUString Text; + sal_Int32 Count; + + ComplexCategory( const OUString& rText, sal_Int32 nCount ) : Text( rText ), Count (nCount) + {} +}; + +class SplitCategoriesProvider +{ +public: + virtual ~SplitCategoriesProvider(); + + virtual sal_Int32 getLevelCount() const = 0; + virtual css::uno::Sequence< OUString > getStringsForLevel( sal_Int32 nIndex ) const = 0; +}; + +class OOO_DLLPUBLIC_CHARTTOOLS ExplicitCategoriesProvider final +{ +public: + ExplicitCategoriesProvider( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSysModel + , ChartModel& rChartModel + ); + ~ExplicitCategoriesProvider(); + + void init(); + + css::uno::Reference< css::chart2::data::XDataSequence > getOriginalCategories(); + + css::uno::Sequence< OUString > const & getSimpleCategories(); + const std::vector* getCategoriesByLevel( sal_Int32 nLevel ); + + static OUString getCategoryByIndex( + const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSysModel + , ChartModel& rModel + , sal_Int32 nIndex ); + + static css::uno::Sequence< OUString > getExplicitSimpleCategories( + const SplitCategoriesProvider& rSplitCategoriesProvider ); + + static void convertCategoryAnysToText( css::uno::Sequence< OUString >& rOutTexts + , const css::uno::Sequence< css::uno::Any >& rInAnys + , ChartModel& rModel ); + + bool hasComplexCategories() const; + sal_Int32 getCategoryLevelCount() const; + + const std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence> >& + getSplitCategoriesList() const { return m_aSplitCategoriesList;} + + bool isDateAxis(); + const std::vector< double >& getDateCategories(); + +private: + ExplicitCategoriesProvider(ExplicitCategoriesProvider const &) = delete; + ExplicitCategoriesProvider& operator =(ExplicitCategoriesProvider const &) = delete; + + bool volatile m_bDirty; + unotools::WeakReference< ::chart::BaseCoordinateSystem > m_xCooSysModel; + ChartModel& mrModel; + css::uno::Reference< css::chart2::data::XLabeledDataSequence> m_xOriginalCategories; + + bool m_bIsExplicitCategoriesInited; + css::uno::Sequence< OUString > m_aExplicitCategories; + std::vector< std::vector< ComplexCategory > > m_aComplexCats; + std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence> > m_aSplitCategoriesList; + + bool m_bIsDateAxis; + bool m_bIsAutoDate; + std::vector< double > m_aDateCategories; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ExponentialRegressionCurveCalculator.hxx b/chart2/source/inc/ExponentialRegressionCurveCalculator.hxx new file mode 100644 index 000000000..c929ac80c --- /dev/null +++ b/chart2/source/inc/ExponentialRegressionCurveCalculator.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" + +namespace chart +{ + +class ExponentialRegressionCurveCalculator final : public RegressionCurveCalculator +{ +public: + ExponentialRegressionCurveCalculator(); + virtual ~ExponentialRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + virtual double SAL_CALL getCurveValue( double x ) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + // formula is: f(x) = m_fSign * exp(m_fLogIntercept) * exp( m_fLogSlope * x ) + // mathematical model f(x) = Intercept * Slope^x + double m_fLogSlope; + double m_fLogIntercept; + double m_fSign; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/FastPropertyIdRanges.hxx b/chart2/source/inc/FastPropertyIdRanges.hxx new file mode 100644 index 000000000..d06809e44 --- /dev/null +++ b/chart2/source/inc/FastPropertyIdRanges.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +namespace chart +{ +enum FastPropertyIdRanges +{ + FAST_PROPERTY_ID_START = 10000, + FAST_PROPERTY_ID_START_DATA_SERIES = FAST_PROPERTY_ID_START + 1000, + FAST_PROPERTY_ID_START_DATA_POINT = FAST_PROPERTY_ID_START + 2000, + FAST_PROPERTY_ID_START_CHAR_PROP = FAST_PROPERTY_ID_START + 3000, + FAST_PROPERTY_ID_START_LINE_PROP = FAST_PROPERTY_ID_START + 4000, + FAST_PROPERTY_ID_START_FILL_PROP = FAST_PROPERTY_ID_START + 5000, + FAST_PROPERTY_ID_START_USERDEF_PROP = FAST_PROPERTY_ID_START + 6000, + FAST_PROPERTY_ID_START_SCENE_PROP = FAST_PROPERTY_ID_START + 7000, + // FAST_PROPERTY_ID_START_NAMED_FILL_PROP = FAST_PROPERTY_ID_START + 8000, + // FAST_PROPERTY_ID_START_NAMED_LINE_PROP = FAST_PROPERTY_ID_START + 9000, + FAST_PROPERTY_ID_START_CHART_STATISTIC_PROP = FAST_PROPERTY_ID_START + 12000, + FAST_PROPERTY_ID_START_CHART_SYMBOL_PROP = FAST_PROPERTY_ID_START + 13000, + FAST_PROPERTY_ID_START_CHART_DATACAPTION_PROP = FAST_PROPERTY_ID_START + 14000, + FAST_PROPERTY_ID_START_CHART_SPLINE_PROP = FAST_PROPERTY_ID_START + 15000, + FAST_PROPERTY_ID_START_CHART_STOCK_PROP = FAST_PROPERTY_ID_START + 16000, + FAST_PROPERTY_ID_START_CHART_AUTOPOSITION_PROP = FAST_PROPERTY_ID_START + 17000, + FAST_PROPERTY_ID_START_SCALE_TEXT_PROP = FAST_PROPERTY_ID_START + 18000, +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/FillProperties.hxx b/chart2/source/inc/FillProperties.hxx new file mode 100644 index 000000000..84759cfa0 --- /dev/null +++ b/chart2/source/inc/FillProperties.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyHelper.hxx" +#include "FastPropertyIdRanges.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements service FillProperties +namespace FillProperties +{ + // FastProperty Ids for properties + enum + { + // com.sun.star.drawing.FillProperties + PROP_FILL_STYLE = FAST_PROPERTY_ID_START_FILL_PROP + , PROP_FILL_COLOR + , PROP_FILL_TRANSPARENCE + , PROP_FILL_TRANSPARENCE_GRADIENT_NAME +// , PROP_FILL_TRANSPARENCE_GRADIENT //optional + , PROP_FILL_GRADIENT_NAME + , PROP_FILL_GRADIENT_STEPCOUNT +// , PROP_FILL_GRADIENT //optional + , PROP_FILL_HATCH_NAME +// , PROP_FILL_HATCH //optional + // bitmap properties start + , PROP_FILL_BITMAP_NAME +// , PROP_FILL_BITMAP //optional +// , PROP_FILL_BITMAP_URL //optional + , PROP_FILL_BITMAP_OFFSETX + , PROP_FILL_BITMAP_OFFSETY + , PROP_FILL_BITMAP_POSITION_OFFSETX + , PROP_FILL_BITMAP_POSITION_OFFSETY + , PROP_FILL_BITMAP_RECTANGLEPOINT + , PROP_FILL_BITMAP_LOGICALSIZE + , PROP_FILL_BITMAP_SIZEX + , PROP_FILL_BITMAP_SIZEY + , PROP_FILL_BITMAP_MODE + // bitmap properties end + , PROP_FILL_BACKGROUND + }; + + OOO_DLLPUBLIC_CHARTTOOLS void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + OOO_DLLPUBLIC_CHARTTOOLS void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/FormattedStringHelper.hxx b/chart2/source/inc/FormattedStringHelper.hxx new file mode 100644 index 000000000..45ce0b301 --- /dev/null +++ b/chart2/source/inc/FormattedStringHelper.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XFormattedString2; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::uno { template class Reference; } + +namespace chart +{ + +class FormattedStringHelper +{ +public: + static css::uno::Sequence< + css::uno::Reference< css::chart2::XFormattedString2 > > + createFormattedStringSequence( + const css::uno::Reference< css::uno::XComponentContext > & xContext + , const OUString & rString + , const css::uno::Reference< css::beans::XPropertySet > & xTextProperties ) noexcept; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/InternalData.hxx b/chart2/source/inc/InternalData.hxx new file mode 100644 index 000000000..9d9abeb3a --- /dev/null +++ b/chart2/source/inc/InternalData.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include + +namespace chart +{ + +class InternalData +{ +public: + InternalData(); + + void createDefaultData(); + + void setData( const css::uno::Sequence< css::uno::Sequence< double > > & rDataInRows ); + css::uno::Sequence< css::uno::Sequence< double > > getData() const; + + css::uno::Sequence< double > getColumnValues( sal_Int32 nColumnIndex ) const; + css::uno::Sequence< double > getRowValues( sal_Int32 nRowIndex ) const; + + void setColumnValues( sal_Int32 nColumnIndex, const std::vector< double > & rNewData ); + void setRowValues( sal_Int32 nRowIndex, const std::vector< double > & rNewData ); + + void setComplexColumnLabel( sal_Int32 nColumnIndex, std::vector< css::uno::Any >&& rComplexLabel ); + void setComplexRowLabel( sal_Int32 nRowIndex, std::vector< css::uno::Any >&& rComplexLabel ); + + std::vector< css::uno::Any > getComplexColumnLabel( sal_Int32 nColumnIndex ) const; + std::vector< css::uno::Any > getComplexRowLabel( sal_Int32 nRowIndex ) const; + + void swapRowWithNext( sal_Int32 nRowIndex ); + void swapColumnWithNext( sal_Int32 nColumnIndex ); + + void insertColumn( sal_Int32 nAfterIndex ); + void insertRow( sal_Int32 nAfterIndex ); + void deleteColumn( sal_Int32 nAtIndex ); + void deleteRow( sal_Int32 nAtIndex ); + + /// @return the index of the newly appended column + sal_Int32 appendColumn(); + /// @return the index of the newly appended row + sal_Int32 appendRow(); + + sal_Int32 getRowCount() const; + sal_Int32 getColumnCount() const; + + typedef std::vector< std::vector< css::uno::Any > > tVecVecAny; //inner index is hierarchical level + + void setComplexRowLabels( tVecVecAny&& rNewRowLabels ); + const tVecVecAny& getComplexRowLabels() const; + void setComplexColumnLabels( tVecVecAny&& rNewColumnLabels ); + const tVecVecAny& getComplexColumnLabels() const; + + void dump() const; + +private: //methods + /** resizes the data if at least one of the given dimensions is larger than + before. The data is never becoming smaller only larger. + + @return , if the data was enlarged + */ + bool enlargeData( sal_Int32 nColumnCount, sal_Int32 nRowCount ); + +private: + sal_Int32 m_nColumnCount; + sal_Int32 m_nRowCount; + + typedef std::valarray< double > tDataType; + tDataType m_aData; + tVecVecAny m_aRowLabels;//outer index is row index, inner index is category level + tVecVecAny m_aColumnLabels;//outer index is column index +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/InternalDataProvider.hxx b/chart2/source/inc/InternalDataProvider.hxx new file mode 100644 index 000000000..a5032efcd --- /dev/null +++ b/chart2/source/inc/InternalDataProvider.hxx @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "InternalData.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::chart2 { class XChartDocument; } + +namespace chart +{ +class ChartModel; +class UncachedDataSequence; + +namespace impl +{ + +typedef ::cppu::WeakImplHelper< + css::chart2::XInternalDataProvider, + css::chart2::data::XRangeXMLConversion, + css::chart2::XAnyDescriptionAccess, + css::chart::XDateCategories, + css::util::XCloneable, + css::lang::XInitialization, + css::lang::XServiceInfo > + InternalDataProvider_Base; +} + +/** Data provider that handles data internally. This is used for charts with + their own data. + +

The format for single ranges is "categories|label n|n" where n is a + non-negative number. Meaning return all categories, the label of sequence n, + or the data of sequence n.

+ +

The format for a complete range is "all". (Do we need more than + that?)

+ */ +class InternalDataProvider final : + public impl::InternalDataProvider_Base +{ +public: + explicit InternalDataProvider(); + + // #i120559# allow handing over a default for data orientation + // (DataInColumns) that will be used when no data is available + explicit InternalDataProvider( + const rtl::Reference< ::chart::ChartModel > & xChartDoc, + bool bConnectToModel, + bool bDefaultDataInColumns ); + explicit InternalDataProvider( const InternalDataProvider & rOther ); + virtual ~InternalDataProvider() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XInternalDataProvider ____ + virtual sal_Bool SAL_CALL hasDataByRangeRepresentation( const OUString& aRange ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL + getDataByRangeRepresentation( const OUString& aRange ) override; + virtual void SAL_CALL setDataByRangeRepresentation( + const OUString& aRange, + const css::uno::Sequence< css::uno::Any >& aNewData ) override; + virtual void SAL_CALL insertSequence( ::sal_Int32 nAfterIndex ) override; + virtual void SAL_CALL deleteSequence( ::sal_Int32 nAtIndex ) override; + virtual void SAL_CALL appendSequence() override; + virtual void SAL_CALL insertComplexCategoryLevel( ::sal_Int32 nLevel ) override; + virtual void SAL_CALL deleteComplexCategoryLevel( ::sal_Int32 nLevel ) override; + virtual void SAL_CALL insertDataPointForAllSequences( ::sal_Int32 nAfterIndex ) override; + virtual void SAL_CALL deleteDataPointForAllSequences( ::sal_Int32 nAtIndex ) override; + virtual void SAL_CALL swapDataPointWithNextOneForAllSequences( ::sal_Int32 nAtIndex ) override; + virtual void SAL_CALL registerDataSequenceForChanges( + const css::uno::Reference< css::chart2::data::XDataSequence >& xSeq ) override; + + // ____ XDataProvider (base of XInternalDataProvider) ____ + virtual sal_Bool SAL_CALL createDataSourcePossible( + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) override; + virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource( + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) override; + virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource ) override; + virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible( + const OUString& aRangeRepresentation ) override; + virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation( + const OUString& aRangeRepresentation ) override; + + virtual css::uno::Reference SAL_CALL + createDataSequenceByValueArray( const OUString& aRole, const OUString& aRangeRepresentation, + const OUString& aRoleQualifier ) override; + + virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override; + + // ____ XRangeXMLConversion ____ + virtual OUString SAL_CALL convertRangeToXML( + const OUString& aRangeRepresentation ) override; + virtual OUString SAL_CALL convertRangeFromXML( + const OUString& aXMLRange ) override; + + // ____ XDateCategories ____ + virtual css::uno::Sequence< double > SAL_CALL getDateCategories() override; + virtual void SAL_CALL setDateCategories( const css::uno::Sequence< double >& rDates ) override; + + // ____ XAnyDescriptionAccess ____ + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyRowDescriptions() override; + virtual void SAL_CALL setAnyRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< css::uno::Any > > SAL_CALL + getAnyColumnDescriptions() override; + virtual void SAL_CALL setAnyColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< css::uno::Any > >& aColumnDescriptions ) override; + + // ____ XComplexDescriptionAccess (base of XAnyDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexRowDescriptions() override; + virtual void SAL_CALL setComplexRowDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aRowDescriptions ) override; + virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL + getComplexColumnDescriptions() override; + virtual void SAL_CALL setComplexColumnDescriptions( + const css::uno::Sequence< css::uno::Sequence< OUString > >& aColumnDescriptions ) override; + + // ____ XChartDataArray (base of XComplexDescriptionAccess) ____ + virtual css::uno::Sequence< css::uno::Sequence< double > > SAL_CALL getData() override; + virtual void SAL_CALL setData( + const css::uno::Sequence< css::uno::Sequence< double > >& aData ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getRowDescriptions() override; + virtual void SAL_CALL setRowDescriptions( + const css::uno::Sequence< OUString >& aRowDescriptions ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getColumnDescriptions() override; + virtual void SAL_CALL setColumnDescriptions( + const css::uno::Sequence< OUString >& aColumnDescriptions ) override; + + // ____ XChartData (base of XChartDataArray) ____ + virtual void SAL_CALL addChartDataChangeEventListener( + const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual void SAL_CALL removeChartDataChangeEventListener( + const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override; + virtual double SAL_CALL getNotANumber() override; + virtual sal_Bool SAL_CALL isNotANumber( + double nNumber ) override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + // css::lang::XInitialization: + virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override; + +private: + void addDataSequenceToMap( + const OUString & rRangeRepresentation, + const css::uno::Reference< css::chart2::data::XDataSequence > & xSequence ); + + css::uno::Reference< css::chart2::data::XDataSequence > + createDataSequenceAndAddToMap( const OUString & rRangeRepresentation, + const OUString & rRole ); + rtl::Reference< UncachedDataSequence > + createDataSequenceAndAddToMap( const OUString & rRangeRepresentation ); + + rtl::Reference + createDataSequenceFromArray( const OUString& rArrayStr, std::u16string_view rRole, + std::u16string_view rRoleQualifier); + + void deleteMapReferences( const OUString & rRangeRepresentation ); + + void adaptMapReferences( + const OUString & rOldRangeRepresentation, + const OUString & rNewRangeRepresentation ); + + void increaseMapReferences( sal_Int32 nBegin, sal_Int32 nEnd ); + void decreaseMapReferences( sal_Int32 nBegin, sal_Int32 nEnd ); + + typedef std::multimap< OUString, + css::uno::WeakReference< css::chart2::data::XDataSequence > > + tSequenceMap; + typedef std::pair< tSequenceMap::iterator, tSequenceMap::iterator > tSequenceMapRange; + + /** cache for all sequences that have been returned. + + If the range-representation of a sequence changes and it is still + referred to by some component (weak reference is valid), the range will + be adapted. + */ + tSequenceMap m_aSequenceMap; + InternalData m_aInternalData; + bool m_bDataInColumns; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LabeledDataSequence.hxx b/chart2/source/inc/LabeledDataSequence.hxx new file mode 100644 index 000000000..9f9e1c793 --- /dev/null +++ b/chart2/source/inc/LabeledDataSequence.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include "ModifyListenerHelper.hxx" +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::util { class XCloneable; } +namespace com::sun::star::util { class XModifyListener; } + +namespace chart +{ + +namespace impl +{ +typedef cppu::WeakImplHelper< + css::chart2::data::XLabeledDataSequence2, + css::lang::XServiceInfo > + LabeledDataSequence_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS LabeledDataSequence final : + public cppu::BaseMutex, + public impl::LabeledDataSequence_Base +{ +public: + explicit LabeledDataSequence(); + explicit LabeledDataSequence(const LabeledDataSequence &); + explicit LabeledDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & rValues ); + explicit LabeledDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & rValues, + const css::uno::Reference< css::chart2::data::XDataSequence > & rLabels ); + + virtual ~LabeledDataSequence() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XLabeledDataSequence ____ + virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL getValues() override; + virtual void SAL_CALL setValues( + const css::uno::Reference< css::chart2::data::XDataSequence >& xSequence ) override; + virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL getLabel() override; + virtual void SAL_CALL setLabel( + const css::uno::Reference< css::chart2::data::XDataSequence >& xSequence ) override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + css::uno::Reference< css::chart2::data::XDataSequence > m_xData; + css::uno::Reference< css::chart2::data::XDataSequence > m_xLabel; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/Legend.hxx b/chart2/source/inc/Legend.hxx new file mode 100644 index 000000000..728d60d8a --- /dev/null +++ b/chart2/source/inc/Legend.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" +#include "charttoolsdllapi.hxx" + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XLegend, + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + Legend_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS Legend final : + public cppu::BaseMutex, + public impl::Legend_Base, + public ::property::OPropertySet +{ +public: + explicit Legend(); + virtual ~Legend() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + + explicit Legend( const Legend & rOther ); + +private: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + +public: + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LegendHelper.hxx b/chart2/source/inc/LegendHelper.hxx new file mode 100644 index 000000000..f2bf2e55f --- /dev/null +++ b/chart2/source/inc/LegendHelper.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" + +namespace chart { class ChartModel; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XLegend; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ +class Diagram; +class Legend; + +class OOO_DLLPUBLIC_CHARTTOOLS LegendHelper +{ +public: + static rtl::Reference< ::chart::Legend > + showLegend( ChartModel& rModel + , const css::uno::Reference< css::uno::XComponentContext >& xContext ); + + static void hideLegend( ChartModel& rModel ); + + static rtl::Reference< ::chart::Legend > + getLegend( ChartModel& rModel + , const css::uno::Reference< css::uno::XComponentContext >& xContext = nullptr + , bool bCreate = false ); + + /** returns , if either there is no legend at the diagram, or there + is a legend which has a "Show" property of value . Otherwise, + is returned. + */ + static bool hasLegend( const rtl::Reference< ::chart::Diagram > & xDiagram ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LifeTime.hxx b/chart2/source/inc/LifeTime.hxx new file mode 100644 index 000000000..613d92314 --- /dev/null +++ b/chart2/source/inc/LifeTime.hxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::lang { class XComponent; } +namespace com::sun::star::util { class CloseVetoException; } +namespace com::sun::star::util { class XCloseListener; } +namespace com::sun::star::util { class XCloseable; } + +namespace apphelper +{ + +class OOO_DLLPUBLIC_CHARTTOOLS LifeTimeManager +{ +friend class LifeTimeGuard; +protected: + mutable ::osl::Mutex m_aAccessMutex; +public: + LifeTimeManager( css::lang::XComponent* pComponent ); + virtual ~LifeTimeManager(); + + bool impl_isDisposed( bool bAssert=true ); + /// @throws css::uno::RuntimeException + bool dispose(); + +public: + ::comphelper::OMultiTypeInterfaceContainerHelper2 m_aListenerContainer; + +protected: + SAL_DLLPRIVATE virtual bool impl_canStartApiCall(); + SAL_DLLPRIVATE virtual void impl_apiCallCountReachedNull(){} + + SAL_DLLPRIVATE void impl_registerApiCall(bool bLongLastingCall); + SAL_DLLPRIVATE void impl_unregisterApiCall(bool bLongLastingCall); + +protected: + css::lang::XComponent* m_pComponent; + + ::osl::Condition m_aNoAccessCountCondition; + sal_Int32 m_nAccessCount; + + bool volatile m_bDisposed; + bool volatile m_bInDispose; + + ::osl::Condition m_aNoLongLastingCallCountCondition; + sal_Int32 m_nLongLastingCallCount; +}; + +class CloseableLifeTimeManager final : public LifeTimeManager +{ + css::util::XCloseable* m_pCloseable; + + ::osl::Condition m_aEndTryClosingCondition; + bool volatile m_bClosed; + bool volatile m_bInTryClose; + //the ownership between model and controller is not clear at first + //each controller might consider him as owner of the model first + //at start the model is not considered as owner of itself + bool volatile m_bOwnership; + +public: + CloseableLifeTimeManager( css::util::XCloseable* pCloseable + , css::lang::XComponent* pComponent ); + virtual ~CloseableLifeTimeManager() override; + + bool impl_isDisposedOrClosed( bool bAssert=true ); +/// @throws css::uno::Exception + bool g_close_startTryClose(bool bDeliverOwnership); +/// @throws css::util::CloseVetoException + void g_close_isNeedToCancelLongLastingCalls( bool bDeliverOwnership, css::util::CloseVetoException const & ex ); + void g_close_endTryClose(bool bDeliverOwnership ); + void g_close_endTryClose_doClose(); +/// @throws css::uno::RuntimeException + void g_addCloseListener( const css::uno::Reference< css::util::XCloseListener > & xListener ); + +private: + virtual bool impl_canStartApiCall() override; + virtual void impl_apiCallCountReachedNull() override; + + void impl_setOwnership( bool bDeliverOwnership, bool bMyVeto ); + void impl_doClose(); +}; + +/* +Use this Guard in your ApiCalls to protect access on resources +which will be released in dispose. +It's guaranteed that the release of resources only starts if your +guarded call has finished. +! It's only partly guaranteed that this resources will not change during the call. +See the example for details. + +This class is to be used as described in the example. + +If this guard is used in all api calls of an XCloseable object +it's guaranteed that the closeable will close itself after finishing the last call +if it should do so. + + ::ApiCall +{ + //hold no mutex!!! + LifeTimeGuard aLifeTimeGuard(m_aLifeTimeManager); + + //mutex is acquired; call is not registered + + if(!aLifeTimeGuard.startApiCall()) + return ; //behave as passive as possible, if disposed or closed + + //mutex is acquired, call is registered + { + //you might access some private members here + //but then you need to protect access to these members always like this + //never call to the outside here + } + + aLifeTimeGuard.clear(); //!!! + + //Mutex is released, the running call is still registered + //this call will finish before the 'release-section' in dispose is allowed to start + + { + //you might access some private members here guarded with your own mutex + //but release your mutex at the end of this block + } + + //you can call to the outside (without holding the mutex) without becoming disposed + + //End of method -> ~LifeTimeGuard + //-> call is unregistered + //-> this object might be disposed now +} + +your XComponent::dispose method has to be implemented in the following way: + + ::dispose() +{ + //hold no mutex!!! + if( !m_aLifeTimeManager.dispose() ) + return; + + //--release all resources and references + +} + +*/ + +class LifeTimeGuard +{ + +public: + LifeTimeGuard( LifeTimeManager& rManager ) + : m_guard( rManager.m_aAccessMutex ) + , m_rManager(rManager) + , m_bCallRegistered(false) + , m_bLongLastingCallRegistered(false) + { + + } + bool startApiCall(bool bLongLastingCall=false); + ~LifeTimeGuard(); + void clear() { m_guard.clear(); } + +private: + osl::ClearableMutexGuard m_guard; + LifeTimeManager& m_rManager; + bool m_bCallRegistered; + bool m_bLongLastingCallRegistered; + +private: + LifeTimeGuard( const LifeTimeGuard& ) = delete; + LifeTimeGuard& operator= ( const LifeTimeGuard& ) = delete; +}; + +template +class NegativeGuard final +{ + T * m_pT; +public: + + NegativeGuard(T & t) : m_pT(&t) + { + m_pT->release(); + } + + ~NegativeGuard() + { + m_pT->acquire(); + } +}; + +}//end namespace apphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LinePropertiesHelper.hxx b/chart2/source/inc/LinePropertiesHelper.hxx new file mode 100644 index 000000000..2999de81a --- /dev/null +++ b/chart2/source/inc/LinePropertiesHelper.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyHelper.hxx" +#include "FastPropertyIdRanges.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::beans { struct Property; } +namespace com::sun::star::uno { template class Reference; } + +namespace chart +{ + +// implements service LineProperties +namespace LinePropertiesHelper +{ + // FastProperty Ids for properties + enum + { + // com.sun.star.drawing.LineProperties + PROP_LINE_STYLE = FAST_PROPERTY_ID_START_LINE_PROP, + PROP_LINE_DASH, + PROP_LINE_DASH_NAME, //not in service description + PROP_LINE_COLOR, + PROP_LINE_TRANSPARENCE, + PROP_LINE_WIDTH, + PROP_LINE_JOINT, + PROP_LINE_CAP + }; + + OOO_DLLPUBLIC_CHARTTOOLS void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + OOO_DLLPUBLIC_CHARTTOOLS void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); + + bool IsLineVisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ); + void SetLineVisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ); + void SetLineInvisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ); + void SetLineColor( const css::uno::Reference< + css::beans::XPropertySet >& xGridProperties, sal_Int32 nColor ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LinearRegressionCurveCalculator.hxx b/chart2/source/inc/LinearRegressionCurveCalculator.hxx new file mode 100644 index 000000000..05853b26a --- /dev/null +++ b/chart2/source/inc/LinearRegressionCurveCalculator.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PolynomialRegressionCurveCalculator.hxx" + +namespace chart +{ + +class LinearRegressionCurveCalculator final : public PolynomialRegressionCurveCalculator +{ +public: + LinearRegressionCurveCalculator(); + virtual ~LinearRegressionCurveCalculator() override; + +private: + virtual void SAL_CALL setRegressionProperties( + sal_Int32 aDegree, + sal_Bool aForceIntercept, + double aInterceptValue, + sal_Int32 aPeriod, + sal_Int32 nMovingType) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/LogarithmicRegressionCurveCalculator.hxx b/chart2/source/inc/LogarithmicRegressionCurveCalculator.hxx new file mode 100644 index 000000000..02fa1fc22 --- /dev/null +++ b/chart2/source/inc/LogarithmicRegressionCurveCalculator.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" + +namespace chart +{ + +class LogarithmicRegressionCurveCalculator final : public RegressionCurveCalculator +{ +public: + LogarithmicRegressionCurveCalculator(); + virtual ~LogarithmicRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + virtual double SAL_CALL getCurveValue( double x ) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + // formula is: f(x) = m_fSlope * log( x ) + m_fIntercept + double m_fSlope; + double m_fIntercept; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/MeanValueRegressionCurveCalculator.hxx b/chart2/source/inc/MeanValueRegressionCurveCalculator.hxx new file mode 100644 index 000000000..be46e9738 --- /dev/null +++ b/chart2/source/inc/MeanValueRegressionCurveCalculator.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" + +namespace chart +{ + +class MeanValueRegressionCurveCalculator final : public RegressionCurveCalculator +{ +public: + MeanValueRegressionCurveCalculator(); + virtual ~MeanValueRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + virtual double SAL_CALL getCurveValue( double x ) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + // formula is: f(x) = m_fMeanValue + double m_fMeanValue; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/MediaDescriptorHelper.hxx b/chart2/source/inc/MediaDescriptorHelper.hxx new file mode 100644 index 000000000..cfef8fc14 --- /dev/null +++ b/chart2/source/inc/MediaDescriptorHelper.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::beans { struct PropertyValue; } +namespace com::sun::star::embed { class XStorage; } +namespace com::sun::star::io { class XInputStream; } +namespace com::sun::star::io { class XOutputStream; } +namespace com::sun::star::io { class XStream; } + +/* +* This class helps to read and write the properties mentioned in the service description +* com.sun.star.document.MediaDescriptor from and to a sequence of PropertyValues. +* Properties that are not mentioned in the service description +* are stored in the member AdditionalProperties. +* +* As an additional feature this helper class can generate a reduced sequence of PropertyValues +* that does not contain properties which are known to be only view relevant. This +* reduced sequence than might be attached to a model directly. +*/ + +namespace apphelper +{ + +class OOO_DLLPUBLIC_CHARTTOOLS MediaDescriptorHelper final +{ +public: + MediaDescriptorHelper( const css::uno::Sequence< css::beans::PropertyValue > & rMediaDescriptor ); + + const css::uno::Sequence< css::beans::PropertyValue >& getReducedForModel() const { return m_aModelProperties;} + + //all properties given in the constructor are stored in the following three sequences + + //properties which should be given to a model are additionally stored in this sequence (not documented properties and deprecated properties are not included!) + css::uno::Sequence< css::beans::PropertyValue > + m_aModelProperties; //these are properties which are not described in service com.sun.star.document.MediaDescriptor + + OUString FilterName; //internal filter name. + bool ISSET_FilterName; + + OUString HierarchicalDocumentName; + + css::uno::Reference< css::io::XOutputStream > + OutputStream; //a stream to receive the document data for saving + bool ISSET_OutputStream; + css::uno::Reference< css::io::XInputStream > + InputStream; //content of document. + bool ISSET_InputStream; + + bool ReadOnly; //open document readonly. + + OUString URL;// FileName, URL of the document. + bool ISSET_URL; + + // new framework objects + css::uno::Reference< css::embed::XStorage > + Storage; + bool ISSET_Storage; + css::uno::Reference< css::io::XStream > + Stream; + bool ISSET_Stream; + +private: + SAL_DLLPRIVATE void impl_init(); +}; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ModifyListenerCallBack.hxx b/chart2/source/inc/ModifyListenerCallBack.hxx new file mode 100644 index 000000000..406804189 --- /dev/null +++ b/chart2/source/inc/ModifyListenerCallBack.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace chart +{ +/** Use this class as a member if you want to listen on a XModifyBroadcaster +without becoming a XModifyListener yourself + */ + +class ModifyListenerCallBack_impl; + +class OOO_DLLPUBLIC_CHARTTOOLS ModifyListenerCallBack final +{ +public: + explicit ModifyListenerCallBack(const Link& rCallBack); + + ~ModifyListenerCallBack(); + + void startListening( + const ::com::sun::star::uno::Reference<::com::sun::star::util::XModifyBroadcaster>& + xBroadcaster); + SAL_DLLPRIVATE void stopListening(); + +private: //methods + ModifyListenerCallBack(const ModifyListenerCallBack&) = delete; + +private: //member + ModifyListenerCallBack_impl* pModifyListener_impl; + css::uno::Reference m_xModifyListener; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ModifyListenerHelper.hxx b/chart2/source/inc/ModifyListenerHelper.hxx new file mode 100644 index 000000000..1042e5d20 --- /dev/null +++ b/chart2/source/inc/ModifyListenerHelper.hxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace chart +{ + +/** This helper class serves as forwarder of modify events. It can be used + whenever an object has to send modify events after it gets a modify event of + one of its children. + */ +class ModifyEventForwarder final : + public ::comphelper::WeakComponentImplHelper< + css::util::XModifyBroadcaster, + css::util::XModifyListener > +{ +public: + ModifyEventForwarder(); + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + +private: + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ WeakComponentImplHelperBase ____ + virtual void disposing(std::unique_lock& ) override; + + comphelper::OInterfaceContainerHelper4 m_aModifyListeners; +}; + +} + +namespace chart::ModifyListenerHelper +{ + +namespace impl +{ + +template< class InterfaceRef > +struct addListenerFunctor +{ + explicit addListenerFunctor( const css::uno::Reference< css::util::XModifyListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const InterfaceRef & xObject ) + { + css::uno::Reference< css::util::XModifyBroadcaster > + xBroadcaster( xObject, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->addModifyListener( m_xListener ); + } +private: + css::uno::Reference< css::util::XModifyListener > m_xListener; +}; + +template< class InterfaceRef > +struct removeListenerFunctor +{ + explicit removeListenerFunctor( const css::uno::Reference< css::util::XModifyListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const InterfaceRef & xObject ) + { + css::uno::Reference< css::util::XModifyBroadcaster > + xBroadcaster( xObject, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->removeModifyListener( m_xListener ); + } +private: + css::uno::Reference< css::util::XModifyListener > m_xListener; +}; + +template< class Pair > +struct addListenerToMappedElementFunctor +{ + explicit addListenerToMappedElementFunctor( const css::uno::Reference< css::util::XModifyListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const Pair & aPair ) + { + css::uno::Reference< css::util::XModifyBroadcaster > + xBroadcaster( aPair.second, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->addModifyListener( m_xListener ); + } +private: + css::uno::Reference< css::util::XModifyListener > m_xListener; +}; + +template< class Pair > +struct removeListenerFromMappedElementFunctor +{ + explicit removeListenerFromMappedElementFunctor( const css::uno::Reference< css::util::XModifyListener > & xListener ) : + m_xListener( xListener ) + {} + + void operator() ( const Pair & aPair ) + { + css::uno::Reference< css::util::XModifyBroadcaster > + xBroadcaster( aPair.second, css::uno::UNO_QUERY ); + if( xBroadcaster.is() && m_xListener.is()) + xBroadcaster->removeModifyListener( m_xListener ); + } +private: + css::uno::Reference< css::util::XModifyListener > m_xListener; +}; + +} // namespace impl + +template< class InterfaceRef > +void addListener( + const InterfaceRef & xObject, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + { + impl::addListenerFunctor< InterfaceRef > aFunctor( xListener ); + aFunctor( xObject ); + } +} +template< class T > +void addListener( + const rtl::Reference & xBroadcaster, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xBroadcaster && xListener ) + xBroadcaster->addModifyListener( xListener ); +} + +template< class Container > +void addListenerToAllElements( + const Container & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::addListenerFunctor< typename Container::value_type >( xListener )); +} + +template< class T > +void addListenerToAllElements( + const std::vector> & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( !xListener ) + return; + for (auto const & i : rContainer) + i->addModifyListener(xListener); +} + +template< class Container > +void addListenerToAllMapElements( + const Container & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::addListenerToMappedElementFunctor< typename Container::value_type >( xListener )); +} + +template< typename T > +void addListenerToAllSequenceElements( + const css::uno::Sequence< T > & rSequence, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rSequence.begin(), rSequence.end(), + impl::addListenerFunctor< T >( xListener )); +} + +template< class InterfaceRef > +void removeListener( + const InterfaceRef & xObject, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + { + impl::removeListenerFunctor< InterfaceRef > aFunctor( xListener ); + aFunctor( xObject ); + } +} + +template< class T > +void removeListener( + const rtl::Reference & xBroadcaster, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xBroadcaster && xListener ) + xBroadcaster->removeModifyListener( xListener ); +} + +template< class Container > +void removeListenerFromAllElements( + const Container & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::removeListenerFunctor< typename Container::value_type >( xListener )); +} + +template< class T > +void removeListenerFromAllElements( + const std::vector> & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( !xListener ) + return; + for (auto const & i : rContainer) + i->removeModifyListener(xListener); +} + +template< class Container > +void removeListenerFromAllMapElements( + const Container & rContainer, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rContainer.begin(), rContainer.end(), + impl::removeListenerFromMappedElementFunctor< typename Container::value_type >( xListener )); +} + +template< typename T > +void removeListenerFromAllSequenceElements( + const css::uno::Sequence< T > & rSequence, + const css::uno::Reference< css::util::XModifyListener > & xListener ) +{ + if( xListener.is()) + std::for_each( rSequence.begin(), rSequence.end(), + impl::removeListenerFunctor< T >( xListener )); +} + +} // namespace chart::ModifyListenerHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx b/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx new file mode 100644 index 000000000..f7e25fe51 --- /dev/null +++ b/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" +#include "RegressionCalculationHelper.hxx" +#include + +namespace chart +{ + +class MovingAverageRegressionCurveCalculator final : public RegressionCurveCalculator +{ +public: + MovingAverageRegressionCurveCalculator(); + virtual ~MovingAverageRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + virtual double SAL_CALL getCurveValue( double x ) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + void calculateValues(RegressionCalculationHelper::tDoubleVectorPair aValues, bool bUseXAvg); + void calculateValuesCentral(RegressionCalculationHelper::tDoubleVectorPair aValues); + std::vector aYList; + std::vector aXList; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/NameContainer.hxx b/chart2/source/inc/NameContainer.hxx new file mode 100644 index 000000000..12fc76978 --- /dev/null +++ b/chart2/source/inc/NameContainer.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::container::XNameContainer, + css::lang::XServiceInfo, + css::util::XCloneable > + NameContainer_Base; +} + +/// Contains the XML namespaces map +/// +class NameContainer final : public impl::NameContainer_Base +{ +public: + NameContainer(); + explicit NameContainer( const NameContainer & rOther ); + virtual ~NameContainer() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XNameContainer + virtual void SAL_CALL insertByName( const OUString& aName, const css::uno::Any& aElement ) override; + virtual void SAL_CALL removeByName( const OUString& Name ) override; + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override; + + // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + + // XElementAccess + virtual sal_Bool SAL_CALL hasElements( ) override; + virtual css::uno::Type SAL_CALL getElementType( ) override; + + // XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + +private: //member + + typedef std::map< OUString, css::uno::Any > tContentMap; + tContentMap m_aMap; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/NumberFormatterWrapper.hxx b/chart2/source/inc/NumberFormatterWrapper.hxx new file mode 100644 index 000000000..c3412fc9c --- /dev/null +++ b/chart2/source/inc/NumberFormatterWrapper.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" +#include +#include + +class SvNumberFormatter; +class Color; + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS NumberFormatterWrapper final +{ +public: + NumberFormatterWrapper( const css::uno::Reference< css::util::XNumberFormatsSupplier >& xSupplier ); + ~NumberFormatterWrapper(); + + SvNumberFormatter* getSvNumberFormatter() const { return m_pNumberFormatter;} + const css::uno::Reference< css::util::XNumberFormatsSupplier >& + getNumberFormatsSupplier() const { return m_xNumberFormatsSupplier; }; + + OUString getFormattedString( sal_Int32 nNumberFormatKey, double fValue, Color& rLabelColor, bool& rbColorChanged ) const; + Date getNullDate() const; + +private: //private member + css::uno::Reference< css::util::XNumberFormatsSupplier > + m_xNumberFormatsSupplier; + + SvNumberFormatter* m_pNumberFormatter; + css::uno::Any m_aNullDate; +}; + +class FixedNumberFormatter final +{ +public: + FixedNumberFormatter( const css::uno::Reference< css::util::XNumberFormatsSupplier >& xSupplier + , sal_Int32 nNumberFormatKey ); + ~FixedNumberFormatter(); + + OUString getFormattedString( double fValue, Color& rLabelColor, bool& rbColorChanged ) const; + +private: + NumberFormatterWrapper m_aNumberFormatterWrapper; + sal_uInt32 m_nNumberFormatKey; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/OPropertySet.hxx b/chart2/source/inc/OPropertySet.hxx new file mode 100644 index 000000000..bc603dbd9 --- /dev/null +++ b/chart2/source/inc/OPropertySet.hxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +// helper classes +#include + +// interfaces and types +#include +#include +#include +#include +#include "charttoolsdllapi.hxx" + +#include + +namespace property +{ + +class OOO_DLLPUBLIC_CHARTTOOLS OPropertySet : + public ::cppu::OBroadcastHelper, + // includes beans::XPropertySet, XMultiPropertySet and XFastPropertySet + public ::cppu::OPropertySetHelper, + // includes uno::XWeak (and XInterface, esp. ref-counting) + + public css::lang::XTypeProvider, + public css::beans::XPropertyState, + public css::beans::XMultiPropertyStates, + public css::style::XStyleSupplier +{ +public: + OPropertySet( ::osl::Mutex & rMutex ); + virtual ~OPropertySet(); + +protected: + explicit OPropertySet( const OPropertySet & rOther, ::osl::Mutex & rMutex ); + + void SetNewValuesExplicitlyEvenIfTheyEqualDefault(); + + /** implement this method to provide default values for all properties + supporting defaults. If a property does not have a default value, you + may throw an UnknownPropertyException. + We pass the any by reference because this code is very hot and doing + it this way is cheaper than the two step process of constructing a new + any and then assigning to via a return value. + + @throws css::beans::UnknownPropertyException + @throws css::uno::RuntimeException + */ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const = 0; + + /** The InfoHelper table contains all property names and types of + this object. + + @return the object that provides information for the + PropertySetInfo + + @see ::cppu::OPropertySetHelper + */ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override = 0; + + /** Try to convert the value rValue to the type required by the + property associated with nHandle. + + Override this method to take influence in modification of properties. + + If the conversion changed , is returned and the converted value + is in rConvertedValue. The former value is contained in + rOldValue. + + After this call returns successfully, the vetoable listeners are + notified. + + @throws IllegalArgumentException, if the conversion was not successful, + or if there is no corresponding property to the given handle. + + @param rConvertedValue the converted value. Only set if return is true. + @param rOldValue the old value. Only set if return is true. + @param nHandle the handle of the property. + + @return true, if the conversion was successful and converted value + differs from the old value. + + @see ::cppu::OPropertySetHelper + */ + virtual sal_Bool SAL_CALL convertFastPropertyValue + ( css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + /** The same as setFastPropertyValue; nHandle is always valid. + The changes must not be broadcasted in this method. + + @attention + Although you are permitted to throw any UNO exception, only the following + are valid for usage: + -- css::beans::UnknownPropertyException + -- css::beans::PropertyVetoException + -- css::lang::IllegalArgumentException + -- css::lang::WrappedTargetException + -- css::uno::RuntimeException + + @param nHandle handle + @param rValue value + + @see ::cppu::OPropertySetHelper + */ + virtual void SAL_CALL setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + /** + The same as getFastPropertyValue, but return the value through rValue and + nHandle is always valid. + + @see ::cppu::OPropertySetHelper + */ + virtual void SAL_CALL getFastPropertyValue + ( css::uno::Any& rValue, + sal_Int32 nHandle ) const override; + + /// make original interface function visible again + using ::com::sun::star::beans::XFastPropertySet::getFastPropertyValue; + + /** implement this method in derived classes to get called when properties + change. + */ + virtual void firePropertyChangeEvent(); + +public: + // Interfaces + + // ____ XInterface ____ + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL + getTypes() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL + getImplementationId() override; + + // ____ XPropertyState ____ + virtual css::beans::PropertyState SAL_CALL + getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL + getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL + setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL + getPropertyDefault( const OUString& aPropertyName ) override; + + // ____ XMultiPropertyStates ____ + // Note: getPropertyStates() is already implemented in XPropertyState with the + // same signature + virtual void SAL_CALL + setAllPropertiesToDefault() override; + virtual void SAL_CALL + setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL + getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + + // ____ XStyleSupplier ____ + virtual css::uno::Reference< css::style::XStyle > SAL_CALL getStyle() override; + virtual void SAL_CALL setStyle( const css::uno::Reference< css::style::XStyle >& xStyle ) override; + + // ____ XMultiPropertySet ____ + virtual void SAL_CALL setPropertyValues( + const css::uno::Sequence< OUString >& PropertyNames, + const css::uno::Sequence< css::uno::Any >& Values ) override; + + // ____ XFastPropertySet ____ + virtual void SAL_CALL setFastPropertyValue( sal_Int32 nHandle, const css::uno::Any& rValue ) override; + + // Note: it is assumed that the base class implements setPropertyValue by + // using setFastPropertyValue + +private: + /** supports states DIRECT_VALUE and DEFAULT_VALUE + */ + css::beans::PropertyState + GetPropertyStateByHandle( sal_Int32 nHandle ) const; + + css::uno::Sequence< css::beans::PropertyState > + GetPropertyStatesByHandle( const std::vector< sal_Int32 > & aHandles ) const; + + void SetPropertyToDefault( sal_Int32 nHandle ); + void SetPropertiesToDefault( const std::vector< sal_Int32 > & aHandles ); + void SetAllPropertiesToDefault(); + + /** @param rValue is set to the value for the property given in nHandle. If + the property is not set, the style chain is searched for any + instance set there. If there was no value found either in the + property set itself or any of its styles, rValue remains + unchanged and false is returned. + + @return false if the property is default, true otherwise. + */ + bool GetPropertyValueByHandle( + css::uno::Any & rValue, + sal_Int32 nHandle ) const; + + void SetPropertyValueByHandle( sal_Int32 nHandle, + const css::uno::Any & rValue ); + + bool SetStyle( const css::uno::Reference< css::style::XStyle > & xStyle ); + + /// reference to mutex of class deriving from here + ::osl::Mutex & m_rMutex; + + bool m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault; + typedef std::map< sal_Int32, css::uno::Any > tPropertyMap; + tPropertyMap m_aProperties; + css::uno::Reference< css::style::XStyle > m_xStyle; +}; + +} // namespace property + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ObjectIdentifier.hxx b/chart2/source/inc/ObjectIdentifier.hxx new file mode 100644 index 000000000..9edd51041 --- /dev/null +++ b/chart2/source/inc/ObjectIdentifier.hxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +#include "TitleHelper.hxx" +#include "charttoolsdllapi.hxx" + +#include +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::awt { struct Point; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XInterface; } + +namespace chart +{ +class Axis; +class BaseCoordinateSystem; +class DataSeries; +class Diagram; +class Legend; + +enum ObjectType +{ + OBJECTTYPE_PAGE, + OBJECTTYPE_TITLE, + OBJECTTYPE_LEGEND, + OBJECTTYPE_LEGEND_ENTRY, + OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DIAGRAM_WALL, + OBJECTTYPE_DIAGRAM_FLOOR, + OBJECTTYPE_AXIS, + OBJECTTYPE_AXIS_UNITLABEL, + OBJECTTYPE_GRID, + OBJECTTYPE_SUBGRID, + OBJECTTYPE_DATA_SERIES, + OBJECTTYPE_DATA_POINT, + OBJECTTYPE_DATA_LABELS, + OBJECTTYPE_DATA_LABEL, + OBJECTTYPE_DATA_ERRORS_X, + OBJECTTYPE_DATA_ERRORS_Y, + OBJECTTYPE_DATA_ERRORS_Z, + OBJECTTYPE_DATA_CURVE,//e.g. a statistical method printed as line + OBJECTTYPE_DATA_AVERAGE_LINE, + OBJECTTYPE_DATA_CURVE_EQUATION, + OBJECTTYPE_DATA_STOCK_RANGE, + OBJECTTYPE_DATA_STOCK_LOSS, + OBJECTTYPE_DATA_STOCK_GAIN, + OBJECTTYPE_SHAPE, + OBJECTTYPE_UNKNOWN +}; + +class OOO_DLLPUBLIC_CHARTTOOLS ObjectIdentifier +{ + //CID == ClassifiedIdentifier <--> name of shape + //semicolon, colon, equal sign and slash have special meanings in a CID + //and are therefore not allowed in its components + + //syntax of a CID: CID:/classification/ObjectID + + //where classification: nothing or "MultiClick" or "DragMethod=DragMethodServiceName" and "DragParameter=DragParameterString" + // or a combination of these separated with a colon + //where DragMethodServiceName can be a selfdefined servicename for special actions //todo define standard service for this purpose + //where DragParameterString is any string you like to transport information to your special drag service + // only semicolon, colon, equal sign and slash are not allowed characters + // also the keywords used in the ObjectIdentifiers are not allowed + + //where ObjectID: Parent-Particle:Particle //e.g. Series=2:Point=22 + //where Particle: Type=ParticleID //e.g. Point=22 + //where Type: getStringForType( ObjectType eType ) or other string + +public: + ObjectIdentifier(); + ObjectIdentifier( const OUString& rObjectCID ); + ObjectIdentifier( const css::uno::Reference< css::drawing::XShape >& rxShape ); + ObjectIdentifier( const css::uno::Any& rAny ); + + bool operator==( const ObjectIdentifier& rOID ) const; + bool operator!=( const ObjectIdentifier& rOID ) const; + bool operator<( const ObjectIdentifier& rOID ) const; + + static OUString createClassifiedIdentifierForObject( + const css::uno::Reference< css::uno::XInterface >& xObject + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString createClassifiedIdentifierForObject( + const rtl::Reference< ::chart::Legend >& xObject + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + static OUString createClassifiedIdentifierForObject( + const rtl::Reference< ::chart::Axis >& xObject + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static OUString createClassifiedIdentifierForParticle( + std::u16string_view rParticle ); + + static OUString createClassifiedIdentifierForParticles( + std::u16string_view rParentParticle + , std::u16string_view rChildParticle + , std::u16string_view rDragMethodServiceName = std::u16string_view() + , std::u16string_view rDragParameterString = std::u16string_view() ); + + static OUString createClassifiedIdentifierForGrid( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference<::chart::ChartModel>& xChartModel + , sal_Int32 nSubIndex = -1 );//-1: main grid, 0: first subgrid etc + + SAL_DLLPRIVATE static OUString createParticleForDiagram(); + + static OUString createParticleForCoordinateSystem( + const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static OUString createParticleForAxis( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + static OUString createParticleForGrid( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + static OUString createParticleForSeries( sal_Int32 nDiagramIndex, sal_Int32 nCooSysIndex + , sal_Int32 nChartTypeIndex, sal_Int32 nSeriesIndex ); + + static OUString createParticleForLegend( + const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static OUString addChildParticle( std::u16string_view rParticle, std::u16string_view rChildParticle ); + static OUString createChildParticleWithIndex( ObjectType eObjectType, sal_Int32 nIndex ); + static sal_Int32 getIndexFromParticleOrCID( const OUString& rParticleOrCID ); + + static OUString createClassifiedIdentifier( + enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_SERIES + , std::u16string_view rParticleID );//e.g. SeriesID + + static OUString createClassifiedIdentifierWithParent( + enum ObjectType //e.g. OBJECTTYPE_DATA_POINT or OBJECTTYPE_GRID + , std::u16string_view rParticleID //for points or subgrids this is an Index or otherwise an identifier from the model object + , std::u16string_view rParentPartical //e.g. "Series=SeriesID" or "Grid=GridId" + , std::u16string_view rDragMethodServiceName = std::u16string_view() + , std::u16string_view rDragParameterString = std::u16string_view() + ); + + static bool isCID( std::u16string_view rName ); + static std::u16string_view getDragMethodServiceName( std::u16string_view rClassifiedIdentifier ); + static std::u16string_view getDragParameterString( std::u16string_view rCID ); + static bool isDragableObject( std::u16string_view rClassifiedIdentifier ); + bool isDragableObject() const; + static bool isRotateableObject( std::u16string_view rClassifiedIdentifier ); + static bool isMultiClickObject( std::u16string_view rClassifiedIdentifier ); + static bool areSiblings( const OUString& rCID1, const OUString& rCID2 );//identical object is no sibling + static bool areIdenticalObjects( const OUString& rCID1, const OUString& rCID2 ); + + static OUString getStringForType( ObjectType eObjectType ); + static ObjectType getObjectType( std::u16string_view rCID ); + ObjectType getObjectType() const; + + static OUString createSeriesSubObjectStub( ObjectType eSubObjectType + , std::u16string_view rSeriesParticle + , std::u16string_view rDragMethodServiceName = std::u16string_view() + , std::u16string_view rDragParameterString = std::u16string_view() ); + static OUString createPointCID( std::u16string_view rPointCID_Stub, sal_Int32 nIndex ); + + static OUString createDataCurveCID( std::u16string_view rSeriesParticle, sal_Int32 nCurveIndex, bool bAverageLine ); + static OUString createDataCurveEquationCID( std::u16string_view rSeriesParticle, sal_Int32 nCurveIndex ); + + SAL_DLLPRIVATE static OUString getObjectID( const OUString& rCID ); + static std::u16string_view getParticleID( std::u16string_view rCID ); + static std::u16string_view getFullParentParticle( std::u16string_view rCID ); + + //returns the series particle of a CID when the CID is a child of the series + static OUString getSeriesParticleFromCID( const OUString& rCID ); + + //return the model object that is indicated by rObjectCID + static css::uno::Reference< css::beans::XPropertySet > + getObjectPropertySet( + const OUString& rObjectCID + , const rtl::Reference< ::chart::ChartModel >& xChartDocument ); + + //return the axis object that belongs to rObjectCID if any + static rtl::Reference< ::chart::Axis > + getAxisForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + //return the series object that belongs to rObjectCID if any + static rtl::Reference< ::chart::DataSeries > + getDataSeriesForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static rtl::Reference< ::chart::Diagram > + getDiagramForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ); + + static const OUString& getPieSegmentDragMethodServiceName(); + static OUString createPieSegmentDragParameterString( + sal_Int32 nOffsetPercent + , const css::awt::Point& rMinimumPosition + , const css::awt::Point& rMaximumPosition ); + static bool parsePieSegmentDragParameterString( std::u16string_view rDragParameterString + , sal_Int32& rOffsetPercent + , css::awt::Point& rMinimumPosition + , css::awt::Point& rMaximumPosition ); + + static TitleHelper::eTitleType getTitleTypeForCID( std::u16string_view rCID ); + + static OUString getMovedSeriesCID( const OUString& rObjectCID, bool bForward ); + + bool isValid() const; + bool isAutoGeneratedObject() const; + bool isAdditionalShape() const; + const OUString& getObjectCID() const { return m_aObjectCID;} + const css::uno::Reference< css::drawing::XShape >& getAdditionalShape() const { return m_xAdditionalShape;} + css::uno::Any getAny() const; + +private: + // #i12587# support for shapes in chart + // For autogenerated chart objects a CID is specified in m_aObjectCID, + // for all other objects m_xAdditionalShape is set. + // Note, that if m_aObjectCID is set, m_xAdditionalShape must be empty + // and vice versa. + OUString m_aObjectCID; + css::uno::Reference< css::drawing::XShape > m_xAdditionalShape; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx b/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx new file mode 100644 index 000000000..73512497b --- /dev/null +++ b/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" +#include + +namespace RegressionCalculationHelper +{ + typedef std::pair< std::vector< double >, std::vector< double > > tDoubleVectorPair; +} + +namespace chart +{ + +class PolynomialRegressionCurveCalculator : public RegressionCurveCalculator +{ +public: + PolynomialRegressionCurveCalculator(); + virtual ~PolynomialRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth = nullptr ) const override; + + virtual double SAL_CALL getCurveValue( double x ) override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + void computeCorrelationCoefficient( + RegressionCalculationHelper::tDoubleVectorPair& rValues, + const sal_Int32 aNoValues, + double yAverage ); + + std::vector mCoefficients; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/PopupRequest.hxx b/chart2/source/inc/PopupRequest.hxx new file mode 100644 index 000000000..a755fdfa3 --- /dev/null +++ b/chart2/source/inc/PopupRequest.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "charttoolsdllapi.hxx" + +#include +#include + +namespace chart +{ +namespace impl +{ +typedef comphelper::WeakComponentImplHelper PopupRequest_Base; +} + +class OOO_DLLPUBLIC_CHARTTOOLS PopupRequest final : public impl::PopupRequest_Base +{ +public: + explicit PopupRequest(); + virtual ~PopupRequest() override; + + css::uno::Reference const& getCallback() const { return m_xCallback; } + + // ____ XRequestCallback ____ + virtual void SAL_CALL addCallback(const css::uno::Reference<::css::awt::XCallback>& xCallback, + const css::uno::Any& aData) override; + +private: + css::uno::Reference m_xCallback; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/PotentialRegressionCurveCalculator.hxx b/chart2/source/inc/PotentialRegressionCurveCalculator.hxx new file mode 100644 index 000000000..a0d05b4a2 --- /dev/null +++ b/chart2/source/inc/PotentialRegressionCurveCalculator.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "RegressionCurveCalculator.hxx" + +namespace chart +{ + +class PotentialRegressionCurveCalculator final : public RegressionCurveCalculator +{ +public: + PotentialRegressionCurveCalculator(); + virtual ~PotentialRegressionCurveCalculator() override; + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const override; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence& aXValues, + const css::uno::Sequence& aYValues ) override; + + virtual double SAL_CALL getCurveValue( double x ) override; + + virtual css::uno::Sequence SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference& xScalingX, + const css::uno::Reference& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + // formula is: f(x) = x ^ m_fSlope * m_fSign * m_fIntercept + double m_fSlope; + double m_fIntercept; + double m_fSign; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/PropertyHelper.hxx b/chart2/source/inc/PropertyHelper.hxx new file mode 100644 index 000000000..14aa57609 --- /dev/null +++ b/chart2/source/inc/PropertyHelper.hxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace chart +{ + +typedef int tPropertyValueMapKey; + +typedef std::unordered_map tPropertyValueMap; + +namespace PropertyHelper +{ + +/** adds a line dash with a unique name to the gradient obtained by the given + factory. + + @return The name used for storing this element in the table +*/ +OOO_DLLPUBLIC_CHARTTOOLS OUString addLineDashUniqueNameToTable( + const css::uno::Any & rValue, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ); + +/** adds a gradient with a unique name to the gradient obtained by the given + factory. + + @return The name used for storing this element in the table +*/ +OOO_DLLPUBLIC_CHARTTOOLS OUString addGradientUniqueNameToTable( + const css::uno::Any & rValue, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ); + +/** adds a transparency gradient with a unique name to the gradient obtained + by the given factory. + + @return The name used for storing this element in the table +*/ +OOO_DLLPUBLIC_CHARTTOOLS +OUString addTransparencyGradientUniqueNameToTable( + const css::uno::Any & rValue, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ); + +/** adds a hatch with a unique name to the gradient obtained by the given + factory. + + @return The name used for storing this element in the table +*/ +OOO_DLLPUBLIC_CHARTTOOLS OUString addHatchUniqueNameToTable( + const css::uno::Any & rValue, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ); + +/** adds a bitmap with a unique name to the gradient obtained by the given + factory. + + @return The name used for storing this element in the table +*/ +OOO_DLLPUBLIC_CHARTTOOLS OUString addBitmapUniqueNameToTable( + const css::uno::Any & rValue, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ); + +/** Set a property to a certain value in the given map. This works for + properties that are already set, and those which are not yet in the map. + + @param any is the value encapsulated in the variant type Any + */ +OOO_DLLPUBLIC_CHARTTOOLS +void setPropertyValueAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, + const css::uno::Any & rAny ); + +/** Set a property to a certain value in the given map. This works for + properties that are already set, and those which are not yet in the map. + + @param value is the value of type Value that will be put into a variant type + Any before set in the property map. + */ +template< typename Value > + void setPropertyValue( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const Value & value ) +{ + setPropertyValueAny( rOutMap, key, css::uno::Any( value )); +} + +template<> + void setPropertyValue< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny ); + +OOO_DLLPUBLIC_CHARTTOOLS void setPropertyValueDefaultAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny ); + +/** Calls setPropertyValue() but asserts that the given property hasn't been set + before. + */ +template< typename Value > + void setPropertyValueDefault( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const Value & value ) +{ + setPropertyValueDefaultAny( rOutMap, key, css::uno::Any( value )); +} + +/** Calls setPropertyValue() but asserts that the given property hasn't been set + before. + */ +template<> + void setPropertyValueDefault< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny ); + +/** Calls setPropertyValueDefault() with an empty Any as value + */ +OOO_DLLPUBLIC_CHARTTOOLS void setEmptyPropertyValueDefault( tPropertyValueMap & rOutMap, tPropertyValueMapKey key ); + +} // namespace PropertyHelper + +struct OOO_DLLPUBLIC_CHARTTOOLS PropertyNameLess +{ + bool operator() ( const css::beans::Property & first, + const css::beans::Property & second ) + { + return ( first.Name.compareTo( second.Name ) < 0 ); + } +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RangeHighlighter.hxx b/chart2/source/inc/RangeHighlighter.hxx new file mode 100644 index 000000000..c7bcdd2c5 --- /dev/null +++ b/chart2/source/inc/RangeHighlighter.hxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XDiagram; + class XDataSeries; + class XAxis; + } +} +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::view { class XSelectionSupplier; } + +namespace chart +{ +class ChartModel; +class DataSeries; +class Diagram; + +namespace impl +{ +typedef comphelper::WeakComponentImplHelper< + css::chart2::data::XRangeHighlighter, + css::view::XSelectionChangeListener + > + RangeHighlighter_Base; +} + +class RangeHighlighter final : + public impl::RangeHighlighter_Base +{ +public: + explicit RangeHighlighter( + const rtl::Reference< ::chart::ChartModel > & xSelectionSupplier ); + virtual ~RangeHighlighter() override; + +protected: + // ____ XRangeHighlighter ____ + virtual css::uno::Sequence< css::chart2::data::HighlightedRange > SAL_CALL getSelectedRanges() override; + virtual void SAL_CALL addSelectionChangeListener( + const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( + const css::uno::Reference< css::view::XSelectionChangeListener >& xListener ) override; + + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XSelectionChangeListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ WeakComponentImplHelperBase ____ + // is called when dispose() is called at this component + virtual void disposing(std::unique_lock&) override; + +private: + void fireSelectionEvent(); + void startListening(); + void stopListening(); + void determineRanges(); + + void fillRangesForDiagram( const rtl::Reference< ::chart::Diagram > & xDiagram ); + void fillRangesForDataSeries( const css::uno::Reference< css::chart2::XDataSeries > & xSeries ); + void fillRangesForCategories( const css::uno::Reference< css::chart2::XAxis > & xAxis ); + void fillRangesForDataPoint( const rtl::Reference< ::chart::DataSeries > & xDataSeries, sal_Int32 nIndex ); + void fillRangesForErrorBars( const css::uno::Reference< css::beans::XPropertySet > & xErrorBar, + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries ); + + css::uno::Reference< css::view::XSelectionSupplier > + m_xSelectionSupplier; + rtl::Reference< ::chart::ChartModel > m_xChartModel; + css::uno::Reference< css::view::XSelectionChangeListener > + m_xListener; + css::uno::Sequence< css::chart2::data::HighlightedRange > + m_aSelectedRanges; + sal_Int32 m_nAddedListenerCount; + bool m_bIncludeHiddenCells; + comphelper::OInterfaceContainerHelper4 maSelectionChangeListeners; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ReferenceSizeProvider.hxx b/chart2/source/inc/ReferenceSizeProvider.hxx new file mode 100644 index 000000000..dbacd093f --- /dev/null +++ b/chart2/source/inc/ReferenceSizeProvider.hxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XTitle; + class XTitled; + class XChartDocument; + } + namespace beans { + class XPropertySet; + } +} + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS ReferenceSizeProvider +{ +public: + + enum AutoResizeState + { + AUTO_RESIZE_YES, + AUTO_RESIZE_NO, + AUTO_RESIZE_AMBIGUOUS, + AUTO_RESIZE_UNKNOWN + }; + + ReferenceSizeProvider( + css::awt::Size aPageSize, + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + const css::awt::Size& getPageSize() const { return m_aPageSize;} + + /** Retrieves the state auto-resize from all objects that support this + feature. If all objects return the same state, AUTO_RESIZE_YES or + AUTO_RESIZE_NO is returned. + + If no object supporting the feature is found, AUTO_RESIZE_UNKNOWN is + returned. If there are multiple objects, some with state YES and some + with state NO, AUTO_RESIZE_AMBIGUOUS is returned. + */ + static AutoResizeState getAutoResizeState( + const rtl::Reference<::chart::ChartModel> & xChartDoc ); + + /** sets or resets the auto-resize at all objects that support this feature + for text to the opposite of the current setting. If the current state + is ambiguous, it is turned on. If the current state is unknown it stays + unknown. + */ + void toggleAutoResizeState(); + + /** Sets the ReferencePageSize according to the internal settings of this + class at the XPropertySet, and the adapted font sizes if bAdaptFontSizes + is . + */ + SAL_DLLPRIVATE void setValuesAtPropertySet( + const css::uno::Reference< css::beans::XPropertySet > & xProp, + bool bAdaptFontSizes = true ); + + /** Sets the ReferencePageSize according to the internal settings of this + class at the XTitle, and the adapted font sizes at the contained + XFormattedStrings + */ + SAL_DLLPRIVATE void setValuesAtTitle( + const css::uno::Reference< css::chart2::XTitle > & xTitle ); + + /** Sets the internal value at all data series in the currently set model. + This is useful, if you have changed a chart-type and thus probably added + some new data series via model functionality. + */ + void setValuesAtAllDataSeries(); + +private: + SAL_DLLPRIVATE bool useAutoScale() const { return m_bUseAutoScale;} + + /** sets the auto-resize at all objects that support this feature for text. + eNewState must be either AUTO_RESIZE_YES or AUTO_RESIZE_NO + */ + SAL_DLLPRIVATE void setAutoResizeState( AutoResizeState eNewState ); + + /** Retrieves the auto-resize state from the given propertyset. The result + will be put into eInOutState. If you initialize eInOutState with + AUTO_RESIZE_UNKNOWN, you will get the actual state. If you pass any + other state, the result will be the accumulated state, + esp. AUTO_RESIZE_AMBIGUOUS, if the value was NO before, and is YES for + the current property set, or the other way round. + */ + SAL_DLLPRIVATE static void getAutoResizeFromPropSet( + const css::uno::Reference< css::beans::XPropertySet > & xProp, + AutoResizeState & rInOutState ); + + SAL_DLLPRIVATE void impl_setValuesAtTitled( + const css::uno::Reference< css::chart2::XTitled > & xTitled ); + SAL_DLLPRIVATE static void impl_getAutoResizeFromTitled( + const css::uno::Reference< css::chart2::XTitled > & xTitled, + AutoResizeState & rInOutState ); + + css::awt::Size m_aPageSize; + rtl::Reference<::chart::ChartModel> m_xChartDoc; + bool m_bUseAutoScale; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RegressionCalculationHelper.hxx b/chart2/source/inc/RegressionCalculationHelper.hxx new file mode 100644 index 000000000..0b9600e99 --- /dev/null +++ b/chart2/source/inc/RegressionCalculationHelper.hxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include + +namespace chart::RegressionCalculationHelper +{ + +typedef std::pair< std::vector< double >, std::vector< double > > tDoubleVectorPair; + +/** takes the given x- and y-values and copies them into the resulting pair, + which contains x-values in the first element and the y-values in the second + one. All tuples for which aPred is false are not copied. + +

The function below provide a set of useful predicates that can be + used to pass as parameter aPred.

+ */ +template< class Pred > +tDoubleVectorPair + cleanup( const css::uno::Sequence< double > & rXValues, + const css::uno::Sequence< double > & rYValues, + Pred aPred ) +{ + tDoubleVectorPair aResult; + sal_Int32 nSize = std::min( rXValues.getLength(), rYValues.getLength()); + for( sal_Int32 i=0; i= 0.0 ); + } +}; + +class isValidAndBothPositive +{ +public: + bool operator()( double x, double y ) + { return ! ( std::isnan( x ) || + std::isnan( y ) || + std::isinf( x ) || + std::isinf( y ) || + x <= 0.0 || + y <= 0.0 ); + } +}; + +class isValidAndXPositiveAndYNegative +{ +public: + bool operator()( double x, double y ) + { return ! ( std::isnan( x ) || + std::isnan( y ) || + std::isinf( x ) || + std::isinf( y ) || + x <= 0.0 || + y >= 0.0 ); + } +}; + +} // namespace chart::RegressionCalculationHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RegressionCurveCalculator.hxx b/chart2/source/inc/RegressionCurveCalculator.hxx new file mode 100644 index 000000000..6cf1f2914 --- /dev/null +++ b/chart2/source/inc/RegressionCurveCalculator.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +namespace com::sun::star::util { class XNumberFormatsSupplier; } +namespace com::sun::star::util { class XNumberFormatter; } + +namespace chart +{ + +class RegressionCurveCalculator : public + cppu::WeakImplHelper< css::chart2::XRegressionCurveCalculator > +{ +public: + RegressionCurveCalculator(); + virtual ~RegressionCurveCalculator() override; + + static bool isLinearScaling( + const css::uno::Reference< css::chart2::XScaling >& xScaling ); + + static bool isLogarithmicScaling( + const css::uno::Reference< css::chart2::XScaling >& xScaling ); + +protected: + virtual OUString ImplGetRepresentation( + const css::uno::Reference< css::util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength = nullptr ) const = 0; + + static OUString getFormattedString( + const css::uno::Reference< css::util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, + double fNumber, + const sal_Int32* pStringLength ); + + static void addStringToEquation( OUStringBuffer& aStrEquation, sal_Int32& nLineLength, OUStringBuffer const & aAddString, const sal_Int32* pMaxLength ); + + double m_fCorrelationCoefficient; + + sal_Int32 mDegree; + bool mForceIntercept; + double mInterceptValue; + sal_Int32 mPeriod; + OUString mXName, mYName; + sal_Int32 mnMovingType; + + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL setRegressionProperties( + sal_Int32 aDegree, + sal_Bool aForceIntercept, + double aInterceptValue, + sal_Int32 aPeriod, + sal_Int32 nMovingType) override; + + virtual void SAL_CALL recalculateRegression( + const css::uno::Sequence< double >& aXValues, + const css::uno::Sequence< double >& aYValues ) override = 0; + + virtual double SAL_CALL getCurveValue( double x ) override = 0; + + virtual css::uno::Sequence< css::geometry::RealPoint2D > SAL_CALL getCurveValues( + double min, + double max, + sal_Int32 nPointCount, + const css::uno::Reference< css::chart2::XScaling >& xScalingX, + const css::uno::Reference< css::chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) override; + + virtual double SAL_CALL getCorrelationCoefficient() override; + + virtual OUString SAL_CALL getRepresentation() override; + + virtual OUString SAL_CALL getFormattedRepresentation( + const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumFmtSupplier, + sal_Int32 nNumberFormatKey, sal_Int32 nFormulaLength ) override; + + virtual void SAL_CALL setXYNames( + const OUString& aXName, const OUString& aYName ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RegressionCurveHelper.hxx b/chart2/source/inc/RegressionCurveHelper.hxx new file mode 100644 index 000000000..2666b41d9 --- /dev/null +++ b/chart2/source/inc/RegressionCurveHelper.hxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "charttoolsdllapi.hxx" +#include + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::chart2 { class XRegressionCurve; } +namespace com::sun::star::chart2 { class XRegressionCurveCalculator; } +namespace com::sun::star::chart2 { class XRegressionCurveContainer; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::frame { class XModel; } +namespace chart { class ChartModel; } +namespace chart { class DataSeries; } +namespace chart { class Diagram; } +namespace chart { class RegressionCurveModel; } + +namespace chart::RegressionCurveHelper +{ + /// returns a model mean-value line + rtl::Reference<::chart::RegressionCurveModel> createMeanValueLine(); + + /// returns a model regression curve + rtl::Reference<::chart::RegressionCurveModel> + createRegressionCurveByServiceName( std::u16string_view aServiceName ); + + OOO_DLLPUBLIC_CHARTTOOLS bool hasMeanValueLine( + const css::uno::Reference & xRegCnt ); + OOO_DLLPUBLIC_CHARTTOOLS bool hasMeanValueLine( + const rtl::Reference<::chart::DataSeries> & xRegCnt ); + + OOO_DLLPUBLIC_CHARTTOOLS bool isMeanValueLine( + const css::uno::Reference & xRegCurve ); + OOO_DLLPUBLIC_CHARTTOOLS bool isMeanValueLine( + const rtl::Reference<::chart::RegressionCurveModel> & xRegCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + getMeanValueLine( + const css::uno::Reference & xRegCnt ); + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + getMeanValueLine( + const rtl::Reference<::chart::DataSeries> & xRegCnt ); + + /** creates a mean-value line and adds it to the container. + + @param xSeriesProp + If set, this property-set will be used to apply a line color + */ + OOO_DLLPUBLIC_CHARTTOOLS void addMeanValueLine( + css::uno::Reference const & xRegCnt, + const css::uno::Reference& xSeriesProp ); + OOO_DLLPUBLIC_CHARTTOOLS void addMeanValueLine( + rtl::Reference<::chart::DataSeries> const & xRegCnt, + const css::uno::Reference& xSeriesProp ); + + OOO_DLLPUBLIC_CHARTTOOLS void removeMeanValueLine( + css::uno::Reference const & xRegCnt ); + OOO_DLLPUBLIC_CHARTTOOLS void removeMeanValueLine( + rtl::Reference<::chart::DataSeries> const & xRegCnt ); + + /** Returns the first regression curve found that is not of type + mean-value line + */ + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + getFirstCurveNotMeanValueLine( + const css::uno::Reference& xCurveContainer ); + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + getFirstCurveNotMeanValueLine( + const rtl::Reference<::chart::DataSeries>& xCurveContainer ); + + /** Returns the regression curve found at the index provided. + */ + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + getRegressionCurveAtIndex( + const rtl::Reference<::chart::DataSeries>& xCurveContainer, + sal_Int32 aIndex); + + /** Returns the type of the first regression curve found that is not of type + mean-value line + */ + OOO_DLLPUBLIC_CHARTTOOLS SvxChartRegress getFirstRegressTypeNotMeanValueLine( + const css::uno::Reference& xCurveContainer ); + + OOO_DLLPUBLIC_CHARTTOOLS SvxChartRegress getRegressionType( + const css::uno::Reference& xCurve ); + + /** @param xPropertySource is taken as source to copy all properties from if + not null + @param xEquationProperties is set at the new regression curve as + equation properties if not null + */ + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + addRegressionCurve( + SvxChartRegress eType, + css::uno::Reference const & xCurveContainer, + const css::uno::Reference& xPropertySource = + css::uno::Reference(), + const css::uno::Reference& xEquationProperties = + css::uno::Reference() ); + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + addRegressionCurve( + SvxChartRegress eType, + rtl::Reference<::chart::DataSeries> const & xCurveContainer, + const css::uno::Reference& xPropertySource = + css::uno::Reference(), + const css::uno::Reference& xEquationProperties = + css::uno::Reference() ); + + OOO_DLLPUBLIC_CHARTTOOLS bool removeAllExceptMeanValueLine( + rtl::Reference<::chart::DataSeries> const & xCurveContainer ); + + OOO_DLLPUBLIC_CHARTTOOLS void removeEquations( + rtl::Reference<::chart::DataSeries> const & xCurveContainer ); + + OOO_DLLPUBLIC_CHARTTOOLS rtl::Reference<::chart::RegressionCurveModel> + changeRegressionCurveType( + SvxChartRegress eType, + css::uno::Reference const & xRegressionCurveContainer, + css::uno::Reference const & xRegressionCurve ); + + /// returns a calculator object for regression curves (used by the view) + OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference + createRegressionCurveCalculatorByServiceName( std::u16string_view aServiceName ); + + /** recalculates the regression parameters according to the data given in + the data source. + + A sequence having the role "values-x" will be used as x-values for the + calculation if found. Otherwise a sequence (1, 2, 3, ...) of category + indexes will be used for the recalculateRegression() method of the + regression curve. + + The first sequence having the role "values-y" will be used as y-values + for the recalculateRegression() method of the regression curve. + + @param bUseXValuesIfAvailable + If false, the sequence (1, 2, 3, ...) will always be used, even if + there is a data-sequence with role "values-x" + */ + void initializeCurveCalculator( + const css::uno::Reference& xOutCurveCalculator, + const css::uno::Reference& xSource, + bool bUseXValuesIfAvailable ); + + /** Same method as above, but uses the given XModel to determine the + parameter bUseXValuesIfAvailable in the above function. It is also + necessary that the data::XDataSource is an XDataSeries, thus this parameter + also changed. + */ + OOO_DLLPUBLIC_CHARTTOOLS void initializeCurveCalculator( + const css::uno::Reference& xOutCurveCalculator, + const css::uno::Reference& xSeries, + const rtl::Reference<::chart::ChartModel>& xModel ); + + OOO_DLLPUBLIC_CHARTTOOLS OUString getUINameForRegressionCurve( + const css::uno::Reference& xCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS OUString getRegressionCurveName( + const css::uno::Reference& xCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS OUString getRegressionCurveGenericName( + const css::uno::Reference& xCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS OUString getRegressionCurveSpecificName( + const css::uno::Reference& xCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS std::vector > + getAllRegressionCurvesNotMeanValueLine( + const rtl::Reference<::chart::Diagram>& xDiagram ); + + OOO_DLLPUBLIC_CHARTTOOLS void resetEquationPosition( + const css::uno::Reference& xCurve ); + + /// @return the index of the given curve in the given container. -1 if not contained + OOO_DLLPUBLIC_CHARTTOOLS sal_Int32 getRegressionCurveIndex( + const rtl::Reference<::chart::DataSeries>& xContainer, + const rtl::Reference<::chart::RegressionCurveModel>& xCurve ); + + OOO_DLLPUBLIC_CHARTTOOLS bool hasEquation(const css::uno::Reference& xCurve ); + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RegressionCurveModel.hxx b/chart2/source/inc/RegressionCurveModel.hxx new file mode 100644 index 000000000..c7e48a826 --- /dev/null +++ b/chart2/source/inc/RegressionCurveModel.hxx @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "ModifyListenerHelper.hxx" + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::lang::XServiceName, + css::chart2::XRegressionCurve, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + RegressionCurveModel_Base; +} + +class SAL_DLLPUBLIC_RTTI RegressionCurveModel : + public cppu::BaseMutex, + public impl::RegressionCurveModel_Base, + public ::property::OPropertySet +{ +public: + enum tCurveType + { + CURVE_TYPE_MEAN_VALUE, + CURVE_TYPE_LINEAR, + CURVE_TYPE_LOGARITHM, + CURVE_TYPE_EXPONENTIAL, + CURVE_TYPE_POWER, + CURVE_TYPE_POLYNOMIAL, + CURVE_TYPE_MOVING_AVERAGE + }; + + RegressionCurveModel( tCurveType eCurveType ); + RegressionCurveModel( const RegressionCurveModel & rOther ); + virtual ~RegressionCurveModel() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + +public: + // ____ XRegressionCurve ____ + virtual css::uno::Reference< css::chart2::XRegressionCurveCalculator > SAL_CALL getCalculator() override; + virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getEquationProperties() override; + virtual void SAL_CALL setEquationProperties( + const css::uno::Reference< css::beans::XPropertySet >& xEquationProperties ) override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +protected: + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + using ::cppu::OPropertySetHelper::disposing; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + + void fireModifyEvent(); + +private: + const tCurveType m_eRegressionCurveType; + + rtl::Reference m_xModifyEventForwarder; + css::uno::Reference< css::beans::XPropertySet > m_xEquationProperties; +}; + +// implementations for factory instantiation + +class MeanValueRegressionCurve : public RegressionCurveModel +{ +public: + explicit MeanValueRegressionCurve(); + explicit MeanValueRegressionCurve( + const MeanValueRegressionCurve & rOther ); + virtual ~MeanValueRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class LinearRegressionCurve : public RegressionCurveModel +{ +public: + explicit LinearRegressionCurve(); + explicit LinearRegressionCurve( const LinearRegressionCurve & rOther ); + virtual ~LinearRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class LogarithmicRegressionCurve : public RegressionCurveModel +{ +public: + explicit LogarithmicRegressionCurve(); + explicit LogarithmicRegressionCurve( const LogarithmicRegressionCurve & rOther ); + virtual ~LogarithmicRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class ExponentialRegressionCurve : public RegressionCurveModel +{ +public: + explicit ExponentialRegressionCurve(); + explicit ExponentialRegressionCurve( const ExponentialRegressionCurve & rOther ); + virtual ~ExponentialRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class PotentialRegressionCurve : public RegressionCurveModel +{ +public: + explicit PotentialRegressionCurve(); + explicit PotentialRegressionCurve( const PotentialRegressionCurve & rOther ); + virtual ~PotentialRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class PolynomialRegressionCurve : public RegressionCurveModel +{ +public: + explicit PolynomialRegressionCurve(); + explicit PolynomialRegressionCurve( const PolynomialRegressionCurve & rOther ); + virtual ~PolynomialRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +class MovingAverageRegressionCurve : public RegressionCurveModel +{ +public: + explicit MovingAverageRegressionCurve(); + explicit MovingAverageRegressionCurve( const MovingAverageRegressionCurve & rOther ); + virtual ~MovingAverageRegressionCurve() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RelativePositionHelper.hxx b/chart2/source/inc/RelativePositionHelper.hxx new file mode 100644 index 000000000..5a6bcbbc8 --- /dev/null +++ b/chart2/source/inc/RelativePositionHelper.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { struct RelativeSize; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS RelativePositionHelper +{ +public: + /** returns the upper left corner of an object that has size aObjectSize and + where the point indicated by aAnchor has coordinates indicated by aPoint + ( e.g. if aAnchor equals BOTTOM_LEFT, aPoint describes the + coordinates of the bottom left corner of an object with size aObjectSize ) + */ + static css::awt::Point + getUpperLeftCornerOfAnchoredObject( + css::awt::Point aPoint, + css::awt::Size aObjectSize, + css::drawing::Alignment aAnchor ); + + /** returns the center of an object that has size aObjectSize and + where the point indicated by aAnchor has coordinates indicated by aPoint + ( e.g. if aAnchor equals BOTTOM_LEFT, aPoint describes the + coordinates of the bottom left corner of an object with size aObjectSize ) + */ + static css::awt::Point + getCenterOfAnchoredObject( + css::awt::Point aPoint, + css::awt::Size aUnrotatedObjectSize, + css::drawing::Alignment aAnchor, + double fAnglePi ); + + /** Returns a relative position that is the same point after the anchor has + been changed to the given one. The passed object size is taken into + account for shifting the position. + */ + SAL_DLLPRIVATE static css::chart2::RelativePosition + getReanchoredPosition( + const css::chart2::RelativePosition & rPosition, + const css::chart2::RelativeSize & rObjectSize, + css::drawing::Alignment aNewAnchor ); + + /** grows a relative size about the given amount and shifts the given + position such that the resize is relative to the former rectangle's + center. + + The resize is only done, if after + transformation, the position and size are within the bounds [0,1]. + + @return , if changes were applied. + +

That means, if the position's alignment is center, the position will + not change at all.

+ */ + static bool centerGrow( + css::chart2::RelativePosition & rInOutPosition, + css::chart2::RelativeSize & rInOutSize, + double fAmountX, double fAmountY ); + + /** shifts a relative position about the given amount + + The shift is only done, if after + transformation, the object represented by the position + rInOutPosition and its size rObjectSize the position and size are + within the bounds [0,1]. + + @return , if changes were applied. + */ + static bool moveObject( + css::chart2::RelativePosition & rInOutPosition, + const css::chart2::RelativeSize & rObjectSize, + double fAmountX, double fAmountY ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RelativeSizeHelper.hxx b/chart2/source/inc/RelativeSizeHelper.hxx new file mode 100644 index 000000000..b07876bb6 --- /dev/null +++ b/chart2/source/inc/RelativeSizeHelper.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::uno { template class Reference; } +class SvxShapeText; + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS RelativeSizeHelper +{ +public: + static double calculate( + double fValue, + const css::awt::Size & rOldReferenceSize, + const css::awt::Size & rNewReferenceSize ); + + static void adaptFontSizes( + const css::uno::Reference< + css::beans::XPropertySet > & xTargetProperties, + const css::awt::Size & rOldReferenceSize, + const css::awt::Size & rNewReferenceSize ); + + static void adaptFontSizes( + SvxShapeText& xTargetProperties, + const css::awt::Size & rOldReferenceSize, + const css::awt::Size & rNewReferenceSize ); + +private: + RelativeSizeHelper() = delete; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ResId.hxx b/chart2/source/inc/ResId.hxx new file mode 100644 index 000000000..48baf852a --- /dev/null +++ b/chart2/source/inc/ResId.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "charttoolsdllapi.hxx" +#include + +namespace chart +{ +OUString OOO_DLLPUBLIC_CHARTTOOLS SchResId(TranslateId aId); + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/Scaling.hxx b/chart2/source/inc/Scaling.hxx new file mode 100644 index 000000000..6f6310933 --- /dev/null +++ b/chart2/source/inc/Scaling.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +class LogarithmicScaling final : + public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + /// base is 10.0 + explicit LogarithmicScaling(); + LogarithmicScaling( double fBase ); + virtual ~LogarithmicScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) override; + + virtual css::uno::Reference< + css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const double m_fBase; + const double m_fLogOfBase; +}; + +class ExponentialScaling final : + public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + /// base is 10.0 + explicit ExponentialScaling(); + explicit ExponentialScaling( double fBase ); + virtual ~ExponentialScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL + doScaling( double value ) override; + + virtual css::uno::Reference< css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const double m_fBase; +}; + +class LinearScaling final : public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + /// y(x) = x + explicit LinearScaling(); + /// y(x) = fSlope * x + fOffset + LinearScaling( double fSlope, double fOffset ); + virtual ~LinearScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) override; + + virtual css::uno::Reference< css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const double m_fSlope; + const double m_fOffset; +}; + +class PowerScaling final : public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + /// exponent 10.0 + explicit PowerScaling(); + explicit PowerScaling( double fExponent ); + virtual ~PowerScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL + doScaling( double value ) override; + + virtual css::uno::Reference< css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const double m_fExponent; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/SceneProperties.hxx b/chart2/source/inc/SceneProperties.hxx new file mode 100644 index 000000000..ab7d89711 --- /dev/null +++ b/chart2/source/inc/SceneProperties.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyHelper.hxx" +#include "FastPropertyIdRanges.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements service SceneProperties +namespace SceneProperties +{ + // FastProperty Ids for properties + enum + { + // "com.sun.star.drawing.SceneProperties" (does not exist) + PROP_SCENE_TRANSF_MATRIX = FAST_PROPERTY_ID_START_SCENE_PROP, + PROP_SCENE_DISTANCE, + PROP_SCENE_FOCAL_LENGTH, + PROP_SCENE_SHADOW_SLANT, + PROP_SCENE_SHADE_MODE, + PROP_SCENE_AMBIENT_COLOR, + PROP_SCENE_TWO_SIDED_LIGHTING, + PROP_SCENE_CAMERA_GEOMETRY, + PROP_SCENE_PERSPECTIVE, + PROP_SCENE_LIGHT_COLOR_1, + PROP_SCENE_LIGHT_DIRECTION_1, + PROP_SCENE_LIGHT_ON_1, + PROP_SCENE_LIGHT_COLOR_2, + PROP_SCENE_LIGHT_DIRECTION_2, + PROP_SCENE_LIGHT_ON_2, + PROP_SCENE_LIGHT_COLOR_3, + PROP_SCENE_LIGHT_DIRECTION_3, + PROP_SCENE_LIGHT_ON_3, + PROP_SCENE_LIGHT_COLOR_4, + PROP_SCENE_LIGHT_DIRECTION_4, + PROP_SCENE_LIGHT_ON_4, + PROP_SCENE_LIGHT_COLOR_5, + PROP_SCENE_LIGHT_DIRECTION_5, + PROP_SCENE_LIGHT_ON_5, + PROP_SCENE_LIGHT_COLOR_6, + PROP_SCENE_LIGHT_DIRECTION_6, + PROP_SCENE_LIGHT_ON_6, + PROP_SCENE_LIGHT_COLOR_7, + PROP_SCENE_LIGHT_DIRECTION_7, + PROP_SCENE_LIGHT_ON_7, + PROP_SCENE_LIGHT_COLOR_8, + PROP_SCENE_LIGHT_DIRECTION_8, + PROP_SCENE_LIGHT_ON_8 + }; + + OOO_DLLPUBLIC_CHARTTOOLS void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + OOO_DLLPUBLIC_CHARTTOOLS void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/StackMode.hxx b/chart2/source/inc/StackMode.hxx new file mode 100644 index 000000000..718befc4e --- /dev/null +++ b/chart2/source/inc/StackMode.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +namespace chart +{ +// needed for chart type templates + +enum class StackMode +{ + NONE, + YStacked, + YStackedPercent, + ZStacked +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/StatisticsHelper.hxx b/chart2/source/inc/StatisticsHelper.hxx new file mode 100644 index 000000000..d4a05daaf --- /dev/null +++ b/chart2/source/inc/StatisticsHelper.hxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2::data { class XDataProvider; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::chart2::data { class XDataSource; } +namespace com::sun::star::chart2::data { class XLabeledDataSequence; } +namespace com::sun::star::uno { template class Sequence; } +namespace chart { class LabeledDataSequence; } + +namespace chart::StatisticsHelper +{ + /** Calculates 1/n * sum (x_i - x_mean)^2. + + @see http://mathworld.wolfram.com/Variance.html + */ + OOO_DLLPUBLIC_CHARTTOOLS double getVariance( const css::uno::Sequence< double > & rData ); + + // square root of the variance + OOO_DLLPUBLIC_CHARTTOOLS double getStandardDeviation( const css::uno::Sequence< double > & rData ); + + // also called "Standard deviation of the mean (SDOM)" + OOO_DLLPUBLIC_CHARTTOOLS double getStandardError( const css::uno::Sequence< double > & rData ); + + OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XLabeledDataSequence > + getErrorLabeledDataSequenceFromDataSource( + const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource, + bool bPositiveValue, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::chart2::data::XDataSequence > + getErrorDataSequenceFromDataSource( + const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource, + bool bPositiveValue, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS double getErrorFromDataSource( + const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource, + sal_Int32 nIndex, + bool bPositiveValue, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS void setErrorDataSequence( + const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource, + const css::uno::Reference< css::chart2::data::XDataProvider > & xDataProvider, + const OUString & rNewRange, + bool bPositiveValue, + bool bYError = true, + OUString const * pXMLRange = nullptr ); + + /// @return the newly created or existing error bar object + OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::beans::XPropertySet > + addErrorBars( + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries, + sal_Int32 nStyle, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS css::uno::Reference< css::beans::XPropertySet > + getErrorBars( + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS bool hasErrorBars( + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS void removeErrorBars( + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries, + bool bYError = true ); + + OOO_DLLPUBLIC_CHARTTOOLS bool usesErrorBarRanges( + const css::uno::Reference< css::chart2::XDataSeries > & xDataSeries, + bool bYError = true ); + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ThreeDHelper.hxx b/chart2/source/inc/ThreeDHelper.hxx new file mode 100644 index 000000000..b5edf986c --- /dev/null +++ b/chart2/source/inc/ThreeDHelper.hxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XDiagram; } + +namespace chart +{ +class Diagram; + +enum class ThreeDLookScheme +{ + ThreeDLookScheme_Simple, + ThreeDLookScheme_Realistic, + ThreeDLookScheme_Unknown +}; + +enum CuboidPlanePosition +{ + CuboidPlanePosition_Left, + CuboidPlanePosition_Right, + CuboidPlanePosition_Top, + CuboidPlanePosition_Bottom, + CuboidPlanePosition_Front, + CuboidPlanePosition_Back +}; + +class OOO_DLLPUBLIC_CHARTTOOLS ThreeDHelper +{ +public: + + /** Returns the default camera geometry that is set in the Diagram CTOR. + This is not the property default! + + @todo deprecate the hard set camera geometry and use the property + default + */ + static css::drawing::CameraGeometry getDefaultCameraGeometry( bool bPie=false ); + + static void getRotationAngleFromDiagram( + const css::uno::Reference< css::beans::XPropertySet >& xSceneProperties + , double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad ); + static void setRotationAngleToDiagram( + const rtl::Reference< ::chart::Diagram >& xSceneProperties + , double fXAngleRad, double fYAngleRad, double fZAngleRad ); + + static void getRotationFromDiagram( + const rtl::Reference< ::chart::Diagram >& xSceneProperties + , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree ); + static void setRotationToDiagram( + const rtl::Reference< ::chart::Diagram >& xSceneProperties + , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree ); + + static void switchRightAngledAxes( const css::uno::Reference< css::beans::XPropertySet >& xSceneProperties + , bool bRightAngledAxes ); + + static void adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad ); + static double getXDegreeAngleLimitForRightAngledAxes() { return 90.0; } + static double getYDegreeAngleLimitForRightAngledAxes() { return 45.0; } + + static double getValueClippedToRange( double fValue, const double& fPositivLimit ); + + static void convertElevationRotationDegToXYZAngleRad( + sal_Int32 nElevationDeg, sal_Int32 nRotationDeg + , double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad ); + + SAL_DLLPRIVATE static void convertXYZAngleRadToElevationRotationDeg( + sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg + , double fXRad, double fYRad, double fZRad ); + + static double getCameraDistance( + const css::uno::Reference< css::beans::XPropertySet >& xSceneProperties ); + static void setCameraDistance( + const css::uno::Reference< css::beans::XPropertySet >& xSceneProperties + , double fCameraDistance ); + SAL_DLLPRIVATE static void ensureCameraDistanceRange( double& rfCameraDistance ); + SAL_DLLPRIVATE static void getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance ); + + static double CameraDistanceToPerspective( double fCameraDistance ); + static double PerspectiveToCameraDistance( double fPerspective ); + + static void set3DSettingsToDefault( const rtl::Reference< ::chart::Diagram >& xSceneProperties ); + static void setDefaultRotation( const rtl::Reference< ::chart::Diagram >& xDiagram ); + static void setDefaultIllumination( const rtl::Reference< ::chart::Diagram >& xDiagram ); + + static void setDefaultRotation( const css::uno::Reference< css::beans::XPropertySet >& xSceneProperties, bool bPieOrDonut ); + + static CuboidPlanePosition getAutomaticCuboidPlanePositionForStandardLeftWall( const rtl::Reference< + ::chart::Diagram >& xDiagram ); + static CuboidPlanePosition getAutomaticCuboidPlanePositionForStandardBackWall(const rtl::Reference< + ::chart::Diagram >& xDiagram ); + static CuboidPlanePosition getAutomaticCuboidPlanePositionForStandardBottom(const rtl::Reference< + ::chart::Diagram >& xDiagram ); + + static ThreeDLookScheme detectScheme( const rtl::Reference< ::chart::Diagram >& xDiagram ); + static void setScheme( const rtl::Reference< ::chart::Diagram >& xDiagram + , ThreeDLookScheme aScheme ); + + //sal_Int32 nRoundedEdges: <0 or >100 -> mixed state + //sal_Int32 nObjectLines: 0->no lines; 1->all lines on; other->mixed state + + static void getRoundedEdgesAndObjectLines( const rtl::Reference< ::chart::Diagram >& xDiagram + , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines ); + static void setRoundedEdgesAndObjectLines( const rtl::Reference< ::chart::Diagram >& xDiagram + , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/Title.hxx b/chart2/source/inc/Title.hxx new file mode 100644 index 000000000..091c558db --- /dev/null +++ b/chart2/source/inc/Title.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "OPropertySet.hxx" +#include +#include +#include +#include +#include +#include +#include "ModifyListenerHelper.hxx" + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XTitle, + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + Title_Base; +} + +class Title final : + public cppu::BaseMutex, + public impl::Title_Base, + public ::property::OPropertySet +{ +public: + explicit Title(); + virtual ~Title() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +private: + explicit Title( const Title & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XTitle ____ + virtual css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > > SAL_CALL getText() override; + virtual void SAL_CALL setText( const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& Strings ) override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + + css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > > m_aStrings; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/TitleHelper.hxx b/chart2/source/inc/TitleHelper.hxx new file mode 100644 index 000000000..5eafa8bce --- /dev/null +++ b/chart2/source/inc/TitleHelper.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +namespace chart { class ChartModel; } +namespace chart { class ReferenceSizeProvider; } +namespace com::sun::star::chart2 { class XTitle; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS TitleHelper +{ +public: + enum eTitleType + { + TITLE_BEGIN = 0, + MAIN_TITLE = 0, + SUB_TITLE, + X_AXIS_TITLE, + Y_AXIS_TITLE, + Z_AXIS_TITLE, + SECONDARY_X_AXIS_TITLE, + SECONDARY_Y_AXIS_TITLE, + NORMAL_TITLE_END, + + //it is intended that this both types are after NORMAL_TITLE_END + TITLE_AT_STANDARD_X_AXIS_POSITION, //equals the Y_AXIS_TITLE for barchart + TITLE_AT_STANDARD_Y_AXIS_POSITION //equals the X_AXIS_TITLE for barchart + }; + + static css::uno::Reference< css::chart2::XTitle > + getTitle( eTitleType nTitleIndex + , ChartModel& rModel ); + + static css::uno::Reference< css::chart2::XTitle > + getTitle( eTitleType nTitleIndex + , const rtl::Reference< ::chart::ChartModel >& xModel ); + + static css::uno::Reference< + css::chart2::XTitle > + createTitle( eTitleType nTitleIndex + , const OUString& rTitleText + , const rtl::Reference< ::chart::ChartModel >& xModel + , const css::uno::Reference< css::uno::XComponentContext > & xContext + , ReferenceSizeProvider * pRefSizeProvider = nullptr ); + static css::uno::Reference< + css::chart2::XTitle > + createOrShowTitle( eTitleType nTitleIndex + , const OUString& rTitleText + , const rtl::Reference< ::chart::ChartModel >& xModel + , const css::uno::Reference< css::uno::XComponentContext > & xContex ); + + static void removeTitle( eTitleType nTitleIndex + , const rtl::Reference< ::chart::ChartModel >& xModel ); + + static OUString getCompleteString( const css::uno::Reference< css::chart2::XTitle >& xTitle ); + static void setCompleteString( const OUString& rNewText + , const css::uno::Reference< css::chart2::XTitle >& xTitle + , const css::uno::Reference< css::uno::XComponentContext > & xContext + , const float * pDefaultCharHeight = nullptr ); + + static bool getTitleType( eTitleType& rType + , const css::uno::Reference< css::chart2::XTitle >& xTitle + , const rtl::Reference< ::chart::ChartModel >& xModel ); + static void hideTitle( eTitleType nTitleIndex, + const rtl::Reference< ::chart::ChartModel > & xModel); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/UncachedDataSequence.hxx b/chart2/source/inc/UncachedDataSequence.hxx new file mode 100644 index 000000000..6b4c21fe7 --- /dev/null +++ b/chart2/source/inc/UncachedDataSequence.hxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +// helper classes +#include +#include +#include +#include +#include +#include + +// interfaces and types +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySetInfo; } +namespace com::sun::star::chart2 { class XInternalDataProvider; } + +namespace chart +{ +class InternalDataProvider; +class ModifyEventForwarder; + +namespace impl +{ +typedef ::cppu::WeakComponentImplHelper< + css::chart2::data::XDataSequence, + css::chart2::data::XNumericalDataSequence, + css::chart2::data::XTextualDataSequence, + css::util::XCloneable, + css::util::XModifiable, // contains util::XModifyBroadcaster + css::container::XIndexReplace, + css::container::XNamed, // for setting a new range representation + css::lang::XServiceInfo > + UncachedDataSequence_Base; +} + +/** + * This sequence object does NOT store actual sequence data. Instead, it + * references a column inside the internal data table (represented by class + * InternalData) via range representation string. The range representation + * string ends with a numeric value that indicates the column index within + * the internal data table. + * + *

A range representation can be either '0', '1', '2', ..., or 'label 1', + * 'label 2', ...

+ */ +class UncachedDataSequence final : + public ::comphelper::OMutexAndBroadcastHelper, + public ::comphelper::OPropertyContainer, + public ::comphelper::OPropertyArrayUsageHelper< UncachedDataSequence >, + public impl::UncachedDataSequence_Base +{ +public: + /** The referring data provider is held as uno reference to ensure its + lifetime is at least as long as the one of this object. + */ + UncachedDataSequence( + const rtl::Reference< InternalDataProvider > & xIntDataProv, + const OUString & rRangeRepresentation ); + UncachedDataSequence( + const rtl::Reference< InternalDataProvider > & xIntDataProv, + const OUString & rRangeRepresentation, + const OUString & rRole ); + UncachedDataSequence( const UncachedDataSequence & rSource ); + virtual ~UncachedDataSequence() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +private: + // ____ XPropertySet ____ + /// @see css::beans::XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + /// @see ::comphelper::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + /// @see ::comphelper::OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + + // ____ XDataSequence ____ + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getData() override; + virtual OUString SAL_CALL getSourceRangeRepresentation() override; + virtual css::uno::Sequence< OUString > SAL_CALL generateLabel( + css::chart2::data::LabelOrigin nLabelOrigin ) override; + virtual ::sal_Int32 SAL_CALL getNumberFormatKeyByIndex( ::sal_Int32 nIndex ) override; + + // ____ XNumericalDataSequence ____ + /// @see css::chart::data::XNumericalDataSequence + virtual css::uno::Sequence< double > SAL_CALL getNumericalData() override; + + // ____ XTextualDataSequence ____ + /// @see css::chart::data::XTextualDataSequence + virtual css::uno::Sequence< OUString > SAL_CALL getTextualData() override; + + // ____ XIndexReplace ____ + virtual void SAL_CALL replaceByIndex( ::sal_Int32 Index, const css::uno::Any& Element ) override; + + // ____ XIndexAccess (base of XIndexReplace) ____ + virtual ::sal_Int32 SAL_CALL getCount() override; + virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override; + + // ____ XElementAccess (base of XIndexAccess) ____ + virtual css::uno::Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + + // ____ XNamed (for setting a new range representation) ____ + virtual OUString SAL_CALL getName() override; + virtual void SAL_CALL setName( const OUString& aName ) override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifiable ____ + virtual sal_Bool SAL_CALL isModified() override; + virtual void SAL_CALL setModified( sal_Bool bModified ) override; + + // ____ XModifyBroadcaster (base of XModifiable) ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + void fireModifyEvent(); + + // + sal_Int32 m_nNumberFormatKey; + OUString m_sRole; + OUString m_aXMLRange; + // + + /** This method registers all properties. It should be called by all + constructors. + */ + void registerProperties(); + + rtl::Reference< InternalDataProvider > m_xDataProvider; + OUString m_aSourceRepresentation; + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/UserDefinedProperties.hxx b/chart2/source/inc/UserDefinedProperties.hxx new file mode 100644 index 000000000..07ab7b5bb --- /dev/null +++ b/chart2/source/inc/UserDefinedProperties.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "FastPropertyIdRanges.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements service com.sun.star.xml.UserDefinedAttributesSupplier +namespace UserDefinedProperties +{ + // FastProperty Ids for properties + enum + { + // UserDefined attributes in the chart-properties + PROP_XML_USERDEF_CHART = FAST_PROPERTY_ID_START_USERDEF_PROP, + PROP_XML_USERDEF_TEXT, + PROP_XML_USERDEF_PARA, + // com.sun.star.xml.UserDefinedAttributesSupplier + // UserDefined attributes in the other properties-sections. (as long as + // there is no reliable mechanism, properties may move between the + // sections) + PROP_XML_USERDEF + }; + + OOO_DLLPUBLIC_CHARTTOOLS void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WeakListenerAdapter.hxx b/chart2/source/inc/WeakListenerAdapter.hxx new file mode 100644 index 000000000..f300f1aa0 --- /dev/null +++ b/chart2/source/inc/WeakListenerAdapter.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +/** Adapter that enables adding listeners as weak UNO references. Thus, adding + an object as listener to a broadcaster does not increase its reference + count. + +

The helper class, of course, is held as hard reference at the + broadcaster, but this should never be a problem as the adapter's life time + depends on no other object.

+ +

Note that in order to remove an object as listener, you have to remove + the same wrapper that you added, i.e., you should store the adapter as a + member in the adapted class for later use.

+ */ +template< class Listener > + class WeakListenerAdapter : public + ::cppu::WeakImplHelper< Listener > +{ +public: + explicit WeakListenerAdapter( const css::uno::Reference< Listener > & xListener ) : + m_xListener( xListener ) + {} + +protected: + // ____ XEventListener (base of all listeners) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override + { + css::uno::Reference< css::lang::XEventListener > xEventListener( + css::uno::Reference< Listener >( m_xListener), css::uno::UNO_QUERY ); + if( xEventListener.is()) + xEventListener->disposing( Source ); + } + + css::uno::Reference< Listener > getListener() const + { + return m_xListener; + } + +private: + css::uno::WeakReference< Listener > m_xListener; +}; + +class WeakSelectionChangeListenerAdapter final : + public WeakListenerAdapter< css::view::XSelectionChangeListener > +{ +public: + explicit WeakSelectionChangeListenerAdapter( + const css::uno::Reference< css::view::XSelectionChangeListener > & xListener ); + virtual ~WeakSelectionChangeListenerAdapter() override; + +protected: + // ____ XSelectionChangeListener ____ + virtual void SAL_CALL selectionChanged( + const css::lang::EventObject& aEvent ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WrappedDefaultProperty.hxx b/chart2/source/inc/WrappedDefaultProperty.hxx new file mode 100644 index 000000000..08a11ce03 --- /dev/null +++ b/chart2/source/inc/WrappedDefaultProperty.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "WrappedProperty.hxx" +#include "charttoolsdllapi.hxx" + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS WrappedDefaultProperty : public WrappedProperty +{ +public: + explicit WrappedDefaultProperty( + const OUString& rOuterName, const OUString& rInnerName, + const css::uno::Any& rNewOuterDefault ); + virtual ~WrappedDefaultProperty() override; + + virtual void setPropertyToDefault( + const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::uno::Any getPropertyDefault( + const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + + virtual css::beans::PropertyState getPropertyState( + const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; +private: + css::uno::Any m_aOuterDefaultValue; +}; + +} // namespace chart + +// CHART2_WRAPPEDPROPERTYNEWDEFAULT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WrappedDirectStateProperty.hxx b/chart2/source/inc/WrappedDirectStateProperty.hxx new file mode 100644 index 000000000..28398efd8 --- /dev/null +++ b/chart2/source/inc/WrappedDirectStateProperty.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "WrappedProperty.hxx" +#include "charttoolsdllapi.hxx" + +namespace chart +{ +class OOO_DLLPUBLIC_CHARTTOOLS WrappedDirectStateProperty : public WrappedProperty +{ +public: + explicit WrappedDirectStateProperty(const OUString& rOuterName, const OUString& rInnerName); + virtual ~WrappedDirectStateProperty() override; + + virtual css::beans::PropertyState getPropertyState( + const css::uno::Reference& xInnerPropertyState) const override; +}; + +} // namespace chart + +// CHART2_WRAPPEDPROPERTYNEWDEFAULT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WrappedIgnoreProperty.hxx b/chart2/source/inc/WrappedIgnoreProperty.hxx new file mode 100644 index 000000000..a031097bd --- /dev/null +++ b/chart2/source/inc/WrappedIgnoreProperty.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "WrappedProperty.hxx" +#include "charttoolsdllapi.hxx" + +#include + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS WrappedIgnoreProperty final : public WrappedProperty +{ +public: + WrappedIgnoreProperty( const OUString& rOuterName, const css::uno::Any& rDefaultValue ); + virtual ~WrappedIgnoreProperty() override; + + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const override; + +SAL_DLLPRIVATE virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +SAL_DLLPRIVATE virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +SAL_DLLPRIVATE virtual css::beans::PropertyState getPropertyState( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const override; + +private: + css::uno::Any m_aDefaultValue; + mutable css::uno::Any m_aCurrentValue; +}; + +class OOO_DLLPUBLIC_CHARTTOOLS WrappedIgnoreProperties +{ +public: + static void addIgnoreLineProperties( std::vector< std::unique_ptr >& rList ); + + static void addIgnoreFillProperties( std::vector< std::unique_ptr >& rList ); + SAL_DLLPRIVATE static void addIgnoreFillProperties_without_BitmapProperties( std::vector< std::unique_ptr >& rList ); + SAL_DLLPRIVATE static void addIgnoreFillProperties_only_BitmapProperties( std::vector< std::unique_ptr >& rList ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WrappedProperty.hxx b/chart2/source/inc/WrappedProperty.hxx new file mode 100644 index 000000000..6bd13936c --- /dev/null +++ b/chart2/source/inc/WrappedProperty.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include "charttoolsdllapi.hxx" + +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::beans { class XPropertyState; } +namespace com::sun::star::uno { template class Reference; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS WrappedProperty +{ + /** The property visible to the outer PropertySet in the PropertySetWrapper may have a different name, type and value than + a corresponding property of the inner PropertySet. Use this class to do the conversion between the two. + */ +public: + WrappedProperty( const OUString& rOuterName, const OUString& rInnerName ); + virtual ~WrappedProperty(); + + const OUString& getOuterName() const { return m_aOuterName;} + virtual OUString getInnerName() const; + + /// @throws css::beans::UnknownPropertyException + /// @throws css::beans::PropertyVetoException + /// @throws css::lang::IllegalArgumentException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + virtual void setPropertyValue( const css::uno::Any& rOuterValue, const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + + /// @throws css::beans::UnknownPropertyException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + virtual css::uno::Any getPropertyValue( const css::uno::Reference< css::beans::XPropertySet >& xInnerPropertySet ) const; + + /// @throws css::beans::UnknownPropertyException + /// @throws css::uno::RuntimeException + virtual void setPropertyToDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const; + + /// @throws css::beans::UnknownPropertyException + /// @throws css::lang::WrappedTargetException + /// @throws css::uno::RuntimeException + virtual css::uno::Any getPropertyDefault( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const; + + /// @throws css::beans::UnknownPropertyException + /// @throws css::uno::RuntimeException + virtual css::beans::PropertyState getPropertyState( const css::uno::Reference< css::beans::XPropertyState >& xInnerPropertyState ) const; + +protected: + virtual css::uno::Any convertInnerToOuterValue( const css::uno::Any& rInnerValue ) const; + virtual css::uno::Any convertOuterToInnerValue( const css::uno::Any& rOuterValue ) const; + +protected: + OUString m_aOuterName; + OUString m_aInnerName; +}; + +typedef std::map< sal_Int32, std::unique_ptr > tWrappedPropertyMap; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/WrappedPropertySet.hxx b/chart2/source/inc/WrappedPropertySet.hxx new file mode 100644 index 000000000..30ac421b3 --- /dev/null +++ b/chart2/source/inc/WrappedPropertySet.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "WrappedProperty.hxx" +#include "charttoolsdllapi.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace cppu { class IPropertyArrayHelper; } +namespace cppu { class OPropertyArrayHelper; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTTOOLS WrappedPropertySet : + public cppu::BaseMutex + , public ::cppu::WeakImplHelper + < css::beans::XPropertySet + , css::beans::XMultiPropertySet + , css::beans::XPropertyState + , css::beans::XMultiPropertyStates + > +{ +public: + WrappedPropertySet(); + virtual ~WrappedPropertySet() override; + + void clearWrappedPropertySet(); + +public: + //XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + //XMultiPropertySet + //getPropertySetInfo() already declared in XPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + + //XPropertyState + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + //XMultiPropertyStates + //getPropertyStates() already declared in XPropertyState + virtual void SAL_CALL setAllPropertiesToDefault( ) override; + virtual void SAL_CALL setPropertiesToDefault( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyDefaults( const css::uno::Sequence< OUString >& aPropertyNames ) override; + +protected: //methods + /** give all the properties that should be visible to the outer side + */ + virtual const css::uno::Sequence< css::beans::Property >& getPropertySequence()=0; + /** give a list of all properties that need a special treatment; + properties that are not in this list will be wrapped identical. + The base class 'WrappedPropertySet' will take ownership on the contained pointer. + It is not allowed to have duplicate entries in this list. + */ + virtual std::vector< std::unique_ptr > createWrappedProperties()=0; + + virtual css::uno::Reference< css::beans::XPropertySet > getInnerPropertySet() = 0; + SAL_DLLPRIVATE css::uno::Reference< css::beans::XPropertyState > getInnerPropertyState(); + + ::cppu::IPropertyArrayHelper& getInfoHelper(); + SAL_DLLPRIVATE tWrappedPropertyMap& getWrappedPropertyMap(); + + const WrappedProperty* getWrappedProperty( const OUString& rOuterName ); + const WrappedProperty* getWrappedProperty( sal_Int32 nHandle ); + +protected: //member + css::uno::Reference< css::beans::XPropertySetInfo > m_xInfo;//outer PropertySetInfo + + std::unique_ptr<::cppu::OPropertyArrayHelper> m_pPropertyArrayHelper;//holds all possible outer properties + + std::unique_ptr m_pWrappedPropertyMap;//holds all wrapped properties (containing the special mapping from inner to outer properties) + + //Container for the XPropertyChangedListener. The listeners are inserted by handle. + //OMultiTypeInterfaceContainerHelperInt32 m_aBoundListenerContainer; + + //Container for the XPropertyVetoableListener. The listeners are inserted by handle. + //OMultiTypeInterfaceContainerHelperInt32 m_aVetoableListenerContainer; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/XMLRangeHelper.hxx b/chart2/source/inc/XMLRangeHelper.hxx new file mode 100644 index 000000000..519c9b772 --- /dev/null +++ b/chart2/source/inc/XMLRangeHelper.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include "charttoolsdllapi.hxx" + +namespace chart::XMLRangeHelper +{ + +struct OOO_DLLPUBLIC_CHARTTOOLS Cell +{ + sal_Int32 nColumn; + sal_Int32 nRow; + bool bRelativeColumn; + bool bRelativeRow; + bool bIsEmpty; + + Cell() : + nColumn(0), + nRow(0), + bRelativeColumn(false), + bRelativeRow(false), + bIsEmpty(true) + {} + + bool empty() const { return bIsEmpty; } +}; + +struct OOO_DLLPUBLIC_CHARTTOOLS CellRange +{ + Cell aUpperLeft; + Cell aLowerRight; + OUString aTableName; +}; + +CellRange getCellRangeFromXMLString( const OUString & rXMLString ); + +OUString getXMLStringFromCellRange( const CellRange & rRange ); + +} // namespace chart::XMLRangeHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/charttoolsdllapi.hxx b/chart2/source/inc/charttoolsdllapi.hxx new file mode 100644 index 000000000..96336e101 --- /dev/null +++ b/chart2/source/inc/charttoolsdllapi.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#if defined OOO_DLLIMPLEMENTATION_CHARTTOOLS +#define OOO_DLLPUBLIC_CHARTTOOLS SAL_DLLPUBLIC_EXPORT +#else +#define OOO_DLLPUBLIC_CHARTTOOLS SAL_DLLPUBLIC_IMPORT +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/ChartSfxItemIds.hxx b/chart2/source/inc/chartview/ChartSfxItemIds.hxx new file mode 100644 index 000000000..45773344f --- /dev/null +++ b/chart2/source/inc/chartview/ChartSfxItemIds.hxx @@ -0,0 +1,229 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +class SvxSizeItem; +class SfxIntegerListItem; +class SfxBoolItem; +class SfxStringItem; +class SfxInt32Item; +class SfxUInt32Item; +class SvxChartIndicateItem; +class SvxDoubleItem; +class SvxBrushItem; +class SvxChartKindErrorItem; +class SvxChartTextOrderItem; +class SvxChartRegressItem; +class SdrAngleItem; + +// SCHATTR + +// can't this be changed to 0? +constexpr sal_uInt16 SCHATTR_START = 1; + +constexpr sal_uInt16 SCHATTR_DATADESCR_START (SCHATTR_START); +constexpr TypedWhichId SCHATTR_DATADESCR_SHOW_NUMBER (SCHATTR_DATADESCR_START); +constexpr TypedWhichId SCHATTR_DATADESCR_SHOW_PERCENTAGE (SCHATTR_DATADESCR_START + 1); +constexpr TypedWhichId SCHATTR_DATADESCR_SHOW_CATEGORY (SCHATTR_DATADESCR_START + 2); +constexpr TypedWhichId SCHATTR_DATADESCR_SHOW_SYMBOL (SCHATTR_DATADESCR_START + 3); +constexpr TypedWhichId SCHATTR_DATADESCR_WRAP_TEXT (SCHATTR_DATADESCR_START + 4); +constexpr TypedWhichId SCHATTR_DATADESCR_SEPARATOR (SCHATTR_DATADESCR_START + 5); +constexpr TypedWhichId SCHATTR_DATADESCR_PLACEMENT (SCHATTR_DATADESCR_START + 6); +constexpr TypedWhichId SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS (SCHATTR_DATADESCR_START + 7); +constexpr TypedWhichId SCHATTR_DATADESCR_NO_PERCENTVALUE (SCHATTR_DATADESCR_START + 8); //percentage values should not be offered +constexpr TypedWhichId SCHATTR_DATADESCR_CUSTOM_LEADER_LINES (SCHATTR_DATADESCR_START + 9); +constexpr TypedWhichId SCHATTR_PERCENT_NUMBERFORMAT_VALUE (SCHATTR_DATADESCR_START + 10); +constexpr TypedWhichId SCHATTR_PERCENT_NUMBERFORMAT_SOURCE (SCHATTR_DATADESCR_START + 11); +constexpr TypedWhichId SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME (SCHATTR_DATADESCR_START + 12); +constexpr sal_uInt16 SCHATTR_DATADESCR_END (SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME); + +//legend +constexpr sal_uInt16 SCHATTR_LEGEND_START (SCHATTR_DATADESCR_END + 1); +constexpr TypedWhichId SCHATTR_LEGEND_POS (SCHATTR_LEGEND_START); +constexpr TypedWhichId SCHATTR_LEGEND_SHOW (SCHATTR_LEGEND_START + 1); +constexpr TypedWhichId SCHATTR_LEGEND_NO_OVERLAY (SCHATTR_LEGEND_START + 2); +constexpr sal_uInt16 SCHATTR_LEGEND_END (SCHATTR_LEGEND_NO_OVERLAY); + +//text +constexpr sal_uInt16 SCHATTR_TEXT_START (SCHATTR_LEGEND_END + 1); +constexpr TypedWhichId SCHATTR_TEXT_DEGREES (SCHATTR_TEXT_START); +constexpr TypedWhichId SCHATTR_TEXT_STACKED (SCHATTR_TEXT_START + 1); +constexpr sal_uInt16 SCHATTR_TEXT_END (SCHATTR_TEXT_STACKED); + +// statistic +constexpr sal_uInt16 SCHATTR_STAT_START (SCHATTR_TEXT_END + 1); +constexpr TypedWhichId SCHATTR_STAT_AVERAGE (SCHATTR_STAT_START); +constexpr TypedWhichId SCHATTR_STAT_KIND_ERROR (SCHATTR_STAT_START + 1); +constexpr TypedWhichId SCHATTR_STAT_PERCENT (SCHATTR_STAT_START + 2); +constexpr TypedWhichId SCHATTR_STAT_BIGERROR (SCHATTR_STAT_START + 3); +constexpr TypedWhichId SCHATTR_STAT_CONSTPLUS (SCHATTR_STAT_START + 4); +constexpr TypedWhichId SCHATTR_STAT_CONSTMINUS (SCHATTR_STAT_START + 5); +constexpr TypedWhichId SCHATTR_STAT_INDICATE (SCHATTR_STAT_START + 6); +constexpr TypedWhichId SCHATTR_STAT_RANGE_POS (SCHATTR_STAT_START + 7); +constexpr TypedWhichId SCHATTR_STAT_RANGE_NEG (SCHATTR_STAT_START + 8); +constexpr TypedWhichId SCHATTR_STAT_ERRORBAR_TYPE (SCHATTR_STAT_START + 9); +constexpr sal_uInt16 SCHATTR_STAT_END (SCHATTR_STAT_ERRORBAR_TYPE); + +// these attributes are for replacement of enum eChartStyle + +constexpr sal_uInt16 SCHATTR_STYLE_START (SCHATTR_STAT_END + 1); + +// for whole chart +constexpr TypedWhichId SCHATTR_STYLE_DEEP (SCHATTR_STYLE_START ); +constexpr TypedWhichId SCHATTR_STYLE_3D (SCHATTR_STYLE_START + 1); +constexpr TypedWhichId SCHATTR_STYLE_VERTICAL (SCHATTR_STYLE_START + 2); + +// also for series +constexpr TypedWhichId SCHATTR_STYLE_BASETYPE (SCHATTR_STYLE_START + 3);// Line,Area,...,Pie +constexpr TypedWhichId SCHATTR_STYLE_LINES (SCHATTR_STYLE_START + 4);// draw line +constexpr TypedWhichId SCHATTR_STYLE_PERCENT (SCHATTR_STYLE_START + 5); +constexpr TypedWhichId SCHATTR_STYLE_STACKED (SCHATTR_STYLE_START + 6); +constexpr TypedWhichId SCHATTR_STYLE_SPLINES (SCHATTR_STYLE_START + 7); + +// also for data point +constexpr TypedWhichId SCHATTR_STYLE_SYMBOL (SCHATTR_STYLE_START + 8); +constexpr TypedWhichId SCHATTR_STYLE_SHAPE (SCHATTR_STYLE_START + 9); +constexpr sal_uInt16 SCHATTR_STYLE_END (SCHATTR_STYLE_SHAPE ); + +constexpr TypedWhichId SCHATTR_AXIS (SCHATTR_STYLE_END + 1); // see chtmodel.hxx defines CHART_AXIS_PRIMARY_X, etc. +//Re-mapped: +constexpr sal_uInt16 SCHATTR_AXIS_START (SCHATTR_AXIS + 1); +//axis scale +constexpr TypedWhichId SCHATTR_AXISTYPE (SCHATTR_AXIS_START); +constexpr TypedWhichId SCHATTR_AXIS_REVERSE (SCHATTR_AXIS_START + 1); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_MIN (SCHATTR_AXIS_START + 2); +constexpr TypedWhichId SCHATTR_AXIS_MIN (SCHATTR_AXIS_START + 3); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_MAX (SCHATTR_AXIS_START + 4); +constexpr TypedWhichId SCHATTR_AXIS_MAX (SCHATTR_AXIS_START + 5); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_STEP_MAIN (SCHATTR_AXIS_START + 6); +constexpr TypedWhichId SCHATTR_AXIS_STEP_MAIN (SCHATTR_AXIS_START + 7); +constexpr TypedWhichId SCHATTR_AXIS_MAIN_TIME_UNIT (SCHATTR_AXIS_START + 8); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_STEP_HELP (SCHATTR_AXIS_START + 9); +constexpr TypedWhichId SCHATTR_AXIS_STEP_HELP (SCHATTR_AXIS_START + 10); +constexpr TypedWhichId SCHATTR_AXIS_HELP_TIME_UNIT (SCHATTR_AXIS_START + 11); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_TIME_RESOLUTION (SCHATTR_AXIS_START + 12); +constexpr TypedWhichId SCHATTR_AXIS_TIME_RESOLUTION (SCHATTR_AXIS_START + 13); +constexpr TypedWhichId SCHATTR_AXIS_LOGARITHM (SCHATTR_AXIS_START + 14); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_DATEAXIS (SCHATTR_AXIS_START + 15); +constexpr TypedWhichId SCHATTR_AXIS_ALLOW_DATEAXIS (SCHATTR_AXIS_START + 16); +constexpr TypedWhichId SCHATTR_AXIS_AUTO_ORIGIN (SCHATTR_AXIS_START + 17); +constexpr TypedWhichId SCHATTR_AXIS_ORIGIN (SCHATTR_AXIS_START + 18); +//axis position +constexpr sal_uInt16 SCHATTR_AXIS_POSITION_START (SCHATTR_AXIS_ORIGIN + 1); +constexpr TypedWhichId SCHATTR_AXIS_TICKS (SCHATTR_AXIS_POSITION_START); +constexpr TypedWhichId SCHATTR_AXIS_HELPTICKS (SCHATTR_AXIS_POSITION_START + 1); +constexpr TypedWhichId SCHATTR_AXIS_POSITION (SCHATTR_AXIS_POSITION_START + 2); +constexpr TypedWhichId SCHATTR_AXIS_POSITION_VALUE (SCHATTR_AXIS_POSITION_START + 3); +constexpr TypedWhichId SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT (SCHATTR_AXIS_POSITION_START + 4); +constexpr TypedWhichId SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION (SCHATTR_AXIS_POSITION_START + 5); +constexpr TypedWhichId SCHATTR_AXIS_LABEL_POSITION (SCHATTR_AXIS_POSITION_START + 6); +constexpr TypedWhichId SCHATTR_AXIS_MARK_POSITION (SCHATTR_AXIS_POSITION_START + 7); +//axis label +constexpr sal_uInt16 SCHATTR_AXIS_LABEL_START (SCHATTR_AXIS_MARK_POSITION + 1); +constexpr TypedWhichId SCHATTR_AXIS_SHOWDESCR (SCHATTR_AXIS_LABEL_START); +constexpr TypedWhichId SCHATTR_AXIS_LABEL_ORDER (SCHATTR_AXIS_LABEL_START + 1); +constexpr TypedWhichId SCHATTR_AXIS_LABEL_OVERLAP (SCHATTR_AXIS_LABEL_START + 2); +constexpr TypedWhichId SCHATTR_AXIS_LABEL_BREAK (SCHATTR_AXIS_LABEL_START + 3); +constexpr sal_uInt16 SCHATTR_AXIS_LABEL_END (SCHATTR_AXIS_LABEL_BREAK); + +constexpr sal_uInt16 SCHATTR_AXIS_END (SCHATTR_AXIS_LABEL_END); + +constexpr TypedWhichId SCHATTR_SYMBOL_BRUSH (SCHATTR_AXIS_END + 1); +constexpr TypedWhichId SCHATTR_STOCK_VOLUME (SCHATTR_AXIS_END + 2); +constexpr TypedWhichId SCHATTR_STOCK_UPDOWN (SCHATTR_AXIS_END + 3); +constexpr TypedWhichId SCHATTR_SYMBOL_SIZE (SCHATTR_AXIS_END + 4); +constexpr TypedWhichId SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY (SCHATTR_AXIS_END + 5); + +// non persistent items (binary format) +constexpr sal_uInt16 SCHATTR_CHARTTYPE_START (SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY + 1); + +// new from New Chart +constexpr TypedWhichId SCHATTR_BAR_OVERLAP (SCHATTR_CHARTTYPE_START ); +constexpr TypedWhichId SCHATTR_BAR_GAPWIDTH (SCHATTR_CHARTTYPE_START + 1); +constexpr TypedWhichId SCHATTR_BAR_CONNECT (SCHATTR_CHARTTYPE_START + 2); +constexpr TypedWhichId SCHATTR_NUM_OF_LINES_FOR_BAR (SCHATTR_CHARTTYPE_START + 3); +constexpr TypedWhichId SCHATTR_SPLINE_ORDER (SCHATTR_CHARTTYPE_START + 4); +constexpr TypedWhichId SCHATTR_SPLINE_RESOLUTION (SCHATTR_CHARTTYPE_START + 5); +constexpr TypedWhichId SCHATTR_GROUP_BARS_PER_AXIS (SCHATTR_CHARTTYPE_START + 6); +constexpr TypedWhichId SCHATTR_STARTING_ANGLE (SCHATTR_CHARTTYPE_START + 7); +constexpr TypedWhichId SCHATTR_CLOCKWISE (SCHATTR_CHARTTYPE_START + 8); +constexpr TypedWhichId SCHATTR_MISSING_VALUE_TREATMENT (SCHATTR_CHARTTYPE_START + 9); +constexpr TypedWhichId SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS (SCHATTR_CHARTTYPE_START + 10); +constexpr TypedWhichId SCHATTR_INCLUDE_HIDDEN_CELLS (SCHATTR_CHARTTYPE_START + 11); +constexpr TypedWhichId SCHATTR_HIDE_LEGEND_ENTRY (SCHATTR_CHARTTYPE_START + 12); + +constexpr sal_uInt16 SCHATTR_CHARTTYPE_END (SCHATTR_HIDE_LEGEND_ENTRY); + +// items for transporting information to dialogs +constexpr sal_uInt16 SCHATTR_MISC_START (SCHATTR_CHARTTYPE_END + 1); +constexpr TypedWhichId SCHATTR_AXIS_FOR_ALL_SERIES (SCHATTR_MISC_START); +constexpr sal_uInt16 SCHATTR_MISC_END (SCHATTR_AXIS_FOR_ALL_SERIES); + +// regression curve +constexpr sal_uInt16 SCHATTR_REGRESSION_START (SCHATTR_MISC_END + 1); +constexpr TypedWhichId SCHATTR_REGRESSION_TYPE (SCHATTR_REGRESSION_START); +constexpr TypedWhichId SCHATTR_REGRESSION_SHOW_EQUATION (SCHATTR_REGRESSION_START + 1); +constexpr TypedWhichId SCHATTR_REGRESSION_SHOW_COEFF (SCHATTR_REGRESSION_START + 2); +constexpr TypedWhichId SCHATTR_REGRESSION_DEGREE (SCHATTR_REGRESSION_START + 3); +constexpr TypedWhichId SCHATTR_REGRESSION_PERIOD (SCHATTR_REGRESSION_START + 4); +constexpr TypedWhichId SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD (SCHATTR_REGRESSION_START + 5); +constexpr TypedWhichId SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD (SCHATTR_REGRESSION_START + 6); +constexpr TypedWhichId SCHATTR_REGRESSION_SET_INTERCEPT (SCHATTR_REGRESSION_START + 7); +constexpr TypedWhichId SCHATTR_REGRESSION_INTERCEPT_VALUE (SCHATTR_REGRESSION_START + 8); +constexpr TypedWhichId SCHATTR_REGRESSION_CURVE_NAME (SCHATTR_REGRESSION_START + 9); +constexpr TypedWhichId SCHATTR_REGRESSION_XNAME (SCHATTR_REGRESSION_START + 10); +constexpr TypedWhichId SCHATTR_REGRESSION_YNAME (SCHATTR_REGRESSION_START + 11); +constexpr TypedWhichId SCHATTR_REGRESSION_MOVING_TYPE (SCHATTR_REGRESSION_START + 12); +constexpr sal_uInt16 SCHATTR_REGRESSION_END (SCHATTR_REGRESSION_MOVING_TYPE); + +constexpr sal_uInt16 SCHATTR_END (SCHATTR_REGRESSION_END); + +// values for Items + +// values for SCHATTR_AXIS_TICKS and SCHATTR_AXIS_HELPTICKS items +#define CHAXIS_MARK_BOTH 3 +#define CHAXIS_MARK_OUTER 2 +#define CHAXIS_MARK_INNER 1 +#define CHAXIS_MARK_NONE 0 + +// values for SCHATTR_AXISTYPE items +#define CHART_AXIS_REALNUMBER 0 +#define CHART_AXIS_PERCENT 1 +#define CHART_AXIS_CATEGORY 2 +#define CHART_AXIS_SERIES 3 +#define CHART_AXIS_DATE 4 + +// values for SCHATTR_STYLE_SHAPE items +#define CHART_SHAPE3D_IGNORE -2 //internal! (GetChartShapeStyle()!) +#define CHART_SHAPE3D_SQUARE 0 +#define CHART_SHAPE3D_CYLINDER 1 +#define CHART_SHAPE3D_CONE 2 +#define CHART_SHAPE3D_PYRAMID 3 //reserved +#define CHART_SHAPE3D_HANOI 4 + +// values for SCHATTR_AXIS items +#define CHART_AXIS_PRIMARY_X 1 +#define CHART_AXIS_PRIMARY_Y 2 +#define CHART_AXIS_PRIMARY_Z 3 +#define CHART_AXIS_SECONDARY_Y 4 +#define CHART_AXIS_SECONDARY_X 5 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/DataPointSymbolSupplier.hxx b/chart2/source/inc/chartview/DataPointSymbolSupplier.hxx new file mode 100644 index 000000000..58d8a9ff2 --- /dev/null +++ b/chart2/source/inc/chartview/DataPointSymbolSupplier.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::drawing { struct Direction3D; } + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTVIEW DataPointSymbolSupplier +{ +public: + static rtl::Reference< SvxShapeGroup > + create2DSymbolList( const rtl::Reference& xTarget + , const css::drawing::Direction3D& rSize ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/DrawModelWrapper.hxx b/chart2/source/inc/chartview/DrawModelWrapper.hxx new file mode 100644 index 000000000..fb977528e --- /dev/null +++ b/chart2/source/inc/chartview/DrawModelWrapper.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::frame { class XModel; } +namespace com::sun::star::drawing { class XDrawPage; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } + +class SdrObjList; +class SdrObject; + +namespace chart +{ + +class OOO_DLLPUBLIC_CHARTVIEW DrawModelWrapper final : private SdrModel +{ +private: + rtl::Reference m_xMainDrawPage; + rtl::Reference m_xHiddenDrawPage; + rtl::Reference m_xChartItemPool; + VclPtr m_pRefDevice; + +public: + SAL_DLLPRIVATE DrawModelWrapper(); + SAL_DLLPRIVATE virtual ~DrawModelWrapper() override; + + css::uno::Reference< css::lang::XMultiServiceFactory > getShapeFactory(); + + // the main page will contain the normal view objects + const rtl::Reference & getMainDrawPage(); + SAL_DLLPRIVATE void clearMainDrawPage(); + + // the extra page is not visible, but contains some extras like the symbols for data points + const rtl::Reference & getHiddenDrawPage(); + + static rtl::Reference + getChartRootShape( const rtl::Reference& xPage ); + + SAL_DLLPRIVATE void lockControllers(); + SAL_DLLPRIVATE void unlockControllers(); + + OutputDevice* getReferenceDevice() const; + + SfxItemPool& GetItemPool(); + + SAL_DLLPRIVATE virtual css::uno::Reference< css::uno::XInterface > + createUnoModel() override; + SAL_DLLPRIVATE css::uno::Reference< css::frame::XModel > + getUnoModel(); + SdrModel& getSdrModel(); + + XColorListRef GetColorList() const; + XDashListRef GetDashList() const; + XLineEndListRef GetLineEndList() const; + XGradientListRef GetGradientList() const; + XHatchListRef GetHatchList() const; + XBitmapListRef GetBitmapList() const; + XPatternListRef GetPatternList() const; + + SdrObject* getNamedSdrObject( const OUString& rName ); + static SdrObject* getNamedSdrObject( const OUString& rName, SdrObjList const * pObjList ); + + static bool removeShape( const rtl::Reference& xShape ); + + void dumpAsXml(xmlTextWriterPtr pWriter) const override; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/ExplicitScaleValues.hxx b/chart2/source/inc/chartview/ExplicitScaleValues.hxx new file mode 100644 index 000000000..a49dddeb6 --- /dev/null +++ b/chart2/source/inc/chartview/ExplicitScaleValues.hxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::chart2 +{ +class XScaling; +} + +namespace chart +{ +/** This structure contains the explicit values for a scale like Minimum and Maximum. + See also css::chart2::ScaleData. +*/ +struct OOO_DLLPUBLIC_CHARTVIEW ExplicitScaleData +{ + ExplicitScaleData(); + + double Minimum; + double Maximum; + double Origin; + + css::chart2::AxisOrientation Orientation; + + css::uno::Reference Scaling; + + sal_Int32 AxisType; //see css::chart2::AxisType + bool m_bShiftedCategoryPosition; + sal_Int32 TimeResolution; //constant of type css::chart::TimeUnit + Date NullDate; +}; + +struct ExplicitSubIncrement +{ + ExplicitSubIncrement(); + + /** Numbers of intervals between two superior ticks. For an axis + this usually means, that IntervalCount - 1 + sub-tick-marks are displayed between two superior ticks. + + */ + sal_Int32 IntervalCount; + + /** If , the distance between two sub-tick-marks on the + screen is always the same. If , the distances may + differ depending on the XScaling. + */ + bool PostEquidistant; +}; + +/** describes how tickmarks are positioned on the scale of an axis. +*/ +struct OOO_DLLPUBLIC_CHARTVIEW ExplicitIncrementData +{ + ExplicitIncrementData(); + + /** the following two members are only for date-time axis + */ + css::chart::TimeInterval MajorTimeInterval; + css::chart::TimeInterval MinorTimeInterval; + + /** the other members are for *not* date-time axis + */ + + /** Distance describes the distance between two + neighboring main tickmarks on a Scale of an axis. + All neighboring main tickmarks have the same constant distance. + +

If the Scale has a XScaling the Distance + may be measured in two different ways - that is - before or after the + scaling is applied.

+ +

On a logarithmic scale for example the distance between two main + tickmarks is typically measured after the scaling is applied: + Distance = log(tick2)-log(tick1) + ( log(1000)-log(100)==log(100)-log(10)==log(10)-log(1)==1==Distance ). + The resulting tickmarks will always look equidistant on the screen. + The other possibility is to have a Distance = tick2-tick1 measured constant + before a scaling is applied, which may lead to non equidistant tickmarks + on the screen.

+ +

PostEquidistant rules whether the Distance + is meant to be a value before or after scaling.

+ */ + double Distance; + + /** + PostEquidistant rules whether the member Distance + describes a distance before or after the scaling is applied. + +

If PostEquidistant equals Distance + is given in values after XScaling is applied, thus resulting + main tickmarks will always look equidistant on the screen. + If PostEquidistant equals Distance + is given in values before XScaling is applied.

+ */ + bool PostEquidistant; + + /** The BaseValue gives a starting point on the scale + to which all further main tickmarks are relatively positioned. + +

The BaseValue is always a value on the scale before + a possible scaling is applied. If the given value is not valid in the + associated scaling the minimum of the scaling is assumed, + if there is no minimum any other obvious value will be assumed.

+ +

E.g.: assume a scale from 0 to 6 with identical scaling. + Further assume this Increment to have Distance==2 and PostEquidistant==false. + Setting BaseValue=0 would lead to main tickmarks 0; 2; 4; 6; + Setting BaseValue=1,3 would lead to main tickmarks 1,3; 3,3; 5,3; + Setting BaseValue=-0,7 would also lead to main tickmarks 1,3; 3,3; 5,3; + And setting BaseValue to 2, -2, 4, -4 etc. in this example + leads to the same result as BaseValue=0.

+ */ + double BaseValue; + + /** SubIncrements describes the positioning of further + sub tickmarks on the scale of an axis. + +

The first SubIncrement in this sequence determines how the + distance between two neighboring main tickmarks is divided for positioning + of further sub tickmarks. Every following SubIncrement determines the + positions of subsequent tickmarks in relation to their parent tickmarks + given by the preceding SubIncrement.

+ */ + std::vector SubIncrements; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/ExplicitValueProvider.hxx b/chart2/source/inc/chartview/ExplicitValueProvider.hxx new file mode 100644 index 000000000..d97de8458 --- /dev/null +++ b/chart2/source/inc/chartview/ExplicitValueProvider.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::uno { class XInterface; } +namespace com::sun::star::uno { template class Reference; } +namespace com::sun::star::uno { template class Sequence; } +namespace com::sun::star::util { class XNumberFormatsSupplier; } +namespace com::sun::star::awt { struct Rectangle; } +class SvxShape; + +namespace chart +{ + +class BaseCoordinateSystem; +class DrawModelWrapper; +class ChartModel; +struct ExplicitIncrementData; +struct ExplicitScaleData; + +class OOO_DLLPUBLIC_CHARTVIEW ExplicitValueProvider +{ +public: + /** Gives calculated scale and increment values for a given xAxis in the current view. + In contrast to the model data these explicit values are always complete as missing auto properties are calculated. + If the given Axis could not be found or for another reason no correct output can be given false is returned. + */ + virtual bool getExplicitValuesForAxis( + css::uno::Reference< css::chart2::XAxis > xAxis + , ExplicitScaleData& rExplicitScale + , ExplicitIncrementData& rExplicitIncrement )=0; + + /** for rotated objects the shape size and position differs from the visible rectangle + if bSnapRect is set to true you get the resulting visible position (left-top) and size + */ + virtual css::awt::Rectangle + getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect=false )=0; + + virtual css::awt::Rectangle getDiagramRectangleExcludingAxes()=0; + + virtual rtl::Reference< SvxShape > + getShapeForCID( const OUString& rObjectCID )=0; + + virtual std::shared_ptr< DrawModelWrapper > getDrawModelWrapper() = 0; + + static const css::uno::Sequence& getUnoTunnelId(); + + static css::awt::Rectangle + AddSubtractAxisTitleSizes( + ChartModel& rModel + , ExplicitValueProvider* pChartView + , const css::awt::Rectangle& rPositionAndSize, bool bSubtract ); + + static sal_Int32 getExplicitNumberFormatKeyForAxis( + const css::uno::Reference< css::chart2::XAxis >& xAxis + , const rtl::Reference< ::chart::BaseCoordinateSystem > & xCorrespondingCoordinateSystem + , const rtl::Reference<::chart::ChartModel>& xChartDoc); + + static sal_Int32 getExplicitNumberFormatKeyForDataLabel( + const css::uno::Reference< css::beans::XPropertySet >& xSeriesOrPointProp ); + + static sal_Int32 getExplicitPercentageNumberFormatKeyForDataLabel( + const css::uno::Reference< css::beans::XPropertySet >& xSeriesOrPointProp + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + +protected: + ~ExplicitValueProvider() = default; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/chartviewdllapi.hxx b/chart2/source/inc/chartview/chartviewdllapi.hxx new file mode 100644 index 000000000..533a5cb83 --- /dev/null +++ b/chart2/source/inc/chartview/chartviewdllapi.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#if defined OOO_DLLIMPLEMENTATION_CHARTVIEW +#define OOO_DLLPUBLIC_CHARTVIEW SAL_DLLPUBLIC_EXPORT +#else +#define OOO_DLLPUBLIC_CHARTVIEW SAL_DLLPUBLIC_IMPORT +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/defines.hxx b/chart2/source/inc/defines.hxx new file mode 100644 index 000000000..1eb464bc2 --- /dev/null +++ b/chart2/source/inc/defines.hxx @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +constexpr double FIXED_SIZE_FOR_3D_CHART_VOLUME = 10000.0; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/res_BarGeometry.hxx b/chart2/source/inc/res_BarGeometry.hxx new file mode 100644 index 000000000..9e0c01870 --- /dev/null +++ b/chart2/source/inc/res_BarGeometry.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class BarGeometryResources +{ +public: + explicit BarGeometryResources(weld::Builder* pParent); + + void set_visible(bool bShow); + void set_sensitive(bool bEnable); + + sal_Int32 get_selected_index() const; + void select(sal_Int32 nPos); + + void connect_changed(const Link& rLink); + +private: + std::unique_ptr m_xFT_Geometry; + std::unique_ptr m_xLB_Geometry; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/servicenames.hxx b/chart2/source/inc/servicenames.hxx new file mode 100644 index 000000000..30e9b40f5 --- /dev/null +++ b/chart2/source/inc/servicenames.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +inline constexpr OUStringLiteral CHART_MODEL_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartModel"; +inline constexpr OUStringLiteral CHART_MODEL_SERVICE_NAME = u"com.sun.star.chart2.ChartDocument"; +//@todo create your own service containing the service com.sun.star.document.OfficeDocument + +inline constexpr OUStringLiteral CHART_CONTROLLER_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartController"; +inline constexpr OUStringLiteral CHART_CONTROLLER_SERVICE_NAME + = u"com.sun.star.chart2.ChartController"; +//@todo create your own service containing the service com.sun.star.frame.Controller + +inline constexpr OUStringLiteral CHART_VIEW_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartView"; +inline constexpr OUStringLiteral CHART_VIEW_SERVICE_NAME = u"com.sun.star.chart2.ChartView"; + +inline constexpr OUStringLiteral CHART_FRAMELOADER_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartFrameLoader"; +inline constexpr OUStringLiteral CHART_FRAMELOADER_SERVICE_NAME + = u"com.sun.star.frame.SynchronousFrameLoader"; + +inline constexpr OUStringLiteral CHART_WIZARD_DIALOG_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.WizardDialog"; +inline constexpr OUStringLiteral CHART_WIZARD_DIALOG_SERVICE_NAME + = u"com.sun.star.chart2.WizardDialog"; + +inline constexpr OUStringLiteral CHART_TYPE_DIALOG_SERVICE_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartTypeDialog"; +inline constexpr OUStringLiteral CHART_TYPE_DIALOG_SERVICE_NAME + = u"com.sun.star.chart2.ChartTypeDialog"; + +// wrapper for old UNO API (com.sun.star.chart) +inline constexpr OUStringLiteral CHART_CHARTAPIWRAPPER_IMPLEMENTATION_NAME + = u"com.sun.star.comp.chart2.ChartDocumentWrapper"; +inline constexpr OUStringLiteral CHART_CHARTAPIWRAPPER_SERVICE_NAME + = u"com.sun.star.chart2.ChartDocumentWrapper"; + +// accessibility +inline constexpr OUStringLiteral CHART_ACCESSIBLE_TEXT_SERVICE_NAME + = u"com.sun.star.accessibility.AccessibleTextComponent"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/servicenames_charttypes.hxx b/chart2/source/inc/servicenames_charttypes.hxx new file mode 100644 index 000000000..0c06c2d3e --- /dev/null +++ b/chart2/source/inc/servicenames_charttypes.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_AREA + = u"com.sun.star.chart2.AreaChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_BAR + = u"com.sun.star.chart2.BarChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_COLUMN + = u"com.sun.star.chart2.ColumnChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_LINE + = u"com.sun.star.chart2.LineChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_SCATTER + = u"com.sun.star.chart2.ScatterChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_PIE + = u"com.sun.star.chart2.PieChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_NET + = u"com.sun.star.chart2.NetChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET + = u"com.sun.star.chart2.FilledNetChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK + = u"com.sun.star.chart2.CandleStickChartType"; +inline constexpr OUStringLiteral CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE + = u"com.sun.star.chart2.BubbleChartType"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/servicenames_coosystems.hxx b/chart2/source/inc/servicenames_coosystems.hxx new file mode 100644 index 000000000..f8472a3df --- /dev/null +++ b/chart2/source/inc/servicenames_coosystems.hxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +inline constexpr OUStringLiteral CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME = u"com.sun.star.chart2.CoordinateSystems.CartesianView"; +inline constexpr OUStringLiteral CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME = u"com.sun.star.chart2.CoordinateSystems.PolarView"; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/filter/XMLFilter.cxx b/chart2/source/model/filter/XMLFilter.cxx new file mode 100644 index 000000000..a31f1d9f6 --- /dev/null +++ b/chart2/source/model/filter/XMLFilter.cxx @@ -0,0 +1,773 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::osl::MutexGuard; + +namespace +{ +constexpr OUStringLiteral sXML_metaStreamName = u"meta.xml"; +constexpr OUStringLiteral sXML_styleStreamName = u"styles.xml"; +constexpr OUStringLiteral sXML_contentStreamName = u"content.xml"; + + +uno::Reference< embed::XStorage > lcl_getWriteStorage( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const uno::Reference< uno::XComponentContext >& xContext,const OUString& _sMediaType) +{ + uno::Reference< embed::XStorage > xStorage; + try + { + apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor ); + if( aMDHelper.ISSET_Storage ) + { + xStorage = aMDHelper.Storage; + } + else + { + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create( xContext ) ); + + std::vector< beans::PropertyValue > aPropertiesForStorage; + + for( sal_Int32 i=rMediaDescriptor.getLength(); i--; ) + { + // properties understood by storage factory + // (see package/source/xstor/xfactory.cxx for details) + if ( rMediaDescriptor[i].Name == "InteractionHandler" || rMediaDescriptor[i].Name == "Password" || rMediaDescriptor[i].Name == "RepairPackage" ) + { + aPropertiesForStorage.push_back( rMediaDescriptor[i] ); + } + } + + if( aMDHelper.ISSET_Storage ) + xStorage.set( aMDHelper.Storage ); + else + { + Sequence< uno::Any > aStorageArgs{ + aMDHelper.ISSET_OutputStream ? uno::Any(aMDHelper.OutputStream) + : uno::Any(aMDHelper.URL), + uno::Any(embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE), + uno::Any(comphelper::containerToSequence( aPropertiesForStorage )) + }; + + xStorage.set( + xStorageFact->createInstanceWithArguments( aStorageArgs ), + uno::UNO_QUERY_THROW ); + } + } + + // set correct media type at storage + uno::Reference xProp(xStorage,uno::UNO_QUERY); + OUString aMediaType; + if ( ! xProp.is() || + ! ( xProp->getPropertyValue( "MediaType") >>= aMediaType ) || + ( aMediaType.isEmpty() )) + { + xProp->setPropertyValue( "MediaType", uno::Any( _sMediaType )); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xStorage; +} + +uno::Reference< embed::XStorage > lcl_getReadStorage( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const uno::Reference< uno::XComponentContext >& xContext) +{ + uno::Reference< embed::XStorage > xStorage; + + try + { + apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor ); + if( aMDHelper.ISSET_Storage ) + { + xStorage = aMDHelper.Storage; + } + else + { + // get XStream from MediaDescriptor + uno::Reference< io::XInputStream > xStream; + std::vector< beans::PropertyValue > aPropertiesForStorage; + for( sal_Int32 i=rMediaDescriptor.getLength(); i--; ) + { + if( rMediaDescriptor[i].Name == "InputStream" ) + xStream.set( rMediaDescriptor[i].Value, uno::UNO_QUERY ); + + // properties understood by storage factory + // (see package/source/xstor/xfactory.cxx for details) + if ( rMediaDescriptor[i].Name == "InteractionHandler" || rMediaDescriptor[i].Name == "Password" || rMediaDescriptor[i].Name == "RepairPackage" ) + { + aPropertiesForStorage.push_back( rMediaDescriptor[i] ); + } + } + OSL_ENSURE( xStream.is(), "No Stream" ); + if( ! xStream.is()) + return xStorage; + + // convert XInputStream to XStorage via the storage factory + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create( xContext ) ); + Sequence< uno::Any > aStorageArgs{ + uno::Any(xStream), + uno::Any(embed::ElementModes::READ | embed::ElementModes::NOCREATE), + uno::Any(comphelper::containerToSequence( aPropertiesForStorage )) + }; + xStorage.set( + xStorageFact->createInstanceWithArguments( aStorageArgs ), uno::UNO_QUERY_THROW ); + } + + OSL_ENSURE( xStorage.is(), "No Storage" ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xStorage; +} + +} // anonymous namespace + +namespace chart +{ + +XMLFilter::XMLFilter( Reference< uno::XComponentContext > const & xContext ) : + m_xContext( xContext ), + m_bCancelOperation( false ) +{} + +XMLFilter::~XMLFilter() +{} + +// ____ XFilter ____ +sal_Bool SAL_CALL XMLFilter::filter( + const Sequence< beans::PropertyValue >& aDescriptor ) +{ + bool bResult = false; + + MutexGuard aGuard( m_aMutex ); + + // ignore cancel flag at start of function + // note: is currently ignored during import/export + if( m_bCancelOperation ) + m_bCancelOperation = false; + + if( m_xSourceDoc.is()) + { + OSL_ENSURE( ! m_xTargetDoc.is(), "source doc is set -> target document should not be set" ); + if( impl_Export( m_xSourceDoc, + aDescriptor ) == ERRCODE_NONE ) + { + m_xSourceDoc = nullptr; + bResult = true; + } + } + else if( m_xTargetDoc.is()) + { + if( impl_Import( m_xTargetDoc, + aDescriptor ) == ERRCODE_NONE ) + { + m_xTargetDoc = nullptr; + bResult = true; + } + } + else + { + OSL_FAIL( "filter() called with no document set" ); + } + + return bResult; +} + +void SAL_CALL XMLFilter::cancel() +{ + // if mutex is locked set "cancel state" + // note: is currently ignored in filter-method + if( ! m_aMutex.tryToAcquire()) + { + m_bCancelOperation = true; + } +} + +// ____ XImporter ____ +void SAL_CALL XMLFilter::setTargetDocument( + const Reference< lang::XComponent >& Document ) +{ + MutexGuard aGuard( m_aMutex ); + OSL_ENSURE( ! m_xSourceDoc.is(), "Setting target doc while source doc is set" ); + + m_xTargetDoc = Document; +} + +// ____ XExporter ____ +void SAL_CALL XMLFilter::setSourceDocument( + const Reference< lang::XComponent >& Document ) +{ + MutexGuard aGuard( m_aMutex ); + OSL_ENSURE( ! m_xTargetDoc.is(), "Setting source doc while target doc is set" ); + + m_xSourceDoc = Document; +} + +ErrCode XMLFilter::impl_Import( + const Reference< lang::XComponent > & xDocumentComp, + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + ErrCode nWarning = ERRCODE_NONE; + + OSL_ENSURE( xDocumentComp.is(), "Import: No Model" ); + OSL_ENSURE( m_xContext.is(), "Import: No ComponentContext" ); + + if( ! (xDocumentComp.is() && + m_xContext.is())) + return nWarning; + + try + { + Reference< lang::XServiceInfo > xServInfo( xDocumentComp, uno::UNO_QUERY_THROW ); + if( ! xServInfo->supportsService( "com.sun.star.chart2.ChartDocument")) + { + OSL_FAIL( "Import: No ChartDocument" ); + return ERRCODE_SFX_GENERAL; + } + + Reference< lang::XMultiComponentFactory > xFactory( m_xContext->getServiceManager()); + OSL_ENSURE( xFactory.is(), "Import: No Factory" ); + if( ! xFactory.is()) + return ERRCODE_SFX_GENERAL; + + bool bOasis = true; + isOasisFormat( rMediaDescriptor, bOasis ); + Reference< embed::XStorage > xStorage( lcl_getReadStorage( rMediaDescriptor, m_xContext)); + if( ! xStorage.is()) + return ERRCODE_SFX_GENERAL; + + uno::Reference xGraphicStorageHandler; + uno::Reference xServiceFactory(xFactory, uno::UNO_QUERY); + if (xServiceFactory.is()) + { + uno::Sequence aArgs{ uno::Any(xStorage) }; + xGraphicStorageHandler.set( + xServiceFactory->createInstanceWithArguments( + "com.sun.star.comp.Svx.GraphicImportHelper", aArgs), uno::UNO_QUERY); + } + + // create XPropertySet with extra information for the filter + /** property map for import info set */ + static comphelper::PropertyMapEntry const aImportInfoMap[] = + { + // necessary properties for XML progress bar at load time + { OUString("ProgressRange"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("ProgressMax"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("ProgressCurrent"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("PrivateData"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("BaseURI"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("StreamRelPath"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("StreamName"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("BuildId"), 0, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 }, + }; + uno::Reference< beans::XPropertySet > xImportInfo( + comphelper::GenericPropertySet_CreateInstance( + new comphelper::PropertySetInfo( aImportInfoMap ) ) ); + + // Set base URI and Hierarchical Name + OUString aHierarchName, aBaseUri; + // why retrieve this from the model when it's available as rMediaDescriptor? + uno::Reference const xModel(m_xTargetDoc, uno::UNO_QUERY); + if( xModel.is() ) + { + const uno::Sequence< beans::PropertyValue > aModProps = xModel->getArgs(); + for( beans::PropertyValue const & prop : aModProps ) + { + if( prop.Name == "HierarchicalDocumentName" ) + { + // Actually this argument only has meaning for embedded documents + prop.Value >>= aHierarchName; + } + else if( prop.Name == "DocumentBaseURL" ) + { + prop.Value >>= aBaseUri; + } + } + } + + // needed for relative URLs, but in clipboard copy/paste there may be none + SAL_INFO_IF(aBaseUri.isEmpty(), "chart2", "chart::XMLFilter: no base URL"); + if( !aBaseUri.isEmpty() ) + xImportInfo->setPropertyValue( "BaseURI", uno::Any( aBaseUri ) ); + + if( !aHierarchName.isEmpty() ) + xImportInfo->setPropertyValue( "StreamRelPath", uno::Any( aHierarchName ) ); + + // import meta information + if( bOasis ) + nWarning = impl_ImportStream( + sXML_metaStreamName, + "com.sun.star.comp.Chart.XMLOasisMetaImporter", + xStorage, xFactory, xGraphicStorageHandler, xImportInfo ); + + // import styles + ErrCode nTmpErr = impl_ImportStream( + sXML_styleStreamName, + bOasis + ? OUString("com.sun.star.comp.Chart.XMLOasisStylesImporter") + : OUString("com.sun.star.comp.Chart.XMLStylesImporter"), + xStorage, xFactory, xGraphicStorageHandler, xImportInfo ); + nWarning = nWarning != ERRCODE_NONE ? nWarning : nTmpErr; + + // import content + ErrCode nContentWarning = impl_ImportStream( + sXML_contentStreamName, + bOasis + ? OUString("com.sun.star.comp.Chart.XMLOasisContentImporter") + : OUString("com.sun.star.comp.Chart.XMLContentImporter"), + xStorage, xFactory, xGraphicStorageHandler, xImportInfo ); + nWarning = nWarning != ERRCODE_NONE ? nWarning : nContentWarning; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + + // something went awry + nWarning = ERRCODE_SFX_GENERAL; + } + + return nWarning; +} + +ErrCode XMLFilter::impl_ImportStream( + const OUString & rStreamName, + const OUString & rServiceName, + const Reference< embed::XStorage > & xStorage, + const Reference< lang::XMultiComponentFactory > & xFactory, + const Reference< document::XGraphicStorageHandler > & xGraphicStorageHandler, + uno::Reference< beans::XPropertySet > const & xImportInfo ) +{ + ErrCode nWarning = ERRCODE_SFX_GENERAL; + + if( ! (xStorage.is() && + xStorage->hasByName( rStreamName ))) + return ERRCODE_NONE; + + if( xImportInfo.is() ) + xImportInfo->setPropertyValue( "StreamName", uno::Any( rStreamName ) ); + + if( xStorage.is() && + xStorage->isStreamElement( rStreamName ) ) + { + try + { + auto xInputStream = + xStorage->openStreamElement( + rStreamName, + embed::ElementModes::READ | embed::ElementModes::NOCREATE ); + + // todo: encryption + + if( xInputStream.is()) + { + sal_Int32 nArgs = 0; + if( xGraphicStorageHandler.is()) + nArgs++; + if( xImportInfo.is()) + nArgs++; + + uno::Sequence< uno::Any > aFilterCompArgs( nArgs ); + auto aFilterCompArgsRange = asNonConstRange(aFilterCompArgs); + + nArgs = 0; + if( xGraphicStorageHandler.is()) + aFilterCompArgsRange[nArgs++] <<= xGraphicStorageHandler; + if( xImportInfo.is()) + aFilterCompArgsRange[ nArgs++ ] <<= xImportInfo; + + // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler + Reference< XInterface > xFilter = + xFactory->createInstanceWithArgumentsAndContext( rServiceName, aFilterCompArgs, m_xContext ); + assert(xFilter); + Reference< document::XImporter > xImporter( xFilter, uno::UNO_QUERY ); + assert(xImporter); + xImporter->setTargetDocument( Reference< lang::XComponent >( m_xTargetDoc, uno::UNO_SET_THROW )); + + if ( !m_sDocumentHandler.isEmpty() ) + { + try + { + uno::Sequence< uno::Any > aArgs{ + uno::Any(beans::NamedValue("DocumentHandler", uno::Any(xFilter))), + uno::Any(beans::NamedValue("Model", uno::Any(m_xTargetDoc))) + }; + + xFilter = xFactory->createInstanceWithArgumentsAndContext(m_sDocumentHandler,aArgs,m_xContext); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "failed to instantiate " << m_sDocumentHandler); + } + } + xml::sax::InputSource aParserInput; + aParserInput.aInputStream.set(xInputStream, uno::UNO_QUERY_THROW); + + // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler + Reference< xml::sax::XFastParser > xFastParser(xFilter, uno::UNO_QUERY); + if (xFastParser.is()) + xFastParser->parseStream(aParserInput); + else + { + Reference xParser = xml::sax::Parser::create(m_xContext); + xParser->setDocumentHandler( uno::Reference(xFilter, uno::UNO_QUERY_THROW) ); + xParser->parseStream(aParserInput); + } + } + + // load was successful + nWarning = ERRCODE_NONE; + } + catch (const xml::sax::SAXParseException&) + { + // todo: if encrypted: ERRCODE_SFX_WRONGPASSWORD + } + catch (const xml::sax::SAXException&) + { + // todo: if encrypted: ERRCODE_SFX_WRONGPASSWORD + } + catch (const packages::zip::ZipIOException&) + { + nWarning = ERRCODE_IO_BROKENPACKAGE; + } + catch (const io::IOException&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nWarning; +} + +ErrCode XMLFilter::impl_Export( + const Reference< lang::XComponent > & xDocumentComp, + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + m_aMediaDescriptor = rMediaDescriptor; + //save + + ErrCode nWarning = ERRCODE_NONE; + + OSL_ENSURE( xDocumentComp.is(), "Export: No Model" ); + OSL_ENSURE( m_xContext.is(), "Export: No ComponentContext" ); + + if( !xDocumentComp.is() || !m_xContext.is() ) + return nWarning; + + try + { + Reference< lang::XServiceInfo > xServInfo( xDocumentComp, uno::UNO_QUERY_THROW ); + if( ! xServInfo->supportsService( "com.sun.star.chart2.ChartDocument")) + { + OSL_FAIL( "Export: No ChartDocument" ); + return ERRCODE_SFX_GENERAL; + } + + Reference< lang::XMultiComponentFactory > xFactory( m_xContext->getServiceManager()); + OSL_ENSURE( xFactory.is(), "Export: No Factory" ); + if( ! xFactory.is()) + return ERRCODE_SFX_GENERAL; + uno::Reference< lang::XMultiServiceFactory > xServiceFactory( m_xContext->getServiceManager(), uno::UNO_QUERY); + if( ! xServiceFactory.is()) + return ERRCODE_SFX_GENERAL; + + uno::Reference< xml::sax::XWriter > xSaxWriter = xml::sax::Writer::create(m_xContext); + + bool bOasis = true; + isOasisFormat( rMediaDescriptor, bOasis ); + + uno::Reference< embed::XStorage > xStorage( lcl_getWriteStorage( rMediaDescriptor, m_xContext, getMediaType(bOasis) ) ); + OSL_ENSURE( xStorage.is(), "No Storage" ); + if( ! xStorage.is()) + return ERRCODE_SFX_GENERAL; + + uno::Reference< xml::sax::XDocumentHandler> xDocHandler = xSaxWriter; + + if ( !m_sDocumentHandler.isEmpty() ) + { + try + { + uno::Sequence< uno::Any > aArgs{ + uno::Any(beans::NamedValue("DocumentHandler", uno::Any(xDocHandler))), + uno::Any(beans::NamedValue("Model", uno::Any(xDocumentComp))) + }; + + xDocHandler.set(xServiceFactory->createInstanceWithArguments(m_sDocumentHandler,aArgs), uno::UNO_QUERY ); + xSaxWriter.set(xDocHandler,uno::UNO_QUERY); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION( "chart2", "Exception caught!"); + } + } + + Reference xGraphicStorageHandler; + xGraphicStorageHandler.set(document::GraphicStorageHandler::createWithStorage(m_xContext, xStorage)); + + // property map for export info set + static comphelper::PropertyMapEntry const aExportInfoMap[] = + { + { OUString("UsePrettyPrinting"), 0, cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("BaseURI"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("StreamRelPath"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("StreamName"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("ExportTableNumberList"), 0, cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + }; + + uno::Reference< beans::XPropertySet > xInfoSet = + comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ); + + bool bUsePrettyPrinting( officecfg::Office::Common::Save::Document::PrettyPrinting::get() ); + xInfoSet->setPropertyValue( "UsePrettyPrinting", uno::Any( bUsePrettyPrinting ) ); + if( ! bOasis ) + xInfoSet->setPropertyValue( "ExportTableNumberList", uno::Any( true )); + + sal_Int32 nArgs = 2; + if( xGraphicStorageHandler.is()) + nArgs++; + + uno::Sequence< uno::Any > aFilterProperties( nArgs ); + { + auto pFilterProperties = aFilterProperties.getArray(); + nArgs = 0; + pFilterProperties[ nArgs++ ] <<= xInfoSet; + pFilterProperties[ nArgs++ ] <<= xDocHandler; + if( xGraphicStorageHandler.is()) + pFilterProperties[ nArgs++ ] <<= xGraphicStorageHandler; + } + + // export meta information + if( bOasis ) + nWarning = impl_ExportStream( + sXML_metaStreamName, + "com.sun.star.comp.Chart.XMLOasisMetaExporter", + xStorage, xSaxWriter, xServiceFactory, aFilterProperties ); + + // export styles + ErrCode nTmp = impl_ExportStream( + sXML_styleStreamName, + bOasis + ? OUString("com.sun.star.comp.Chart.XMLOasisStylesExporter") + : OUString("com.sun.star.comp.Chart.XMLStylesExporter"), // soffice 6/7 + xStorage, xSaxWriter, xServiceFactory, aFilterProperties ); + nWarning = nWarning != ERRCODE_NONE ? nWarning : nTmp; + + // export content + ErrCode nContentWarning = impl_ExportStream( + sXML_contentStreamName, + bOasis + ? OUString("com.sun.star.comp.Chart.XMLOasisContentExporter") + : OUString("com.sun.star.comp.Chart.XMLContentExporter"), + xStorage, xSaxWriter, xServiceFactory, aFilterProperties ); + nWarning = nWarning != ERRCODE_NONE ? nWarning : nContentWarning; + + Reference< lang::XComponent > xComp(xGraphicStorageHandler, uno::UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + + uno::Reference xTransact( xStorage ,uno::UNO_QUERY); + if ( xTransact.is() ) + xTransact->commit(); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + + // something went awry + nWarning = ERRCODE_SFX_GENERAL; + } + + return nWarning; +} + +ErrCode XMLFilter::impl_ExportStream( + const OUString & rStreamName, + const OUString & rServiceName, + const Reference< embed::XStorage > & xStorage, + const uno::Reference< xml::sax::XWriter >& xActiveDataSource, + const Reference< lang::XMultiServiceFactory >& xServiceFactory, + const Sequence< uno::Any > & rFilterProperties ) +{ + try + { + if( !xServiceFactory.is() ) + return ERRCODE_SFX_GENERAL; + if( !xStorage.is() ) + return ERRCODE_SFX_GENERAL; + if ( !xActiveDataSource.is() ) + return ERRCODE_SFX_GENERAL; + + uno::Reference< io::XStream > xStream( xStorage->openStreamElement( + rStreamName, embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ) ); + if ( !xStream.is() ) + return ERRCODE_SFX_GENERAL; + uno::Reference< io::XOutputStream > xOutputStream( xStream->getOutputStream() ); + if ( !xOutputStream.is() ) + return ERRCODE_SFX_GENERAL; + + uno::Reference< beans::XPropertySet > xStreamProp( xOutputStream, uno::UNO_QUERY ); + if(xStreamProp.is()) try + { + xStreamProp->setPropertyValue( "MediaType", uno::Any( OUString("text/xml") ) ); + xStreamProp->setPropertyValue( "Compressed", uno::Any( true ) );//@todo? + xStreamProp->setPropertyValue( "UseCommonStoragePasswordEncryption", uno::Any( true ) ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + xActiveDataSource->setOutputStream(xOutputStream); + + // set Base URL + { + uno::Reference< beans::XPropertySet > xInfoSet; + if( rFilterProperties.hasElements() ) + rFilterProperties.getConstArray()[0] >>= xInfoSet; + OSL_ENSURE( xInfoSet.is(), "missing infoset for export" ); + if( xInfoSet.is() ) + xInfoSet->setPropertyValue( "StreamName", uno::Any( rStreamName ) ); + } + + Reference< XExporter > xExporter( xServiceFactory->createInstanceWithArguments( + rServiceName, rFilterProperties ), uno::UNO_QUERY); + if ( !xExporter.is() ) + return ERRCODE_SFX_GENERAL; + + xExporter->setSourceDocument( m_xSourceDoc ); + + uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY ); + if ( !xFilter.is() ) + return ERRCODE_SFX_GENERAL; + + xFilter->filter(m_aMediaDescriptor); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return ERRCODE_NONE; +} + +void XMLFilter::isOasisFormat(const Sequence< beans::PropertyValue >& _rMediaDescriptor, bool & rOutOASIS ) +{ + apphelper::MediaDescriptorHelper aMDHelper( _rMediaDescriptor ); + if( aMDHelper.ISSET_FilterName ) + rOutOASIS = aMDHelper.FilterName == "chart8"; +} +OUString XMLFilter::getMediaType(bool _bOasis) +{ + return _bOasis ? OUString(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII) : OUString(MIMETYPE_VND_SUN_XML_CHART_ASCII); +} + +OUString SAL_CALL XMLFilter::getImplementationName() +{ + return "com.sun.star.comp.chart2.XMLFilter"; +} + +sal_Bool SAL_CALL XMLFilter::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL XMLFilter::getSupportedServiceNames() +{ + return { + "com.sun.star.document.ImportFilter", + "com.sun.star.document.ExportFilter" + }; + // todo: services are incomplete. Missing: + // XInitialization, XNamed +} + +void XMLReportFilterHelper::isOasisFormat(const Sequence< beans::PropertyValue >& _rMediaDescriptor, bool & rOutOASIS ) +{ + apphelper::MediaDescriptorHelper aMDHelper( _rMediaDescriptor ); + if( aMDHelper.ISSET_FilterName ) + rOutOASIS = aMDHelper.FilterName == "StarOffice XML (Base) Report Chart"; +} +OUString XMLReportFilterHelper::getMediaType(bool ) +{ + return MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_XMLFilter_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::XMLFilter(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_report_XMLFilter_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::XMLReportFilterHelper(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/inc/CartesianCoordinateSystem.hxx b/chart2/source/model/inc/CartesianCoordinateSystem.hxx new file mode 100644 index 000000000..d84f53bf5 --- /dev/null +++ b/chart2/source/model/inc/CartesianCoordinateSystem.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class CartesianCoordinateSystem : public BaseCoordinateSystem +{ +public: + explicit CartesianCoordinateSystem(sal_Int32 nDimensionCount); + explicit CartesianCoordinateSystem(const CartesianCoordinateSystem& rSource); + virtual ~CartesianCoordinateSystem() override; + + // ____ XCoordinateSystem ____ + virtual OUString SAL_CALL getCoordinateSystemType() override; + virtual OUString SAL_CALL getViewServiceName() override; + + // ____ XCloneable ____ + virtual css::uno::Reference SAL_CALL createClone() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +class CartesianCoordinateSystem2d final : public CartesianCoordinateSystem +{ +public: + explicit CartesianCoordinateSystem2d(); + virtual ~CartesianCoordinateSystem2d() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +class CartesianCoordinateSystem3d final : public CartesianCoordinateSystem +{ +public: + explicit CartesianCoordinateSystem3d(); + virtual ~CartesianCoordinateSystem3d() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/inc/PolarCoordinateSystem.hxx b/chart2/source/model/inc/PolarCoordinateSystem.hxx new file mode 100644 index 000000000..43eaefa5b --- /dev/null +++ b/chart2/source/model/inc/PolarCoordinateSystem.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class PolarCoordinateSystem : public BaseCoordinateSystem +{ +public: + explicit PolarCoordinateSystem(sal_Int32 nDimensionCount); + explicit PolarCoordinateSystem(const PolarCoordinateSystem& rSource); + virtual ~PolarCoordinateSystem() override; + + // ____ XCoordinateSystem ____ + virtual OUString SAL_CALL getCoordinateSystemType() override; + virtual OUString SAL_CALL getViewServiceName() override; + + // ____ XCloneable ____ + virtual css::uno::Reference SAL_CALL createClone() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +class PolarCoordinateSystem2d final : public PolarCoordinateSystem +{ +public: + explicit PolarCoordinateSystem2d(); + virtual ~PolarCoordinateSystem2d() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +class PolarCoordinateSystem3d final : public PolarCoordinateSystem +{ +public: + explicit PolarCoordinateSystem3d(); + virtual ~PolarCoordinateSystem3d() override; + + // ____ XServiceInfo ____ + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/inc/StockBar.hxx b/chart2/source/model/inc/StockBar.hxx new file mode 100644 index 000000000..dbc357ea4 --- /dev/null +++ b/chart2/source/model/inc/StockBar.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + StockBar_Base; +} + +class StockBar final : + public cppu::BaseMutex, + public impl::StockBar_Base, + public ::property::OPropertySet +{ +public: + explicit StockBar( bool bRisingCourse ); + virtual ~StockBar() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + +private: + explicit StockBar( const StockBar & rOther ); + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/inc/XMLFilter.hxx b/chart2/source/model/inc/XMLFilter.hxx new file mode 100644 index 000000000..332bf62ca --- /dev/null +++ b/chart2/source/model/inc/XMLFilter.hxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::xml::sax { class XWriter; } +namespace com::sun::star::lang { class XMultiComponentFactory; } + +namespace com::sun::star { + namespace embed { + class XStorage; + } + namespace xml::sax { + class XFastParser; + } + namespace document { + class XGraphicStorageHandler; + } +} + +namespace chart +{ + +class XMLFilter : public + ::cppu::WeakImplHelper< + css::document::XFilter, + css::document::XExporter, + css::document::XImporter, + css::lang::XServiceInfo > +{ +public: + explicit XMLFilter( css::uno::Reference< css::uno::XComponentContext > const & xContext ); + virtual ~XMLFilter() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +protected: + // ____ XFilter ____ + virtual sal_Bool SAL_CALL filter( + const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor ) override; + virtual void SAL_CALL cancel() override; + + // ____ XImporter ____ + virtual void SAL_CALL setTargetDocument( + const css::uno::Reference< css::lang::XComponent >& Document ) override; + + // ____ XExporter ____ + virtual void SAL_CALL setSourceDocument( + const css::uno::Reference< css::lang::XComponent >& Document ) override; + + void setDocumentHandler(const OUString& _sDocumentHandler) { m_sDocumentHandler = _sDocumentHandler; } + + virtual OUString getMediaType(bool _bOasis); + + /** fills the oasis flag only when a filtername was set + * + * \param _rMediaDescriptor + * \param _rOutOASIS + */ + virtual void isOasisFormat(const css::uno::Sequence< css::beans::PropertyValue >& _rMediaDescriptor, bool & _rOutOASIS ); + +private: + // methods + + /// @return a warning code, or 0 for successful operation + ErrCode impl_Import( const css::uno::Reference< css::lang::XComponent > & xDocumentComp, + const css::uno::Sequence< css::beans::PropertyValue > & aMediaDescriptor ); + /// @return a warning code, or 0 for successful operation + ErrCode impl_ImportStream( + const OUString & rStreamName, + const OUString & rServiceName, + const css::uno::Reference< css::embed::XStorage > & xStorage, + const css::uno::Reference< css::lang::XMultiComponentFactory > & xFactory, + const css::uno::Reference & xGraphicStorageHandler, + css::uno::Reference< css::beans::XPropertySet > const & xPropSet ); + + /// @return a warning code, or 0 for successful operation + ErrCode impl_Export( const css::uno::Reference< css::lang::XComponent > & xDocumentComp, + const css::uno::Sequence< css::beans::PropertyValue > & aMediaDescriptor ); + /// @return a warning code, or 0 for successful operation + ErrCode impl_ExportStream( + const OUString & rStreamName, + const OUString & rServiceName, + const css::uno::Reference< css::embed::XStorage > & xStorage, + const css::uno::Reference< css::xml::sax::XWriter >& xActiveDataSource, + const css::uno::Reference< css::lang::XMultiServiceFactory > & xFactory, + const css::uno::Sequence< css::uno::Any > & rFilterProperties ); + + // members + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::lang::XComponent > m_xTargetDoc; + css::uno::Reference< css::lang::XComponent > m_xSourceDoc; + + css::uno::Sequence m_aMediaDescriptor; + + OUString m_sDocumentHandler; // when set it will be set as doc handler + + volatile bool m_bCancelOperation; + ::osl::Mutex m_aMutex; +}; + +class XMLReportFilterHelper final : public XMLFilter +{ + virtual void isOasisFormat(const css::uno::Sequence< css::beans::PropertyValue >& _rMediaDescriptor, + bool & _rOutOASIS ) override; +public: + explicit XMLReportFilterHelper( css::uno::Reference< css::uno::XComponentContext > const & _xContext ) + :XMLFilter(_xContext) + {} +protected: + virtual OUString SAL_CALL + getImplementationName() override + { + return "com.sun.star.comp.chart2.report.XMLFilter"; + } + // ____ XImporter ____ + virtual void SAL_CALL setTargetDocument( + const css::uno::Reference< css::lang::XComponent >& Document ) override + { + setDocumentHandler( "com.sun.star.comp.report.ImportDocumentHandler" ); + XMLFilter::setTargetDocument(Document); + } + + // ____ XExporter ____ + virtual void SAL_CALL setSourceDocument( + const css::uno::Reference< css::lang::XComponent >& Document ) override + { + setDocumentHandler( "com.sun.star.comp.report.ExportDocumentHandler" ); + XMLFilter::setSourceDocument(Document); + } + + virtual OUString getMediaType(bool _bOasis) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Axis.cxx b/chart2/source/model/main/Axis.cxx new file mode 100644 index 000000000..9507f3719 --- /dev/null +++ b/chart2/source/model/main/Axis.cxx @@ -0,0 +1,615 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "GridProperties.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_AXIS_SHOW, + PROP_AXIS_CROSSOVER_POSITION, + PROP_AXIS_CROSSOVER_VALUE, + PROP_AXIS_DISPLAY_LABELS, + PROP_AXIS_NUMBERFORMAT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_AXIS_LABEL_POSITION, + PROP_AXIS_TEXT_ROTATION, + PROP_AXIS_TEXT_BREAK, + PROP_AXIS_TEXT_OVERLAP, + PROP_AXIS_TEXT_STACKED, + PROP_AXIS_TEXT_ARRANGE_ORDER, + PROP_AXIS_REFERENCE_DIAGRAM_SIZE, + + PROP_AXIS_MAJOR_TICKMARKS, + PROP_AXIS_MINOR_TICKMARKS, + PROP_AXIS_MARK_POSITION, + + PROP_AXIS_DISPLAY_UNITS, + PROP_AXIS_BUILTINUNIT, + + PROP_AXIS_TRY_STAGGERING_FIRST, + PROP_AXIS_MAJOR_ORIGIN +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Show", + PROP_AXIS_SHOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverPosition", + PROP_AXIS_CROSSOVER_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CrossoverValue", + PROP_AXIS_CROSSOVER_VALUE, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "DisplayLabels", + PROP_AXIS_DISPLAY_LABELS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_AXIS_NUMBERFORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LabelPosition", + PROP_AXIS_LABEL_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextRotation", + PROP_AXIS_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextBreak", + PROP_AXIS_TEXT_BREAK, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextOverlap", + PROP_AXIS_TEXT_OVERLAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StackCharacters", + PROP_AXIS_TEXT_STACKED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ArrangeOrder", + PROP_AXIS_TEXT_ARRANGE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_AXIS_REFERENCE_DIAGRAM_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "MajorTickmarks", + PROP_AXIS_MAJOR_TICKMARKS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MinorTickmarks", + PROP_AXIS_MINOR_TICKMARKS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MarkPosition", + PROP_AXIS_MARK_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for display units: + rOutProperties.emplace_back( "DisplayUnits", + PROP_AXIS_DISPLAY_UNITS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //Properties for labels: + rOutProperties.emplace_back( "BuiltInUnit", + PROP_AXIS_BUILTINUNIT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + rOutProperties.emplace_back( "TryStaggeringFirst", + PROP_AXIS_TRY_STAGGERING_FIRST, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MajorOrigin", + PROP_AXIS_MAJOR_ORIGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + +} + +struct StaticAxisDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::CharacterProperties::AddDefaultsToMap( rOutMap ); + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_SHOW, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_CROSSOVER_POSITION, css::chart::ChartAxisPosition_ZERO ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_DISPLAY_LABELS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_LINK_NUMBERFORMAT_TO_SOURCE, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_LABEL_POSITION, css::chart::ChartAxisLabelPosition_NEAR_AXIS ); + ::chart::PropertyHelper::setPropertyValueDefault< double >( rOutMap, PROP_AXIS_TEXT_ROTATION, 0.0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_TEXT_BREAK, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_TEXT_OVERLAP, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_TEXT_STACKED, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_TEXT_ARRANGE_ORDER, css::chart::ChartAxisArrangeOrderType_AUTO ); + + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_AXIS_MAJOR_TICKMARKS, 2 /* CHAXIS_MARK_OUTER */ ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_AXIS_MINOR_TICKMARKS, 0 /* CHAXIS_MARK_NONE */ ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_MARK_POSITION, css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_DISPLAY_UNITS, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_AXIS_TRY_STAGGERING_FIRST, false ); + } +}; + +struct StaticAxisDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticAxisDefaults_Initializer > +{ +}; + +struct StaticAxisInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticAxisInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticAxisInfoHelper_Initializer > +{ +}; + +struct StaticAxisInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticAxisInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticAxisInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticAxisInfo_Initializer > +{ +}; + +typedef uno::Reference< beans::XPropertySet > lcl_tSubGridType; + +void lcl_CloneSubGrids( + const uno::Sequence< lcl_tSubGridType > & rSource, uno::Sequence< lcl_tSubGridType > & rDestination ) +{ + rDestination.realloc( rSource.getLength()); + lcl_tSubGridType * pDestBegin = rDestination.getArray(); + lcl_tSubGridType * pDestEnd = pDestBegin + rDestination.getLength(); + lcl_tSubGridType * pDestIt = pDestBegin; + + for( Reference< beans::XPropertySet > const & i : rSource ) + { + Reference< beans::XPropertySet > xSubGrid( i ); + if( xSubGrid.is()) + { + Reference< util::XCloneable > xCloneable( xSubGrid, uno::UNO_QUERY ); + if( xCloneable.is()) + xSubGrid.set( xCloneable->createClone(), uno::UNO_QUERY ); + } + + (*pDestIt) = xSubGrid; + OSL_ASSERT( pDestIt != pDestEnd ); + ++pDestIt; + } + OSL_ASSERT( pDestIt == pDestEnd ); +} + +} // anonymous namespace + +namespace chart +{ + +Axis::Axis() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_aScaleData( AxisHelper::createDefaultScale() ), + m_xGrid( new GridProperties() ) +{ + osl_atomic_increment(&m_refCount); + setFastPropertyValue_NoBroadcast( + ::chart::LinePropertiesHelper::PROP_LINE_COLOR, uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + + if( m_xGrid.is()) + ModifyListenerHelper::addListener( m_xGrid, m_xModifyEventForwarder ); + if( m_aScaleData.Categories.is()) + ModifyListenerHelper::addListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + + AllocateSubGrids(); + osl_atomic_decrement(&m_refCount); +} + +Axis::Axis( const Axis & rOther ) : + impl::Axis_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_aScaleData( rOther.m_aScaleData ) +{ + m_xGrid.set( CloneHelper::CreateRefClone< beans::XPropertySet >()( rOther.m_xGrid )); + if( m_xGrid.is()) + ModifyListenerHelper::addListener( m_xGrid, m_xModifyEventForwarder ); + + if( m_aScaleData.Categories.is()) + ModifyListenerHelper::addListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + + if( rOther.m_aSubGridProperties.hasElements() ) + lcl_CloneSubGrids( rOther.m_aSubGridProperties, m_aSubGridProperties ); + ModifyListenerHelper::addListenerToAllSequenceElements( m_aSubGridProperties, m_xModifyEventForwarder ); + + m_xTitle.set( CloneHelper::CreateRefClone< chart2::XTitle >()( rOther.m_xTitle )); + if( m_xTitle.is()) + ModifyListenerHelper::addListener( m_xTitle, m_xModifyEventForwarder ); +} + +// late initialization to call after copy-constructing +void Axis::Init() +{ + if( m_aScaleData.Categories.is()) + EventListenerHelper::addListener( m_aScaleData.Categories, this ); +} + +Axis::~Axis() +{ + try + { + ModifyListenerHelper::removeListener( m_xGrid, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllSequenceElements( m_aSubGridProperties, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xTitle, m_xModifyEventForwarder ); + if( m_aScaleData.Categories.is()) + { + ModifyListenerHelper::removeListener( m_aScaleData.Categories, m_xModifyEventForwarder ); + m_aScaleData.Categories.set(nullptr); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + m_aSubGridProperties.realloc(0); + m_xGrid = nullptr; + m_xTitle = nullptr; +} + +void Axis::AllocateSubGrids() +{ + Reference< util::XModifyListener > xModifyEventForwarder; + Reference< lang::XEventListener > xEventListener; + std::vector< Reference< beans::XPropertySet > > aOldBroadcasters; + std::vector< Reference< beans::XPropertySet > > aNewBroadcasters; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + xEventListener = this; + + sal_Int32 nNewSubIncCount = m_aScaleData.IncrementData.SubIncrements.getLength(); + sal_Int32 nOldSubIncCount = m_aSubGridProperties.getLength(); + + if( nOldSubIncCount > nNewSubIncCount ) + { + // remove superfluous entries + for( sal_Int32 i = nNewSubIncCount; i < nOldSubIncCount; ++i ) + aOldBroadcasters.push_back( m_aSubGridProperties[ i ] ); + m_aSubGridProperties.realloc( nNewSubIncCount ); + } + else if( nOldSubIncCount < nNewSubIncCount ) + { + m_aSubGridProperties.realloc( nNewSubIncCount ); + auto pSubGridProperties = m_aSubGridProperties.getArray(); + + // allocate new entries + for( sal_Int32 i = nOldSubIncCount; i < nNewSubIncCount; ++i ) + { + pSubGridProperties[ i ] = new GridProperties(); + LinePropertiesHelper::SetLineInvisible( m_aSubGridProperties[ i ] ); + LinePropertiesHelper::SetLineColor( m_aSubGridProperties[ i ], static_cast(0xdddddd) ); //gray2 + aNewBroadcasters.push_back( m_aSubGridProperties[ i ] ); + } + } + } + //don't keep the mutex locked while calling out + for (auto const& oldBroadcaster : aOldBroadcasters) + ModifyListenerHelper::removeListener(oldBroadcaster, xModifyEventForwarder ); + for (auto const& newBroadcaster : aNewBroadcasters) + ModifyListenerHelper::addListener( newBroadcaster, xModifyEventForwarder ); +} + +// ____ XAxis ____ +void SAL_CALL Axis::setScaleData( const chart2::ScaleData& rScaleData ) +{ + Reference< util::XModifyListener > xModifyEventForwarder; + Reference< lang::XEventListener > xEventListener; + Reference< chart2::data::XLabeledDataSequence > xOldCategories; + Reference< chart2::data::XLabeledDataSequence > xNewCategories = rScaleData.Categories; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + xEventListener = this; + xOldCategories = m_aScaleData.Categories; + m_aScaleData = rScaleData; + } + AllocateSubGrids(); + + //don't keep the mutex locked while calling out + if( xOldCategories.is() && xOldCategories != xNewCategories ) + { + ModifyListenerHelper::removeListener( xOldCategories, xModifyEventForwarder ); + EventListenerHelper::removeListener( xOldCategories, xEventListener ); + } + if( xNewCategories.is() && xOldCategories != xNewCategories ) + { + ModifyListenerHelper::addListener( xNewCategories, m_xModifyEventForwarder ); + EventListenerHelper::addListener( xNewCategories, xEventListener ); + } + fireModifyEvent(); +} + +chart2::ScaleData SAL_CALL Axis::getScaleData() +{ + MutexGuard aGuard( m_aMutex ); + return m_aScaleData; +} + +Reference< beans::XPropertySet > SAL_CALL Axis::getGridProperties() +{ + MutexGuard aGuard( m_aMutex ); + return m_xGrid; +} +Sequence< Reference< beans::XPropertySet > > SAL_CALL Axis::getSubGridProperties() +{ + MutexGuard aGuard( m_aMutex ); + return m_aSubGridProperties; +} + +Sequence< Reference< beans::XPropertySet > > SAL_CALL Axis::getSubTickProperties() +{ + OSL_FAIL( "Not implemented yet" ); + return Sequence< Reference< beans::XPropertySet > >(); +} + +// ____ XTitled ____ +Reference< chart2::XTitle > SAL_CALL Axis::getTitleObject() +{ + MutexGuard aGuard( m_aMutex ); + return m_xTitle; +} + +void SAL_CALL Axis::setTitleObject( const Reference< chart2::XTitle >& xNewTitle ) +{ + Reference< util::XModifyListener > xModifyEventForwarder; + Reference< chart2::XTitle > xOldTitle; + { + MutexGuard aGuard( m_aMutex ); + xOldTitle = m_xTitle; + xModifyEventForwarder = m_xModifyEventForwarder; + m_xTitle = xNewTitle; + } + + //don't keep the mutex locked while calling out + if( xOldTitle.is() && xOldTitle != xNewTitle ) + ModifyListenerHelper::removeListener( xOldTitle, xModifyEventForwarder ); + if( xNewTitle.is() && xOldTitle != xNewTitle ) + ModifyListenerHelper::addListener( xNewTitle, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Axis::createClone() +{ + rtl::Reference pNewAxis( new Axis( *this )); + // do initialization that uses uno references to the clone + pNewAxis->Init(); + return pNewAxis; +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Axis::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Axis::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Axis::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Axis::disposing( const lang::EventObject& Source ) +{ + if( Source.Source == m_aScaleData.Categories ) + m_aScaleData.Categories = nullptr; +} + +// ____ OPropertySet ____ +void Axis::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Axis::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Axis::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticAxisDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Axis::getInfoHelper() +{ + return *StaticAxisInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL Axis::getPropertySetInfo() +{ + return *StaticAxisInfo::get(); +} + +using impl::Axis_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Axis, Axis_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Axis, Axis_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Axis::getImplementationName() +{ + return "com.sun.star.comp.chart2.Axis"; +} + +sal_Bool SAL_CALL Axis::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Axis::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Axis", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Axis_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::Axis); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/BaseCoordinateSystem.cxx b/chart2/source/model/main/BaseCoordinateSystem.cxx new file mode 100644 index 000000000..98dc9b4e8 --- /dev/null +++ b/chart2/source/model/main/BaseCoordinateSystem.cxx @@ -0,0 +1,413 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ +enum +{ + PROP_COORDINATESYSTEM_SWAPXANDYAXIS +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "SwapXAndYAxis", + PROP_COORDINATESYSTEM_SWAPXANDYAXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +struct StaticCooSysDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + ::chart::PropertyHelper::setPropertyValueDefault( aStaticDefaults, PROP_COORDINATESYSTEM_SWAPXANDYAXIS, false ); + return &aStaticDefaults; + } +}; + +struct StaticCooSysDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticCooSysDefaults_Initializer > +{ +}; + +struct StaticCooSysInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticCooSysInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticCooSysInfoHelper_Initializer > +{ +}; + +struct StaticCooSysInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticCooSysInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticCooSysInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticCooSysInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +BaseCoordinateSystem::BaseCoordinateSystem( + sal_Int32 nDimensionCount /* = 2 */ ) : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_nDimensionCount( nDimensionCount ) + { + m_aAllAxis.resize( m_nDimensionCount ); + for( sal_Int32 nN=0; nN xAxis( new Axis ); + m_aAllAxis[nN][0] = xAxis; + + ModifyListenerHelper::addListenerToAllElements( m_aAllAxis[nN], m_xModifyEventForwarder ); + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + if(nN==0) + { + aScaleData.AxisType = chart2::AxisType::CATEGORY; + } + else if( nN==1) + { + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + } + else if( nN==2) + { + aScaleData.AxisType = chart2::AxisType::SERIES; + } + xAxis->setScaleData( aScaleData ); + } + + setFastPropertyValue_NoBroadcast( PROP_COORDINATESYSTEM_SWAPXANDYAXIS, uno::Any( false )); +} + +// explicit +BaseCoordinateSystem::BaseCoordinateSystem( + const BaseCoordinateSystem & rSource ) : + impl::BaseCoordinateSystem_Base(rSource), + ::property::OPropertySet( rSource, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_nDimensionCount( rSource.m_nDimensionCount ) +{ + m_aAllAxis.resize(rSource.m_aAllAxis.size()); + tAxisVecVecType::size_type nN=0; + for( nN=0; nNcloneChartType()); + + for( nN=0; nNaddModifyListener( m_xModifyEventForwarder ); +} + +BaseCoordinateSystem::~BaseCoordinateSystem() +{ + try + { + for(const tAxisVecVecType::value_type & i : m_aAllAxis) + ModifyListenerHelper::removeListenerFromAllElements( i, m_xModifyEventForwarder ); + for (const auto & rxChartType : m_aChartTypes) + rxChartType->removeModifyListener( m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +// ____ XCoordinateSystem ____ +sal_Int32 SAL_CALL BaseCoordinateSystem::getDimension() +{ + return m_nDimensionCount; +} + +void SAL_CALL BaseCoordinateSystem::setAxisByDimension( + sal_Int32 nDimensionIndex, + const Reference< chart2::XAxis >& xAxis, + sal_Int32 nIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + if( nIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + assert(!xAxis || dynamic_cast(xAxis.get())); + + if( m_aAllAxis[ nDimensionIndex ].size() < o3tl::make_unsigned( nIndex+1 )) + { + m_aAllAxis[ nDimensionIndex ].resize( nIndex+1 ); + m_aAllAxis[ nDimensionIndex ][nIndex] = nullptr; + } + + rtl::Reference< Axis > xOldAxis( m_aAllAxis[ nDimensionIndex ][nIndex] ); + if( xOldAxis.is()) + ModifyListenerHelper::removeListener( xOldAxis, m_xModifyEventForwarder ); + m_aAllAxis[ nDimensionIndex ][nIndex] = dynamic_cast(xAxis.get()); + if( xAxis.is()) + ModifyListenerHelper::addListener( xAxis, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void BaseCoordinateSystem::setAxisByDimension( + sal_Int32 nDimensionIndex, + const rtl::Reference< Axis >& xAxis, + sal_Int32 nIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + if( nIndex < 0 ) + throw lang::IndexOutOfBoundsException(); + + if( m_aAllAxis[ nDimensionIndex ].size() < o3tl::make_unsigned( nIndex+1 )) + { + m_aAllAxis[ nDimensionIndex ].resize( nIndex+1 ); + m_aAllAxis[ nDimensionIndex ][nIndex] = nullptr; + } + + rtl::Reference< Axis > xOldAxis( m_aAllAxis[ nDimensionIndex ][nIndex] ); + if( xOldAxis.is()) + ModifyListenerHelper::removeListener( xOldAxis, m_xModifyEventForwarder ); + m_aAllAxis[ nDimensionIndex ][nIndex] = xAxis; + if( xAxis.is()) + ModifyListenerHelper::addListener( xAxis, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Reference< chart2::XAxis > SAL_CALL BaseCoordinateSystem::getAxisByDimension( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( getDimension())); + + if( nAxisIndex < 0 || nAxisIndex > getMaximumAxisIndexByDimension(nDimensionIndex) ) + throw lang::IndexOutOfBoundsException(); + + return m_aAllAxis[ nDimensionIndex ][nAxisIndex]; +} + +const rtl::Reference< Axis > & BaseCoordinateSystem::getAxisByDimension2( + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + if( nDimensionIndex < 0 || nDimensionIndex >= m_nDimensionCount ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( m_nDimensionCount)); + + if( nAxisIndex < 0 || o3tl::make_unsigned(nAxisIndex) > m_aAllAxis[ nDimensionIndex ].size() ) + throw lang::IndexOutOfBoundsException(); + + return m_aAllAxis[ nDimensionIndex ][nAxisIndex]; +} + +sal_Int32 SAL_CALL BaseCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) +{ + if( nDimensionIndex < 0 || nDimensionIndex >= getDimension() ) + throw lang::IndexOutOfBoundsException(); + + OSL_ASSERT( m_aAllAxis.size() == static_cast< size_t >( getDimension())); + + sal_Int32 nRet = m_aAllAxis[ nDimensionIndex ].size(); + if(nRet) + nRet-=1; + + return nRet; +} + +// ____ XChartTypeContainer ____ +void SAL_CALL BaseCoordinateSystem::addChartType( const Reference< chart2::XChartType >& aChartType ) +{ + auto pChartType = dynamic_cast(aChartType.get()); + assert(pChartType); + + if( std::find( m_aChartTypes.begin(), m_aChartTypes.end(), pChartType ) + != m_aChartTypes.end()) + throw lang::IllegalArgumentException("type not found", static_cast(this), 1); + + m_aChartTypes.push_back( pChartType ); + ModifyListenerHelper::addListener( aChartType, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL BaseCoordinateSystem::removeChartType( const Reference< chart2::XChartType >& aChartType ) +{ + auto pChartType = dynamic_cast(aChartType.get()); + assert(pChartType); + auto aIt( std::find( m_aChartTypes.begin(), m_aChartTypes.end(), pChartType )); + if( aIt == m_aChartTypes.end()) + throw container::NoSuchElementException( + "The given chart type is no element of the container", + static_cast< uno::XWeak * >( this )); + + m_aChartTypes.erase( aIt ); + ModifyListenerHelper::removeListener( aChartType, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Sequence< Reference< chart2::XChartType > > SAL_CALL BaseCoordinateSystem::getChartTypes() +{ + return comphelper::containerToSequence< Reference< chart2::XChartType > >( m_aChartTypes ); +} + +void SAL_CALL BaseCoordinateSystem::setChartTypes( const Sequence< Reference< chart2::XChartType > >& aChartTypes ) +{ + for (auto const & aChartType : m_aChartTypes) + aChartType->removeModifyListener( m_xModifyEventForwarder ); + m_aChartTypes.clear(); + for (auto const & aChartType : aChartTypes) + { + auto pChartType = dynamic_cast(aChartType.get()); + assert(pChartType); + m_aChartTypes.push_back(pChartType); + pChartType->addModifyListener( m_xModifyEventForwarder ); + } + fireModifyEvent(); +} + +void BaseCoordinateSystem::setChartTypes( const std::vector< rtl::Reference< ChartType > >& aChartTypes ) +{ + for (auto const & aChartType : m_aChartTypes) + aChartType->removeModifyListener( m_xModifyEventForwarder ); + m_aChartTypes = aChartTypes; + for (auto const & aChartType : m_aChartTypes) + aChartType->addModifyListener( m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL BaseCoordinateSystem::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL BaseCoordinateSystem::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL BaseCoordinateSystem::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL BaseCoordinateSystem::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void BaseCoordinateSystem::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void BaseCoordinateSystem::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void BaseCoordinateSystem::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticCooSysDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL BaseCoordinateSystem::getInfoHelper() +{ + return *StaticCooSysInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL BaseCoordinateSystem::getPropertySetInfo() +{ + return *StaticCooSysInfo::get(); +} + +using impl::BaseCoordinateSystem_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( BaseCoordinateSystem, BaseCoordinateSystem_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( BaseCoordinateSystem, BaseCoordinateSystem_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/CartesianCoordinateSystem.cxx b/chart2/source/model/main/CartesianCoordinateSystem.cxx new file mode 100644 index 000000000..c65adee25 --- /dev/null +++ b/chart2/source/model/main/CartesianCoordinateSystem.cxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace com::sun::star::uno { class XComponentContext; } + +namespace +{ + +constexpr OUStringLiteral CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME = u"com.sun.star.chart2.CoordinateSystems.Cartesian"; + +} + +namespace chart +{ + +// explicit +CartesianCoordinateSystem::CartesianCoordinateSystem( + sal_Int32 nDimensionCount /* = 2 */ ) : + BaseCoordinateSystem( nDimensionCount ) +{} + +CartesianCoordinateSystem::CartesianCoordinateSystem( + const CartesianCoordinateSystem & rSource ) : + BaseCoordinateSystem( rSource ) +{} + +CartesianCoordinateSystem::~CartesianCoordinateSystem() +{} + +// ____ XCoordinateSystem ____ +OUString SAL_CALL CartesianCoordinateSystem::getCoordinateSystemType() +{ + return CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME; +} + +OUString SAL_CALL CartesianCoordinateSystem::getViewServiceName() +{ + return CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME; +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL CartesianCoordinateSystem::createClone() +{ + return Reference< util::XCloneable >( new CartesianCoordinateSystem( *this )); +} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem::getImplementationName() +{ + return "com.sun.star.comp.chart.CartesianCoordinateSystem"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem::getSupportedServiceNames() +{ + return { CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME }; +} + +// ==== CartesianCoordinateSystem2d ==== + +CartesianCoordinateSystem2d::CartesianCoordinateSystem2d() : + CartesianCoordinateSystem( 2 ) +{} + +CartesianCoordinateSystem2d::~CartesianCoordinateSystem2d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem2d::getImplementationName() +{ + return "com.sun.star.comp.chart2.CartesianCoordinateSystem2d"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem2d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem2d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME, + "com.sun.star.chart2.CartesianCoordinateSystem2d" + }; +} + +// ==== CartesianCoordinateSystem3d ==== + +CartesianCoordinateSystem3d::CartesianCoordinateSystem3d() : + CartesianCoordinateSystem( 3 ) +{} + +CartesianCoordinateSystem3d::~CartesianCoordinateSystem3d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL CartesianCoordinateSystem3d::getImplementationName() +{ + return "com.sun.star.comp.chart2.CartesianCoordinateSystem3d"; +} + +sal_Bool SAL_CALL CartesianCoordinateSystem3d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CartesianCoordinateSystem3d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_CARTESIAN_SERVICE_NAME, + "com.sun.star.chart2.CartesianCoordinateSystem3d" + }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_CartesianCoordinateSystem2d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::CartesianCoordinateSystem2d); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_CartesianCoordinateSystem3d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::CartesianCoordinateSystem3d); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/ChartModel.cxx b/chart2/source/model/main/ChartModel.cxx new file mode 100644 index 000000000..712be3fdf --- /dev/null +++ b/chart2/source/model/main/ChartModel.cxx @@ -0,0 +1,1306 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "PageBackground.hxx" +#include +#include +#include "UndoManager.hxx" +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +using namespace ::com::sun::star; +using namespace ::apphelper; +using namespace ::chart::CloneHelper; + +namespace +{ +constexpr OUStringLiteral lcl_aGDIMetaFileMIMEType( + u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""); +constexpr OUStringLiteral lcl_aGDIMetaFileMIMETypeHighContrast( + u"application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\""); + +} // anonymous namespace + +// ChartModel Constructor and Destructor + +namespace chart +{ + +ChartModel::ChartModel(uno::Reference const & xContext) + : m_aLifeTimeManager( this, this ) + , m_bReadOnly( false ) + , m_bModified( false ) + , m_nInLoad(0) + , m_bUpdateNotificationsPending(false) + , mbTimeBased(false) + , m_aControllers( m_aModelMutex ) + , m_nControllerLockCount(0) + , m_xContext( xContext ) + , m_aVisualAreaSize( ChartModelHelper::getDefaultPageSize() ) + , m_xPageBackground( new PageBackground ) + , m_xXMLNamespaceMap( new NameContainer() ) + , mnStart(0) + , mnEnd(0) +{ + osl_atomic_increment(&m_refCount); + { + m_xOldModelAgg.set( + m_xContext->getServiceManager()->createInstanceWithContext( + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + m_xContext ), uno::UNO_QUERY_THROW ); + m_xOldModelAgg->setDelegator( *this ); + } + + { + m_xPageBackground->addModifyListener( this ); + m_xChartTypeManager = new ::chart::ChartTypeManager( m_xContext ); + } + osl_atomic_decrement(&m_refCount); +} + +ChartModel::ChartModel( const ChartModel & rOther ) + : impl::ChartModel_Base(rOther) + , m_aLifeTimeManager( this, this ) + , m_bReadOnly( rOther.m_bReadOnly ) + , m_bModified( rOther.m_bModified ) + , m_nInLoad(0) + , m_bUpdateNotificationsPending(false) + , mbTimeBased(rOther.mbTimeBased) + , m_aResource( rOther.m_aResource ) + , m_aMediaDescriptor( rOther.m_aMediaDescriptor ) + , m_aControllers( m_aModelMutex ) + , m_nControllerLockCount(0) + , m_xContext( rOther.m_xContext ) + // @note: the old model aggregate must not be shared with other models if it + // is, you get mutex deadlocks + //, m_xOldModelAgg( nullptr ) //rOther.m_xOldModelAgg ) + // m_xStorage( nullptr ) //rOther.m_xStorage ) + , m_aVisualAreaSize( rOther.m_aVisualAreaSize ) + , m_aGraphicObjectVector( rOther.m_aGraphicObjectVector ) + , m_xDataProvider( rOther.m_xDataProvider ) + , m_xInternalDataProvider( rOther.m_xInternalDataProvider ) + , mnStart(rOther.mnStart) + , mnEnd(rOther.mnEnd) +{ + osl_atomic_increment(&m_refCount); + { + m_xOldModelAgg.set( + m_xContext->getServiceManager()->createInstanceWithContext( + CHART_CHARTAPIWRAPPER_SERVICE_NAME, + m_xContext ), uno::UNO_QUERY_THROW ); + m_xOldModelAgg->setDelegator( *this ); + + Reference< util::XModifyListener > xListener; + Reference< chart2::XTitle > xNewTitle = CreateRefClone< chart2::XTitle >()( rOther.m_xTitle ); + rtl::Reference< ::chart::Diagram > xNewDiagram; + if (rOther.m_xDiagram.is()) + xNewDiagram = new ::chart::Diagram( *rOther.m_xDiagram ); + rtl::Reference< ::chart::PageBackground > xNewPageBackground = new PageBackground( *rOther.m_xPageBackground ); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager; // does not implement XCloneable + rtl::Reference< ::chart::NameContainer > xXMLNamespaceMap = new NameContainer( *rOther.m_xXMLNamespaceMap ); + + { + MutexGuard aGuard( m_aModelMutex ); + xListener = this; + m_xTitle = xNewTitle; + m_xDiagram = xNewDiagram; + m_xPageBackground = xNewPageBackground; + m_xChartTypeManager = xChartTypeManager; + m_xXMLNamespaceMap = xXMLNamespaceMap; + } + + ModifyListenerHelper::addListener( xNewTitle, xListener ); + if( xNewDiagram && xListener) + xNewDiagram->addModifyListener( xListener ); + if( xNewPageBackground && xListener) + xNewPageBackground->addModifyListener( xListener ); + xListener.clear(); + } + osl_atomic_decrement(&m_refCount); +} + +ChartModel::~ChartModel() +{ + if( m_xOldModelAgg.is()) + m_xOldModelAgg->setDelegator( nullptr ); +} + +void SAL_CALL ChartModel::initialize( const Sequence< Any >& /*rArguments*/ ) +{ + //#i113722# avoid duplicate creation + + //maybe additional todo?: + //support argument "EmbeddedObject"? + //support argument "EmbeddedScriptSupport"? + //support argument "DocumentRecoverySupport"? +} + +ChartView* ChartModel::getChartView() const +{ + return mxChartView.get(); +} + +// private methods + +OUString ChartModel::impl_g_getLocation() +{ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return OUString(); //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + return m_aResource; +} + +bool ChartModel::impl_isControllerConnected( const uno::Reference< frame::XController >& xController ) +{ + try + { + std::vector< uno::Reference > aSeq = m_aControllers.getElements(); + for( const auto & r : aSeq ) + { + if( r == xController ) + return true; + } + } + catch (const uno::Exception&) + { + } + return false; +} + +uno::Reference< frame::XController > ChartModel::impl_getCurrentController() +{ + //@todo? hold only weak references to controllers + + // get the last active controller of this model + if( m_xCurrentController.is() ) + return m_xCurrentController; + + // get the first controller of this model + if( m_aControllers.getLength() ) + { + uno::Reference xI = m_aControllers.getInterface(0); + return uno::Reference( xI, uno::UNO_QUERY ); + } + + //return nothing if no controllers are connected at all + return uno::Reference< frame::XController > (); +} + +void ChartModel::impl_notifyCloseListeners() +{ + ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer + .getContainer( cppu::UnoType::get()); + if( pIC ) + { + lang::EventObject aEvent( static_cast< lang::XComponent*>(this) ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< util::XCloseListener* >( aIt.next() )->notifyClosing( aEvent ); + } + } +} + +void ChartModel::impl_adjustAdditionalShapesPositionAndSize( const awt::Size& aVisualAreaSize ) +{ + uno::Reference< beans::XPropertySet > xProperties( static_cast< ::cppu::OWeakObject* >( this ), uno::UNO_QUERY ); + if ( !xProperties.is() ) + return; + + uno::Reference< drawing::XShapes > xShapes; + xProperties->getPropertyValue( "AdditionalShapes" ) >>= xShapes; + if ( !xShapes.is() ) + return; + + sal_Int32 nCount = xShapes->getCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< drawing::XShape > xShape; + if ( xShapes->getByIndex( i ) >>= xShape ) + { + if ( xShape.is() ) + { + awt::Point aPos( xShape->getPosition() ); + awt::Size aSize( xShape->getSize() ); + + double fWidth = static_cast< double >( aVisualAreaSize.Width ) / m_aVisualAreaSize.Width; + double fHeight = static_cast< double >( aVisualAreaSize.Height ) / m_aVisualAreaSize.Height; + + aPos.X = static_cast< tools::Long >( aPos.X * fWidth ); + aPos.Y = static_cast< tools::Long >( aPos.Y * fHeight ); + aSize.Width = static_cast< tools::Long >( aSize.Width * fWidth ); + aSize.Height = static_cast< tools::Long >( aSize.Height * fHeight ); + + xShape->setPosition( aPos ); + xShape->setSize( aSize ); + } + } + } +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartModel::getImplementationName() +{ + return CHART_MODEL_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartModel::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartModel::getSupportedServiceNames() +{ + return { + CHART_MODEL_SERVICE_NAME, + "com.sun.star.document.OfficeDocument", + "com.sun.star.chart.ChartDocument" + }; +} + +// frame::XModel (required interface) + +sal_Bool SAL_CALL ChartModel::attachResource( const OUString& rURL + , const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + /* + The method attachResource() is used by the frame loader implementations + to inform the model about its URL and MediaDescriptor. + */ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return false; //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + + if(!m_aResource.isEmpty())//we have a resource already //@todo? or is setting a new resource allowed? + return false; + m_aResource = rURL; + m_aMediaDescriptor = rMediaDescriptor; + + //@todo ? check rURL ?? + //@todo ? evaluate m_aMediaDescriptor; + //@todo ? ... ??? --> nothing, this method is only for setting information + + return true; +} + +OUString SAL_CALL ChartModel::getURL() +{ + return impl_g_getLocation(); +} + +uno::Sequence< beans::PropertyValue > SAL_CALL ChartModel::getArgs() +{ + /* + The method getArgs() returns a sequence of property values + that report the resource description according to com.sun.star.document.MediaDescriptor, + specified on loading or saving with storeAsURL. + */ + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return uno::Sequence< beans::PropertyValue >(); //behave passive if already disposed or closed or throw exception @todo? + //mutex is acquired + + return m_aMediaDescriptor; +} + +void SAL_CALL ChartModel::connectController( const uno::Reference< frame::XController >& xController ) +{ + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return ; //behave passive if already disposed or closed + //mutex is acquired + + //--add controller + m_aControllers.addInterface(xController); +} + +void SAL_CALL ChartModel::disconnectController( const uno::Reference< frame::XController >& xController ) +{ + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed + + //--remove controller + m_aControllers.removeInterface(xController); + + //case: current controller is disconnected: + if( m_xCurrentController == xController ) + m_xCurrentController.clear(); + + DisposeHelper::DisposeAndClear( m_xRangeHighlighter ); + DisposeHelper::DisposeAndClear(m_xPopupRequest); +} + +void SAL_CALL ChartModel::lockControllers() +{ + /* + suspends some notifications to the controllers which are used for display updates. + + The calls to lockControllers() and unlockControllers() may be nested + and even overlapping, but they must be in pairs. While there is at least one lock + remaining, some notifications for display updates are not broadcasted. + */ + + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed or throw exception @todo? + ++m_nControllerLockCount; +} + +void SAL_CALL ChartModel::unlockControllers() +{ + /* + resumes the notifications which were suspended by lockControllers() . + + The calls to lockControllers() and unlockControllers() may be nested + and even overlapping, but they must be in pairs. While there is at least one lock + remaining, some notifications for display updates are not broadcasted. + */ + + //@todo? this method is declared as oneway -> ...? + + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return; //behave passive if already disposed or closed or throw exception @todo? + if( m_nControllerLockCount == 0 ) + { + SAL_WARN("chart2", "ChartModel: unlockControllers called with m_nControllerLockCount == 0" ); + return; + } + --m_nControllerLockCount; + if( m_nControllerLockCount == 0 && m_bUpdateNotificationsPending ) + { + aGuard.clear(); + impl_notifyModifiedListeners(); + } +} + +sal_Bool SAL_CALL ChartModel::hasControllersLocked() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + return false; //behave passive if already disposed or closed or throw exception @todo? + return ( m_nControllerLockCount != 0 ) ; +} + +uno::Reference< frame::XController > SAL_CALL ChartModel::getCurrentController() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "getCurrentController was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + return impl_getCurrentController(); +} + +void SAL_CALL ChartModel::setCurrentController( const uno::Reference< frame::XController >& xController ) +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "setCurrentController was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + //OSL_ENSURE( impl_isControllerConnected(xController), "setCurrentController is called with a Controller which is not connected" ); + if(!impl_isControllerConnected(xController)) + throw container::NoSuchElementException( + "setCurrentController is called with a Controller which is not connected", + static_cast< ::cppu::OWeakObject* >(this) ); + + m_xCurrentController = xController; + + DisposeHelper::DisposeAndClear( m_xRangeHighlighter ); + DisposeHelper::DisposeAndClear(m_xPopupRequest); +} + +uno::Reference< uno::XInterface > SAL_CALL ChartModel::getCurrentSelection() +{ + LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall()) + throw lang::DisposedException( + "getCurrentSelection was called on an already disposed or closed model", + static_cast< ::cppu::OWeakObject* >(this) ); + + uno::Reference< uno::XInterface > xReturn; + uno::Reference< frame::XController > xController = impl_getCurrentController(); + + aGuard.clear(); + if( xController.is() ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupl( xController, uno::UNO_QUERY ); + if ( xSelectionSupl.is() ) + { + uno::Any aSel = xSelectionSupl->getSelection(); + OUString aObjectCID; + if( aSel >>= aObjectCID ) + xReturn.set( ObjectIdentifier::getObjectPropertySet( aObjectCID, this)); + } + } + return xReturn; +} + +// lang::XComponent (base of XModel) +void SAL_CALL ChartModel::dispose() +{ + Reference< XInterface > xKeepAlive( *this ); + + //This object should release all resources and references in the + //easiest possible manner + //This object must notify all registered listeners using the method + //XEventListener::disposing + + //hold no mutex + if( !m_aLifeTimeManager.dispose() ) + return; + + //--release all resources and references + //// @todo + + if ( m_xDiagram.is() ) + m_xDiagram->removeModifyListener( this ); + + if ( m_xDataProvider.is() ) + { + Reference xModifyBroadcaster( m_xDataProvider, uno::UNO_QUERY ); + if ( xModifyBroadcaster.is() ) + xModifyBroadcaster->removeModifyListener( this ); + } + + m_xDataProvider.clear(); + m_xInternalDataProvider.clear(); + m_xNumberFormatsSupplier.clear(); + m_xOwnNumberFormatsSupplier.clear(); + m_xChartTypeManager.clear(); + m_xDiagram.clear(); + DisposeHelper::DisposeAndClear( m_xTitle ); + m_xPageBackground.clear(); + m_xXMLNamespaceMap.clear(); + + m_xStorage.clear(); + // just clear, don't dispose - we're not the owner + + if ( m_pUndoManager.is() ) + m_pUndoManager->disposing(); + m_pUndoManager.clear(); + // that's important, since the UndoManager implementation delegates its ref counting to ourself. + + if( m_xOldModelAgg.is()) // #i120828#, to release cyclic reference to ChartModel object + m_xOldModelAgg->setDelegator( nullptr ); + + m_aControllers.disposeAndClear( lang::EventObject( static_cast< cppu::OWeakObject * >( this ))); + m_xCurrentController.clear(); + + DisposeHelper::DisposeAndClear( m_xRangeHighlighter ); + DisposeHelper::DisposeAndClear(m_xPopupRequest); + + if( m_xOldModelAgg.is()) + m_xOldModelAgg->setDelegator( nullptr ); +} + +void SAL_CALL ChartModel::addEventListener( const uno::Reference< lang::XEventListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.addInterface( cppu::UnoType::get(), xListener ); +} + +void SAL_CALL ChartModel::removeEventListener( const uno::Reference< lang::XEventListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType::get(), xListener ); +} + +// util::XCloseBroadcaster (base of XCloseable) +void SAL_CALL ChartModel::addCloseListener( const uno::Reference< util::XCloseListener > & xListener ) +{ + m_aLifeTimeManager.g_addCloseListener( xListener ); +} + +void SAL_CALL ChartModel::removeCloseListener( const uno::Reference< util::XCloseListener > & xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.removeInterface( cppu::UnoType::get(), xListener ); +} + +// util::XCloseable +void SAL_CALL ChartModel::close( sal_Bool bDeliverOwnership ) +{ + //hold no mutex + + if( !m_aLifeTimeManager.g_close_startTryClose( bDeliverOwnership ) ) + return; + //no mutex is acquired + + // At the end of this method may we must dispose ourself ... + // and may nobody from outside hold a reference to us ... + // then it's a good idea to do that by ourself. + uno::Reference< uno::XInterface > xSelfHold( static_cast< ::cppu::OWeakObject* >(this) ); + + //the listeners have had no veto + //check whether we self can close + { + util::CloseVetoException aVetoException( + "the model itself could not be closed", + static_cast< ::cppu::OWeakObject* >(this) ); + + m_aLifeTimeManager.g_close_isNeedToCancelLongLastingCalls( bDeliverOwnership, aVetoException ); + } + m_aLifeTimeManager.g_close_endTryClose_doClose(); + + // BM @todo: is it ok to call the listeners here? + impl_notifyCloseListeners(); +} + +// lang::XTypeProvider +uno::Sequence< uno::Type > SAL_CALL ChartModel::getTypes() +{ + uno::Reference< lang::XTypeProvider > xAggTypeProvider; + if( (m_xOldModelAgg->queryAggregation( cppu::UnoType::get()) >>= xAggTypeProvider) + && xAggTypeProvider.is()) + { + return comphelper::concatSequences( + impl::ChartModel_Base::getTypes(), + xAggTypeProvider->getTypes()); + } + + return impl::ChartModel_Base::getTypes(); +} + +// document::XDocumentPropertiesSupplier +uno::Reference< document::XDocumentProperties > SAL_CALL + ChartModel::getDocumentProperties() +{ + ::osl::MutexGuard aGuard( m_aModelMutex ); + if ( !m_xDocumentProperties.is() ) + { + m_xDocumentProperties.set( document::DocumentProperties::create( ::comphelper::getProcessComponentContext() ) ); + } + return m_xDocumentProperties; +} + +// document::XDocumentPropertiesSupplier +Reference< document::XUndoManager > SAL_CALL ChartModel::getUndoManager( ) +{ + ::osl::MutexGuard aGuard( m_aModelMutex ); + if ( !m_pUndoManager.is() ) + m_pUndoManager.set( new UndoManager( *this, m_aModelMutex ) ); + return m_pUndoManager; +} + +// chart2::XChartDocument + +uno::Reference< chart2::XDiagram > SAL_CALL ChartModel::getFirstDiagram() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xDiagram; +} + +void SAL_CALL ChartModel::setFirstDiagram( const uno::Reference< chart2::XDiagram >& xDiagram ) +{ + rtl::Reference< ::chart::Diagram > xOldDiagram; + Reference< util::XModifyListener > xListener; + { + MutexGuard aGuard( m_aModelMutex ); + if( xDiagram.get() == m_xDiagram.get() ) + return; + xOldDiagram = m_xDiagram; + assert(!xDiagram || dynamic_cast<::chart::Diagram*>(xDiagram.get())); + m_xDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get()); + xListener = this; + } + //don't keep the mutex locked while calling out + if( xOldDiagram && xListener ) + xOldDiagram->removeModifyListener( xListener ); + ModifyListenerHelper::addListener( xDiagram, xListener ); + setModified( true ); +} + +Reference< chart2::data::XDataSource > ChartModel::impl_createDefaultData() +{ + Reference< chart2::data::XDataSource > xDataSource; + if( hasInternalDataProvider() ) + { + //init internal dataprovider + { + beans::NamedValue aParam( "CreateDefaultData" ,uno::Any(true) ); + uno::Sequence< uno::Any > aArgs{ uno::Any(aParam) }; + m_xInternalDataProvider->initialize(aArgs); + } + //create data + uno::Sequence aArgs( comphelper::InitPropertySequence({ + { "CellRangeRepresentation", uno::Any( OUString("all") ) }, + { "HasCategories", uno::Any( true ) }, + { "FirstCellAsLabel", uno::Any( true ) }, + { "DataRowSource", uno::Any( css::chart::ChartDataRowSource_COLUMNS ) } + })); + xDataSource = m_xInternalDataProvider->createDataSource( aArgs ); + } + return xDataSource; +} + +void SAL_CALL ChartModel::createInternalDataProvider( sal_Bool bCloneExistingData ) +{ + // don't lock the mutex, because this call calls out to code that tries to + // lock the solar mutex. On the other hand, a paint locks the solar mutex + // and calls to the model lock the model's mutex => deadlock + // @todo: lock a separate mutex in the InternalData class + if( !hasInternalDataProvider() ) + { + if( bCloneExistingData ) + m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( this, true ); + else + m_xInternalDataProvider = ChartModelHelper::createInternalDataProvider( nullptr, true ); + m_xDataProvider.set( m_xInternalDataProvider ); + } + setModified( true ); +} + +void ChartModel::removeDataProviders() +{ + if (m_xInternalDataProvider.is()) + m_xInternalDataProvider.clear(); + if (m_xDataProvider.is()) + m_xDataProvider.clear(); +} + +void ChartModel::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartModel")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + if (mxChartView.is()) + { + mxChartView->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +sal_Bool SAL_CALL ChartModel::hasInternalDataProvider() +{ + return m_xDataProvider.is() && m_xInternalDataProvider.is(); +} + +uno::Reference< chart2::data::XDataProvider > SAL_CALL ChartModel::getDataProvider() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xDataProvider; +} + +// ____ XDataReceiver ____ + +void SAL_CALL ChartModel::attachDataProvider( const uno::Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + uno::Reference< beans::XPropertySet > xProp( xDataProvider, uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + bool bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( this ); + xProp->setPropertyValue("IncludeHiddenCells", uno::Any(bIncludeHiddenCells)); + } + catch (const beans::UnknownPropertyException&) + { + } + } + + uno::Reference xModifyBroadcaster(xDataProvider, uno::UNO_QUERY); + if (xModifyBroadcaster.is()) + { + xModifyBroadcaster->addModifyListener(this); + } + + m_xDataProvider.set( xDataProvider ); + m_xInternalDataProvider.clear(); + + //the numberformatter is kept independent of the data provider! + } + setModified( true ); +} + +void SAL_CALL ChartModel::attachNumberFormatsSupplier( const uno::Reference< util::XNumberFormatsSupplier >& xNewSupplier ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( xNewSupplier == m_xNumberFormatsSupplier ) + return; + if( xNewSupplier == uno::Reference(m_xOwnNumberFormatsSupplier) ) + return; + if( m_xOwnNumberFormatsSupplier.is() && xNewSupplier.is() ) + { + //@todo + //merge missing numberformats from own to new formatter + } + else if( !xNewSupplier.is() ) + { + if( m_xNumberFormatsSupplier.is() ) + { + //@todo + //merge missing numberformats from old numberformatter to own numberformatter + //create own numberformatter if necessary + } + } + + m_xNumberFormatsSupplier.set( xNewSupplier ); + m_xOwnNumberFormatsSupplier.clear(); + } + setModified( true ); +} + +void SAL_CALL ChartModel::setArguments( const Sequence< beans::PropertyValue >& aArguments ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( !m_xDataProvider.is() ) + return; + lockControllers(); + + try + { + Reference< chart2::data::XDataSource > xDataSource( m_xDataProvider->createDataSource( aArguments ) ); + if( xDataSource.is() ) + { + rtl::Reference< Diagram > xDia = getFirstChartDiagram(); + if( !xDia.is() ) + { + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() ); + if( xTemplate.is()) + setFirstDiagram( xTemplate->createDiagramByDataSource( xDataSource, aArguments ) ); + } + else + xDia->setDiagramData( xDataSource, aArguments ); + } + } + catch (const lang::IllegalArgumentException&) + { + throw; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + unlockControllers(); + } + setModified( true ); +} + +Sequence< OUString > SAL_CALL ChartModel::getUsedRangeRepresentations() +{ + return DataSourceHelper::getUsedDataRanges( this ); +} + +Reference< chart2::data::XDataSource > SAL_CALL ChartModel::getUsedData() +{ + return DataSourceHelper::getUsedData( *this ); +} + +Reference< chart2::data::XRangeHighlighter > SAL_CALL ChartModel::getRangeHighlighter() +{ + if( ! m_xRangeHighlighter.is()) + m_xRangeHighlighter.set( ChartModelHelper::createRangeHighlighter( this )); + return m_xRangeHighlighter; +} + +Reference SAL_CALL ChartModel::getPopupRequest() +{ + if (!m_xPopupRequest.is()) + m_xPopupRequest.set(new PopupRequest); + return m_xPopupRequest; +} + +rtl::Reference< ::chart::ChartTypeTemplate > ChartModel::impl_createDefaultChartTypeTemplate() +{ + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + if( m_xChartTypeManager.is() ) + xTemplate = m_xChartTypeManager->createTemplate( "com.sun.star.chart2.template.Column" ); + return xTemplate; +} + +void SAL_CALL ChartModel::setChartTypeManager( const uno::Reference< chart2::XChartTypeManager >& xNewManager ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_xChartTypeManager = dynamic_cast<::chart::ChartTypeManager*>(xNewManager.get()); + assert(!xNewManager || m_xChartTypeManager); + } + setModified( true ); +} + +uno::Reference< chart2::XChartTypeManager > SAL_CALL ChartModel::getChartTypeManager() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xChartTypeManager; +} + +uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getPageBackground() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xPageBackground; +} + +void SAL_CALL ChartModel::createDefaultChart() +{ + insertDefaultChart(); +} + +// ____ XTitled ____ +uno::Reference< chart2::XTitle > SAL_CALL ChartModel::getTitleObject() +{ + MutexGuard aGuard( m_aModelMutex ); + return m_xTitle; +} + +void SAL_CALL ChartModel::setTitleObject( const uno::Reference< chart2::XTitle >& xTitle ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + if( m_xTitle.is() ) + ModifyListenerHelper::removeListener( m_xTitle, this ); + m_xTitle = xTitle; + ModifyListenerHelper::addListener( m_xTitle, this ); + } + setModified( true ); +} + +// ____ XInterface (for old API wrapper) ____ +uno::Any SAL_CALL ChartModel::queryInterface( const uno::Type& aType ) +{ + uno::Any aResult( impl::ChartModel_Base::queryInterface( aType )); + + if( ! aResult.hasValue()) + { + // try old API wrapper + try + { + if( m_xOldModelAgg.is()) + aResult = m_xOldModelAgg->queryAggregation( aType ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL ChartModel::createClone() +{ + return Reference< util::XCloneable >( new ChartModel( *this )); +} + +// ____ XVisualObject ____ +void SAL_CALL ChartModel::setVisualAreaSize( ::sal_Int64 nAspect, const awt::Size& aSize ) +{ + if( nAspect == embed::Aspects::MSOLE_CONTENT ) + { + ControllerLockGuard aLockGuard( *this ); + bool bChanged = + (m_aVisualAreaSize.Width != aSize.Width || + m_aVisualAreaSize.Height != aSize.Height); + + // #i12587# support for shapes in chart + if ( bChanged ) + { + impl_adjustAdditionalShapesPositionAndSize( aSize ); + } + + m_aVisualAreaSize = aSize; + if( bChanged ) + setModified( true ); + } + else + { + OSL_FAIL( "setVisualAreaSize: Aspect not implemented yet."); + } +} + +awt::Size SAL_CALL ChartModel::getVisualAreaSize( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + // other possible aspects are MSOLE_THUMBNAIL, MSOLE_ICON and MSOLE_DOCPRINT + + return m_aVisualAreaSize; +} + +embed::VisualRepresentation SAL_CALL ChartModel::getPreferredVisualRepresentation( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + + embed::VisualRepresentation aResult; + + try + { + Sequence< sal_Int8 > aMetafile; + + //get view from old api wrapper + Reference< datatransfer::XTransferable > xTransferable( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if( xTransferable.is() ) + { + datatransfer::DataFlavor aDataFlavor( lcl_aGDIMetaFileMIMEType, + "GDIMetaFile", + cppu::UnoType>::get() ); + + uno::Any aData( xTransferable->getTransferData( aDataFlavor ) ); + aData >>= aMetafile; + } + + aResult.Flavor.MimeType = lcl_aGDIMetaFileMIMEType; + aResult.Flavor.DataType = cppu::UnoType::get(); + + aResult.Data <<= aMetafile; + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +::sal_Int32 SAL_CALL ChartModel::getMapUnit( ::sal_Int64 nAspect ) +{ + OSL_ENSURE( nAspect == embed::Aspects::MSOLE_CONTENT, + "No aspects other than content are supported" ); + return embed::EmbedMapUnits::ONE_100TH_MM; +} + +// ____ datatransfer::XTransferable ____ +uno::Any SAL_CALL ChartModel::getTransferData( const datatransfer::DataFlavor& aFlavor ) +{ + uno::Any aResult; + if( !isDataFlavorSupported( aFlavor ) ) + throw datatransfer::UnsupportedFlavorException( + aFlavor.MimeType, static_cast< ::cppu::OWeakObject* >( this )); + + try + { + //get view from old api wrapper + Reference< datatransfer::XTransferable > xTransferable( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if( xTransferable.is() && + xTransferable->isDataFlavorSupported( aFlavor )) + { + aResult = xTransferable->getTransferData( aFlavor ); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +Sequence< datatransfer::DataFlavor > SAL_CALL ChartModel::getTransferDataFlavors() +{ + return { datatransfer::DataFlavor( lcl_aGDIMetaFileMIMETypeHighContrast, + "GDIMetaFile", + cppu::UnoType>::get() ) }; +} + +sal_Bool SAL_CALL ChartModel::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) +{ + return aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast; +} + +namespace +{ +enum eServiceType +{ + SERVICE_DASH_TABLE, + SERVICE_GRADIENT_TABLE, + SERVICE_HATCH_TABLE, + SERVICE_BITMAP_TABLE, + SERVICE_TRANSP_GRADIENT_TABLE, + SERVICE_MARKER_TABLE, + SERVICE_NAMESPACE_MAP +}; + +typedef std::map< OUString, enum eServiceType > tServiceNameMap; + +tServiceNameMap & lcl_getStaticServiceNameMap() +{ + static tServiceNameMap aServiceNameMap{ + {"com.sun.star.drawing.DashTable", SERVICE_DASH_TABLE}, + {"com.sun.star.drawing.GradientTable", SERVICE_GRADIENT_TABLE}, + {"com.sun.star.drawing.HatchTable", SERVICE_HATCH_TABLE}, + {"com.sun.star.drawing.BitmapTable", SERVICE_BITMAP_TABLE}, + {"com.sun.star.drawing.TransparencyGradientTable", SERVICE_TRANSP_GRADIENT_TABLE}, + {"com.sun.star.drawing.MarkerTable", SERVICE_MARKER_TABLE}, + {"com.sun.star.xml.NamespaceMap", SERVICE_NAMESPACE_MAP}}; + return aServiceNameMap; +} +} +// ____ XMultiServiceFactory ____ +Reference< uno::XInterface > SAL_CALL ChartModel::createInstance( const OUString& rServiceSpecifier ) +{ + tServiceNameMap & rMap = lcl_getStaticServiceNameMap(); + + tServiceNameMap::const_iterator aIt( rMap.find( rServiceSpecifier )); + if( aIt != rMap.end()) + { + switch( (*aIt).second ) + { + case SERVICE_DASH_TABLE: + case SERVICE_GRADIENT_TABLE: + case SERVICE_HATCH_TABLE: + case SERVICE_BITMAP_TABLE: + case SERVICE_TRANSP_GRADIENT_TABLE: + case SERVICE_MARKER_TABLE: + { + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + return mxChartView->createInstance( rServiceSpecifier ); + } + break; + case SERVICE_NAMESPACE_MAP: + return static_cast(m_xXMLNamespaceMap.get()); + } + } + else if(rServiceSpecifier == CHART_VIEW_SERVICE_NAME) + { + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + + return static_cast< ::cppu::OWeakObject* >( mxChartView.get() ); + } + else + { + if( m_xOldModelAgg.is() ) + { + Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType::get()); + uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; + if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) + { + return xOldModelFactory->createInstance( rServiceSpecifier ); + } + } + } + return nullptr; +} + +Reference< uno::XInterface > SAL_CALL ChartModel::createInstanceWithArguments( + const OUString& rServiceSpecifier , const Sequence< Any >& Arguments ) +{ + OSL_ENSURE( Arguments.hasElements(), "createInstanceWithArguments: Warning: Arguments are ignored" ); + return createInstance( rServiceSpecifier ); +} + +Sequence< OUString > SAL_CALL ChartModel::getAvailableServiceNames() +{ + uno::Sequence< OUString > aResult; + + if( m_xOldModelAgg.is()) + { + Any aAny = m_xOldModelAgg->queryAggregation( cppu::UnoType::get()); + uno::Reference< lang::XMultiServiceFactory > xOldModelFactory; + if( (aAny >>= xOldModelFactory) && xOldModelFactory.is() ) + { + return xOldModelFactory->getAvailableServiceNames(); + } + } + return aResult; +} + +Reference< util::XNumberFormatsSupplier > const & ChartModel::getNumberFormatsSupplier() +{ + if( !m_xNumberFormatsSupplier.is() ) + { + if( !m_xOwnNumberFormatsSupplier.is() ) + { + m_apSvNumberFormatter.reset( new SvNumberFormatter( m_xContext, LANGUAGE_SYSTEM ) ); + m_xOwnNumberFormatsSupplier = new SvNumberFormatsSupplierObj( m_apSvNumberFormatter.get() ); + //pOwnNumberFormatter->ChangeStandardPrec( 15 ); todo? + } + m_xNumberFormatsSupplier = m_xOwnNumberFormatsSupplier; + } + return m_xNumberFormatsSupplier; +} + +// ____ XUnoTunnel ___ +::sal_Int64 SAL_CALL ChartModel::getSomething( const Sequence< ::sal_Int8 >& aIdentifier ) +{ + if( comphelper::isUnoTunnelId(aIdentifier) ) + { + Reference< lang::XUnoTunnel > xTunnel( getNumberFormatsSupplier(), uno::UNO_QUERY ); + if( xTunnel.is() ) + return xTunnel->getSomething( aIdentifier ); + } + return 0; +} + +// ____ XNumberFormatsSupplier ____ +uno::Reference< beans::XPropertySet > SAL_CALL ChartModel::getNumberFormatSettings() +{ + Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); + if( xSupplier.is() ) + return xSupplier->getNumberFormatSettings(); + return uno::Reference< beans::XPropertySet >(); +} + +uno::Reference< util::XNumberFormats > SAL_CALL ChartModel::getNumberFormats() +{ + Reference< util::XNumberFormatsSupplier > xSupplier( getNumberFormatsSupplier() ); + if( xSupplier.is() ) + return xSupplier->getNumberFormats(); + return uno::Reference< util::XNumberFormats >(); +} + +// ____ XChild ____ +Reference< uno::XInterface > SAL_CALL ChartModel::getParent() +{ + return Reference< uno::XInterface >(m_xParent,uno::UNO_QUERY); +} + +void SAL_CALL ChartModel::setParent( const Reference< uno::XInterface >& Parent ) +{ + if( Parent != m_xParent ) + m_xParent.set( Parent, uno::UNO_QUERY ); +} + +// ____ XDataSource ____ +uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ChartModel::getDataSequences() +{ + rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *this ); + if( xSource.is()) + return xSource->getDataSequences(); + + return uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >(); +} + +//XDumper +OUString SAL_CALL ChartModel::dump() +{ + uno::Reference< qa::XDumper > xDumper( + createInstance( CHART_VIEW_SERVICE_NAME ), uno::UNO_QUERY ); + if (xDumper.is()) + return xDumper->dump(); + + return OUString(); +} + +void ChartModel::setTimeBasedRange(sal_Int32 nStart, sal_Int32 nEnd) +{ + mnStart = nStart; + mnEnd = nEnd; + mbTimeBased = true; +} + +void ChartModel::update() +{ + if(!mxChartView.is()) + { + mxChartView = new ChartView( m_xContext, *this); + } + mxChartView->setViewDirty(); + mxChartView->update(); +} + +bool ChartModel::isDataFromSpreadsheet() +{ + return !isDataFromPivotTable() && !hasInternalDataProvider(); +} + +bool ChartModel::isDataFromPivotTable() const +{ + uno::Reference xPivotTableDataProvider(m_xDataProvider, uno::UNO_QUERY); + return xPivotTableDataProvider.is(); +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartModel_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ChartModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/ChartModel_Persistence.cxx b/chart2/source/model/main/ChartModel_Persistence.cxx new file mode 100644 index 000000000..f6f85e5f2 --- /dev/null +++ b/chart2/source/model/main/ChartModel_Persistence.cxx @@ -0,0 +1,808 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::osl::MutexGuard; + +namespace +{ +struct lcl_PropNameEquals +{ + explicit lcl_PropNameEquals( const OUString & rStrToCompareWith ) : + m_aStr( rStrToCompareWith ) + {} + bool operator() ( const beans::PropertyValue & rProp ) + { + return rProp.Name == m_aStr; + } +private: + OUString m_aStr; +}; + +template< typename T > +T lcl_getProperty( + const Sequence< beans::PropertyValue > & rMediaDescriptor, + const OUString & rPropName ) +{ + T aResult; + if( rMediaDescriptor.hasElements()) + { + const beans::PropertyValue * pIt = rMediaDescriptor.getConstArray(); + const beans::PropertyValue * pEndIt = pIt + + rMediaDescriptor.getLength(); + pIt = std::find_if( pIt, pEndIt, lcl_PropNameEquals( rPropName )); + if( pIt != pEndIt ) + (*pIt).Value >>= aResult; + } + return aResult; +} + +void lcl_addStorageToMediaDescriptor( + Sequence< beans::PropertyValue > & rOutMD, + const Reference< embed::XStorage > & xStorage ) +{ + rOutMD.realloc( rOutMD.getLength() + 1 ); + rOutMD.getArray()[rOutMD.getLength() - 1] = beans::PropertyValue( + "Storage", -1, uno::Any( xStorage ), beans::PropertyState_DIRECT_VALUE ); +} + +Reference< embed::XStorage > lcl_createStorage( + const OUString & rURL, + const Reference< uno::XComponentContext > & xContext, + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + // create new storage + Reference< embed::XStorage > xStorage; + if( !xContext.is()) + return xStorage; + + try + { + Reference< io::XStream > xStream( + ::ucbhelper::Content( rURL, Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext()).openStream(), + uno::UNO_QUERY ); + + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create( xContext ) ); + Sequence< uno::Any > aStorageArgs{ uno::Any(xStream), + uno::Any(embed::ElementModes::READWRITE), + uno::Any(rMediaDescriptor) }; + xStorage.set( + xStorageFact->createInstanceWithArguments( aStorageArgs ), uno::UNO_QUERY_THROW ); + } + catch(const css::ucb::ContentCreationException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + catch(const css::ucb::CommandFailedException&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xStorage; +} + +} // anonymous namespace + +namespace chart +{ + +Reference< document::XFilter > ChartModel::impl_createFilter( + const Sequence< beans::PropertyValue > & rMediaDescriptor ) +{ + Reference< document::XFilter > xFilter; + + // find FilterName in MediaDescriptor + OUString aFilterName( + lcl_getProperty< OUString >( rMediaDescriptor, "FilterName" ) ); + + // if FilterName was found, get Filter from factory + if( !aFilterName.isEmpty() ) + { + try + { + Reference< container::XNameAccess > xFilterFact( + m_xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.document.FilterFactory", m_xContext ), + uno::UNO_QUERY_THROW ); + uno::Any aFilterProps( xFilterFact->getByName( aFilterName )); + Sequence< beans::PropertyValue > aProps; + + if( aFilterProps.hasValue() && + (aFilterProps >>= aProps)) + { + OUString aFilterServiceName( + lcl_getProperty< OUString >( aProps, "FilterService" ) ); + + if( !aFilterServiceName.isEmpty()) + { + xFilter.set( + m_xContext->getServiceManager()->createInstanceWithContext( + aFilterServiceName, m_xContext ), uno::UNO_QUERY_THROW ); + SAL_INFO("chart2", "Filter found for service " << aFilterServiceName ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + OSL_ENSURE( xFilter.is(), "Filter not found via factory" ); + } + + // fall-back: create XML-Filter + if( ! xFilter.is()) + { + SAL_WARN("chart2", "No FilterName passed in MediaDescriptor" ); + xFilter = new XMLFilter(m_xContext); + } + + return xFilter; +} + +// frame::XStorable2 + +void SAL_CALL ChartModel::storeSelf( const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + // only some parameters are allowed (see also SfxBaseModel) + // "VersionComment", "Author", "InteractionHandler", "StatusIndicator" + // However, they are ignored here. They would become interesting when + // charts support a standalone format again. + impl_store( rMediaDescriptor, m_xStorage ); +} + +// frame::XStorable (base of XStorable2) +sal_Bool SAL_CALL ChartModel::hasLocation() +{ + //@todo guard + return !m_aResource.isEmpty(); +} + +OUString SAL_CALL ChartModel::getLocation() +{ + return impl_g_getLocation(); +} + +sal_Bool SAL_CALL ChartModel::isReadonly() +{ + //@todo guard + return m_bReadOnly; +} + +void SAL_CALL ChartModel::store() +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + + OUString aLocation = m_aResource; + + if( aLocation.isEmpty() ) + throw io::IOException( "no location specified", static_cast< ::cppu::OWeakObject* >(this)); + //@todo check whether aLocation is something like private:factory... + if( m_bReadOnly ) + throw io::IOException( "document is read only", static_cast< ::cppu::OWeakObject* >(this)); + + aGuard.clear(); + + // store + impl_store( m_aMediaDescriptor, m_xStorage ); +} + +void SAL_CALL ChartModel::storeAsURL( + const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + + apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor); + uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor( + aMediaDescriptorHelper.getReducedForModel() ); + + m_bReadOnly = false; + aGuard.clear(); + + // create new storage + Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor )); + + if( xStorage.is()) + { + impl_store( aReducedMediaDescriptor, xStorage ); + attachResource( rURL, aReducedMediaDescriptor ); + } +} + +void SAL_CALL ChartModel::storeToURL( + const OUString& rURL, + const uno::Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall(true)) //start LongLastingCall + return; //behave passive if already disposed or closed or throw exception @todo? + //do not change the internal state of the document here + + aGuard.clear(); + + apphelper::MediaDescriptorHelper aMediaDescriptorHelper(rMediaDescriptor); + uno::Sequence< beans::PropertyValue > aReducedMediaDescriptor( + aMediaDescriptorHelper.getReducedForModel() ); + + if ( rURL == "private:stream" ) + { + try + { + if( m_xContext.is() && aMediaDescriptorHelper.ISSET_OutputStream ) + { + Reference< io::XStream > xStream( + io::TempFile::create(m_xContext), uno::UNO_QUERY_THROW ); + Reference< io::XInputStream > xInputStream( xStream->getInputStream()); + + Reference< embed::XStorage > xStorage( + ::comphelper::OStorageHelper::GetStorageFromStream( xStream, embed::ElementModes::READWRITE, m_xContext )); + if( xStorage.is()) + { + impl_store( aReducedMediaDescriptor, xStorage ); + + Reference< io::XSeekable > xSeekable( xStream, uno::UNO_QUERY_THROW ); + xSeekable->seek( 0 ); + ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream, aMediaDescriptorHelper.OutputStream ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + // create new storage + Reference< embed::XStorage > xStorage( lcl_createStorage( rURL, m_xContext, aReducedMediaDescriptor )); + + if( xStorage.is()) + impl_store( aReducedMediaDescriptor, xStorage ); + } +} + +void ChartModel::impl_store( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const Reference< embed::XStorage > & xStorage ) +{ + Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor)); + if( xFilter.is() && xStorage.is()) + { + Sequence< beans::PropertyValue > aMD( rMediaDescriptor ); + lcl_addStorageToMediaDescriptor( aMD, xStorage ); + try + { + Reference< document::XExporter > xExporter( xFilter, uno::UNO_QUERY_THROW ); + xExporter->setSourceDocument( Reference< lang::XComponent >( this )); + xFilter->filter( aMD ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + OSL_FAIL( "No filter" ); + } + + setModified( false ); + + //#i66865# + //for data change notification during chart is not loaded: + //notify parent data provider after saving thus the parent document can store + //the ranges for which a load and update of the chart will be necessary + Reference< beans::XPropertySet > xPropSet( m_xParent, uno::UNO_QUERY ); + if ( hasInternalDataProvider() || !xPropSet.is() ) + return; + + apphelper::MediaDescriptorHelper aMDHelper(rMediaDescriptor); + try + { + xPropSet->setPropertyValue( + "SavedObject", + uno::Any( aMDHelper.HierarchicalDocumentName ) ); + } + catch ( const uno::Exception& ) + { + } +} + +void ChartModel::insertDefaultChart() +{ + lockControllers(); + createInternalDataProvider( false ); + try + { + // create default chart + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( impl_createDefaultChartTypeTemplate() ); + if( xTemplate.is()) + { + try + { + Reference< chart2::data::XDataSource > xDataSource( impl_createDefaultData() ); + Sequence< beans::PropertyValue > aParam; + + bool bSupportsCategories = xTemplate->supportsCategories(); + if( bSupportsCategories ) + { + aParam = { beans::PropertyValue( "HasCategories", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) }; + } + + rtl::Reference< Diagram > xDiagram( xTemplate->createDiagramByDataSource2( xDataSource, aParam ) ); + + setFirstDiagram( xDiagram ); + + bool bIsRTL = AllSettings::GetMathLayoutRTL(); + //reverse x axis for rtl charts + if( bIsRTL ) + AxisHelper::setRTLAxisLayout( AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ) ); + + // create and attach legend + rtl::Reference< Legend > xLegend = new Legend(); + xLegend->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE )); + xLegend->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE )); + xLegend->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) )); // gray30 + xLegend->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10 + + if( bIsRTL ) + xLegend->setPropertyValue( "AnchorPosition", uno::Any( chart2::LegendPosition_LINE_START )); + if(xDiagram.is()) + xDiagram->setLegend( xLegend ); + + // set simple 3D look + if( xDiagram.is() ) + { + xDiagram->setPropertyValue( "RightAngledAxes", uno::Any( true )); + xDiagram->setPropertyValue( "D3DScenePerspective", uno::Any( drawing::ProjectionMode_PARALLEL )); + ThreeDHelper::setScheme( xDiagram, ThreeDLookScheme::ThreeDLookScheme_Realistic ); + } + + //set some new 'defaults' for wall and floor + if( xDiagram.is() ) + { + Reference< beans::XPropertySet > xWall( xDiagram->getWall() ); + if( xWall.is() ) + { + xWall->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + xWall->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE ) ); + xWall->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + xWall->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xe6e6e6 ) ) ); // gray10 + } + Reference< beans::XPropertySet > xFloor( xDiagram->getFloor() ); + if( xFloor.is() ) + { + xFloor->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); + xFloor->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_SOLID ) ); + xFloor->setPropertyValue( "LineColor", uno::Any( static_cast< sal_Int32 >( 0xb3b3b3 ) ) ); // gray30 + xFloor->setPropertyValue( "FillColor", uno::Any( static_cast< sal_Int32 >( 0xcccccc ) ) ); // gray20 + } + + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + ChartModelHelper::setIncludeHiddenCells( false, *this ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + setModified( false ); + unlockControllers(); +} + +// frame::XLoadable +void SAL_CALL ChartModel::initNew() +{ +} + +void SAL_CALL ChartModel::load( + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + Reference< embed::XStorage > xStorage; + OUString aURL; + try + { + apphelper::MediaDescriptorHelper aMDHelper( rMediaDescriptor ); + if( aMDHelper.ISSET_Storage ) + { + xStorage = aMDHelper.Storage; + } + else if( aMDHelper.ISSET_Stream || + aMDHelper.ISSET_InputStream ) + { + if( aMDHelper.ISSET_FilterName && + (aMDHelper.FilterName == "StarChart 5.0" || + aMDHelper.FilterName == "StarChart 4.0" || + aMDHelper.FilterName == "StarChart 3.0" )) + { + attachResource( aMDHelper.URL, rMediaDescriptor ); + impl_load( rMediaDescriptor, nullptr ); // cannot create a storage from binary streams, but I do not need the storage here anyhow + m_bReadOnly = true; + return; + } + + Reference< lang::XSingleServiceFactory > xStorageFact( embed::StorageFactory::create(m_xContext) ); + + if( aMDHelper.ISSET_Stream ) + { + // convert XStream to XStorage via the storage factory + Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.Stream), + // todo: check if stream is read-only + uno::Any(embed::ElementModes::READ) }; //WRITE | embed::ElementModes::NOCREATE); + + xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ), + uno::UNO_QUERY_THROW ); + } + else + { + OSL_ASSERT( aMDHelper.ISSET_InputStream ); + // convert XInputStream to XStorage via the storage factory + Sequence< uno::Any > aStorageArgs{ uno::Any(aMDHelper.InputStream), + uno::Any(embed::ElementModes::READ) }; + + xStorage.set( xStorageFact->createInstanceWithArguments( aStorageArgs ), + uno::UNO_QUERY_THROW ); + } + } + + if( aMDHelper.ISSET_URL ) + aURL = aMDHelper.URL; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( xStorage.is()) + { + attachResource( aURL, rMediaDescriptor ); + impl_load( rMediaDescriptor, xStorage ); + } +} + +void ChartModel::impl_load( + const Sequence< beans::PropertyValue >& rMediaDescriptor, + const Reference< embed::XStorage >& xStorage ) +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_nInLoad++; + } + + Reference< document::XFilter > xFilter( impl_createFilter( rMediaDescriptor )); + + if( xFilter.is()) + { + Reference< document::XImporter > xImporter( xFilter, uno::UNO_QUERY_THROW ); + xImporter->setTargetDocument( this ); + Sequence< beans::PropertyValue > aMD( rMediaDescriptor ); + lcl_addStorageToMediaDescriptor( aMD, xStorage ); + + xFilter->filter( aMD ); + xFilter.clear(); + } + else + { + OSL_FAIL( "loadFromStorage cannot create filter" ); + } + + if( xStorage.is() ) + impl_loadGraphics( xStorage ); + + setModified( false ); + + // switchToStorage without notifying listeners (which shouldn't exist at + // this time, anyway) + m_xStorage = xStorage; + + { + MutexGuard aGuard( m_aModelMutex ); + m_nInLoad--; + } +} + +void ChartModel::impl_loadGraphics( + const Reference< embed::XStorage >& xStorage ) +{ + try + { + const Reference< embed::XStorage >& xGraphicsStorage( + xStorage->openStorageElement( "Pictures", + embed::ElementModes::READ ) ); + + if( xGraphicsStorage.is() ) + { + const uno::Sequence< OUString > aElementNames( + xGraphicsStorage->getElementNames() ); + + for( OUString const & streamName : aElementNames ) + { + if( xGraphicsStorage->isStreamElement( streamName ) ) + { + uno::Reference< io::XStream > xElementStream( + xGraphicsStorage->openStreamElement( + streamName, + embed::ElementModes::READ ) ); + + if( xElementStream.is() ) + { + std::unique_ptr< SvStream > apIStm( + ::utl::UcbStreamHelper::CreateStream( + xElementStream, true ) ); + + if (apIStm) + { + SolarMutexGuard aGuard; + Graphic aGraphic; + if (!GraphicConverter::Import(*apIStm, aGraphic)) + { + m_aGraphicObjectVector.emplace_back(aGraphic ); + } + } + } + } + } + } + } + catch ( const uno::Exception& ) + { + } +} + +// util::XModifiable +void ChartModel::impl_notifyModifiedListeners() +{ + { + MutexGuard aGuard( m_aModelMutex ); + m_bUpdateNotificationsPending = false; + } + + //always notify the view first! + ChartViewHelper::setViewToDirtyState( this ); + + ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer + .getContainer( cppu::UnoType::get()); + if( pIC ) + { + lang::EventObject aEvent( static_cast< lang::XComponent*>(this) ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< util::XModifyListener* >( aIt.next() )->modified( aEvent ); + } + } +} + +sal_Bool SAL_CALL ChartModel::isModified() +{ + //@todo guard + return m_bModified; +} + +void SAL_CALL ChartModel::setModified( sal_Bool bModified ) +{ + // tdf#141914: allow to set *unmodified* when parent does not allow to set modified + if (bModified) + { + // tdf#77007: honor parent's IsEnableSetModified + // Check it before LifeTimeGuard, to avoid deadlocking solar mutex and this guard + if (auto pParentShell = SfxObjectShell::GetShellFromComponent(getParent()); + pParentShell && !pParentShell->IsEnableSetModified()) + return; + } + + apphelper::LifeTimeGuard aGuard(m_aLifeTimeManager); + if(!aGuard.startApiCall())//@todo ? is this a long lasting call?? + return; //behave passive if already disposed or closed or throw exception @todo? + m_bModified = bModified; + + if( m_nControllerLockCount > 0 ) + { + m_bUpdateNotificationsPending = true; + return;//don't call listeners if controllers are locked + } + aGuard.clear(); + + if(bModified) + impl_notifyModifiedListeners(); +} + +// util::XModifyBroadcaster (base of XModifiable) +void SAL_CALL ChartModel::addModifyListener( + const uno::Reference< util::XModifyListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.addInterface( + cppu::UnoType::get(), xListener ); +} + +void SAL_CALL ChartModel::removeModifyListener( + const uno::Reference< util::XModifyListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.removeInterface( + cppu::UnoType::get(), xListener ); +} + +// util::XModifyListener +void SAL_CALL ChartModel::modified( const lang::EventObject& rEvenObject) +{ + uno::Reference xPivotTableDataProvider(rEvenObject.Source, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + lockControllers(); + uno::Reference xDataProvider(xPivotTableDataProvider, uno::UNO_QUERY); + try + { + uno::Sequence aArguments = + DataSourceHelper::createArguments("PivotChart", uno::Sequence(), true, true, true); + + Reference xDataSource(xDataProvider->createDataSource(aArguments)); + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = getTypeManager(); + rtl::Reference xDiagram(getFirstChartDiagram()); + + DiagramHelper::tTemplateWithServiceName aTemplateAndService = DiagramHelper::getTemplateForDiagram(xDiagram, xChartTypeManager); + aTemplateAndService.xChartTypeTemplate->changeDiagramData(xDiagram, xDataSource, aArguments); + } + catch (const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + unlockControllers(); + } + + if (m_nInLoad == 0) + setModified(true); +} + +// lang::XEventListener (base of util::XModifyListener) +void SAL_CALL ChartModel::disposing( const lang::EventObject& ) +{ + // child was disposed -- should not happen from outside +} + +// document::XStorageBasedDocument +void SAL_CALL ChartModel::loadFromStorage( + const Reference< embed::XStorage >& xStorage, + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + attachResource( OUString(), rMediaDescriptor ); + impl_load( rMediaDescriptor, xStorage ); +} + +void SAL_CALL ChartModel::storeToStorage( + const Reference< embed::XStorage >& xStorage, + const Sequence< beans::PropertyValue >& rMediaDescriptor ) +{ + impl_store( rMediaDescriptor, xStorage ); +} + +void SAL_CALL ChartModel::switchToStorage( const Reference< embed::XStorage >& xStorage ) +{ + m_xStorage = xStorage; + impl_notifyStorageChangeListeners(); +} + +Reference< embed::XStorage > SAL_CALL ChartModel::getDocumentStorage() +{ + return m_xStorage; +} + +void ChartModel::impl_notifyStorageChangeListeners() +{ + ::comphelper::OInterfaceContainerHelper2* pIC = m_aLifeTimeManager.m_aListenerContainer + .getContainer( cppu::UnoType::get()); + if( pIC ) + { + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< document::XStorageChangeListener* >( aIt.next() ) + ->notifyStorageChange( static_cast< ::cppu::OWeakObject* >( this ), m_xStorage ); + } + } +} + +void SAL_CALL ChartModel::addStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed() ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.addInterface( + cppu::UnoType::get(), xListener ); +} + +void SAL_CALL ChartModel::removeStorageChangeListener( const Reference< document::XStorageChangeListener >& xListener ) +{ + if( m_aLifeTimeManager.impl_isDisposedOrClosed(false) ) + return; //behave passive if already disposed or closed + + m_aLifeTimeManager.m_aListenerContainer.removeInterface( + cppu::UnoType::get(), xListener ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPoint.cxx b/chart2/source/model/main/DataPoint.cxx new file mode 100644 index 000000000..a5838c91f --- /dev/null +++ b/chart2/source/model/main/DataPoint.cxx @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DataPoint.hxx" +#include "DataPointProperties.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +struct StaticDataPointInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::DataPointProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticDataPointInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticDataPointInfoHelper_Initializer > +{ +}; + +struct StaticDataPointInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticDataPointInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticDataPointInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticDataPointInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +DataPoint::DataPoint( const uno::Reference< beans::XPropertySet > & rParentProperties ) : + ::property::OPropertySet( m_aMutex ), + m_xParentProperties( rParentProperties ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNoParentPropAllowed( false ) +{ + SetNewValuesExplicitlyEvenIfTheyEqualDefault(); +} + +DataPoint::DataPoint( const DataPoint & rOther ) : + impl::DataPoint_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNoParentPropAllowed( true ) +{ + SetNewValuesExplicitlyEvenIfTheyEqualDefault(); + + // m_xParentProperties has to be set from outside, like in the method + // DataSeries::createClone + + // add as listener to XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + m_bNoParentPropAllowed = false; +} + +DataPoint::~DataPoint() +{ + try + { + // remove listener from XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL DataPoint::createClone() +{ + return uno::Reference< util::XCloneable >( new DataPoint( *this )); +} + +// ____ XChild ____ +Reference< uno::XInterface > SAL_CALL DataPoint::getParent() +{ + return Reference< uno::XInterface >( m_xParentProperties.get(), uno::UNO_QUERY ); +} + +void SAL_CALL DataPoint::setParent( + const Reference< uno::XInterface >& Parent ) +{ + m_xParentProperties = Reference< beans::XPropertySet >( Parent, uno::UNO_QUERY ); +} + +// ____ OPropertySet ____ +void DataPoint::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + // the value set at the data series is the default + uno::Reference< beans::XFastPropertySet > xFast( m_xParentProperties.get(), uno::UNO_QUERY ); + if( !xFast.is()) + { + OSL_ENSURE( m_bNoParentPropAllowed, "data point needs a parent property set to provide values correctly" ); + rAny.clear(); + return; + } + + rAny = xFast->getFastPropertyValue( nHandle ); +} + +void SAL_CALL DataPoint::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const uno::Any& rValue ) +{ + if( nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y + || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ) + { + uno::Any aOldValue; + Reference< util::XModifyBroadcaster > xBroadcaster; + getFastPropertyValue( aOldValue, nHandle ); + if( aOldValue.hasValue() && + (aOldValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder ); + } + + OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ); + if( rValue.hasValue() && + (rValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder ); + } + } + + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +::cppu::IPropertyArrayHelper & SAL_CALL DataPoint::getInfoHelper() +{ + return *StaticDataPointInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL DataPoint::getPropertySetInfo() +{ + return *StaticDataPointInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL DataPoint::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL DataPoint::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL DataPoint::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL DataPoint::disposing( const lang::EventObject& ) +{ + // nothing +} + +// ____ OPropertySet ____ +void DataPoint::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// needed by MSC compiler +using impl::DataPoint_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( DataPoint, DataPoint_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL DataPoint::getImplementationName() +{ + return "com.sun.star.comp.chart.DataPoint" ; +} + +sal_Bool SAL_CALL DataPoint::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataPoint::getSupportedServiceNames() +{ + return { + "com.sun.star.drawing.FillProperties", + "com.sun.star.chart2.DataPoint", + "com.sun.star.chart2.DataPointProperties", + "com.sun.star.beans.PropertySet" + }; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPoint.hxx b/chart2/source/model/main/DataPoint.hxx new file mode 100644 index 000000000..52feb197d --- /dev/null +++ b/chart2/source/model/main/DataPoint.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::container::XChild, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::lang::XServiceInfo > + DataPoint_Base; +} + +class DataPoint final : + public cppu::BaseMutex, + public impl::DataPoint_Base, + public ::property::OPropertySet +{ +public: + explicit DataPoint( const css::uno::Reference< css::beans::XPropertySet > & rParentProperties ); + virtual ~DataPoint() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +private: + explicit DataPoint( const DataPoint & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + // Note: m_xParentProperties are not cloned! + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XChild ____ + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent() override; + virtual void SAL_CALL setParent( + const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + css::uno::WeakReference< css::beans::XPropertySet > m_xParentProperties; + + rtl::Reference m_xModifyEventForwarder; + bool m_bNoParentPropAllowed; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPointProperties.cxx b/chart2/source/model/main/DataPointProperties.cxx new file mode 100644 index 000000000..267bf9014 --- /dev/null +++ b/chart2/source/model/main/DataPointProperties.cxx @@ -0,0 +1,542 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DataPointProperties.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void DataPointProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // DataPointProperties + + // Common + + rOutProperties.emplace_back( "Color", + PROP_DATAPOINT_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillColor", + PROP_DATAPOINT_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Transparency", + PROP_DATAPOINT_TRANSPARENCY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillTransparence", + PROP_DATAPOINT_TRANSPARENCY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Fill Properties + rOutProperties.emplace_back( "FillStyle", + PROP_DATAPOINT_FILL_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TransparencyGradientName", + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillTransparenceGradientName", + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "GradientName", + PROP_DATAPOINT_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillGradientName", + PROP_DATAPOINT_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "GradientStepCount", + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillGradientStepCount", + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "HatchName", + PROP_DATAPOINT_HATCH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillHatchName", + PROP_DATAPOINT_HATCH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillBitmapName", + PROP_DATAPOINT_FILL_BITMAP_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillBackground", + PROP_DATAPOINT_FILL_BACKGROUND, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + // border for filled objects + rOutProperties.emplace_back( "BorderColor", + PROP_DATAPOINT_BORDER_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderStyle", + PROP_DATAPOINT_BORDER_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderWidth", + PROP_DATAPOINT_BORDER_WIDTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "BorderDashName", + PROP_DATAPOINT_BORDER_DASH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "BorderTransparency", + PROP_DATAPOINT_BORDER_TRANSPARENCY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // Line Properties + + rOutProperties.emplace_back( "LineColor", + PROP_DATAPOINT_BORDER_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineStyle", + LinePropertiesHelper::PROP_LINE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineWidth", + LinePropertiesHelper::PROP_LINE_WIDTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineDash", + LinePropertiesHelper::PROP_LINE_DASH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineDashName", + LinePropertiesHelper::PROP_LINE_DASH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineTransparence", + PROP_DATAPOINT_BORDER_TRANSPARENCY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineCap", + ::chart::LinePropertiesHelper::PROP_LINE_CAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // FillProperties + // bitmap properties + rOutProperties.emplace_back( "FillBitmapOffsetX", + FillProperties::PROP_FILL_BITMAP_OFFSETX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapOffsetY", + FillProperties::PROP_FILL_BITMAP_OFFSETY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetX", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetY", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapRectanglePoint", + FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapLogicalSize", + FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeX", + FillProperties::PROP_FILL_BITMAP_SIZEX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeY", + FillProperties::PROP_FILL_BITMAP_SIZEY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapMode", + FillProperties::PROP_FILL_BITMAP_MODE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // others + rOutProperties.emplace_back( "Symbol", + PROP_DATAPOINT_SYMBOL_PROP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Offset", + PROP_DATAPOINT_OFFSET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Geometry3D", + PROP_DATAPOINT_GEOMETRY3D, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_DATAPOINT_NUMBER_FORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LINK_TO_SRC_NUMFMT, + PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //additional 'PercentageNumberFormat' + rOutProperties.emplace_back( "PercentageNumberFormat", + PROP_DATAPOINT_PERCENTAGE_NUMBER_FORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LabelPlacement", + PROP_DATAPOINT_LABEL_PLACEMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_DATAPOINT_REFERENCE_DIAGRAM_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "TextRotation", + PROP_DATAPOINT_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // statistics + rOutProperties.emplace_back( CHART_UNONAME_ERRORBAR_X, + PROP_DATAPOINT_ERROR_BAR_X, + // XPropertySet supporting service ErrorBar + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_ERRORBAR_Y, + PROP_DATAPOINT_ERROR_BAR_Y, + // XPropertySet supporting service ErrorBar + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "ShowErrorBox", + PROP_DATAPOINT_SHOW_ERROR_BOX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "PercentDiagonal", + PROP_DATAPOINT_PERCENT_DIAGONAL, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + // Properties specific to data label. + + rOutProperties.emplace_back( CHART_UNONAME_LABEL, + PROP_DATAPOINT_LABEL, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextWordWrap", + PROP_DATAPOINT_TEXT_WORD_WRAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_SEP, + PROP_DATAPOINT_LABEL_SEPARATOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_STYLE, + PROP_DATAPOINT_LABEL_BORDER_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_COLOR, + PROP_DATAPOINT_LABEL_BORDER_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_STYLE, + PROP_DATAPOINT_LABEL_FILL_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_COLOR, + PROP_DATAPOINT_LABEL_FILL_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_BACKGROUND, + PROP_DATAPOINT_LABEL_FILL_BACKGROUND, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_FILL_HATCH_NAME, + PROP_DATAPOINT_LABEL_FILL_HATCH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_WIDTH, + PROP_DATAPOINT_LABEL_BORDER_WIDTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_DASH, + PROP_DATAPOINT_LABEL_BORDER_DASH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_DASHNAME, + PROP_DATAPOINT_LABEL_BORDER_DASH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( CHART_UNONAME_LABEL_BORDER_TRANS, + PROP_DATAPOINT_LABEL_BORDER_TRANS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_CUSTOM_LABEL_FIELDS, + PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, + cppu::UnoType>>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT); + + rOutProperties.emplace_back( "CustomLabelPosition", + PROP_DATAPOINT_LABEL_CUSTOM_POS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +void DataPointProperties::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_DATAPOINT_COLOR, 0x0099ccff ); // blue 8 + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_DATAPOINT_TRANSPARENCY, 0 ); + + //fill + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_STYLE, drawing::FillStyle_SOLID ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_GRADIENT_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_HATCH_NAME ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_BITMAP_NAME ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_FILL_BACKGROUND, false ); + + //border + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_DATAPOINT_BORDER_COLOR, 0x000000 ); // black + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_STYLE, drawing::LineStyle_SOLID ); // drawing::LineStyle_NONE + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_DATAPOINT_BORDER_WIDTH, 0 ); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, PROP_DATAPOINT_BORDER_DASH_NAME ); + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_DATAPOINT_BORDER_TRANSPARENCY, 0 ); + + //line + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_SOLID ); + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, LinePropertiesHelper::PROP_LINE_WIDTH, 0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_DASH, drawing::LineDash()); + PropertyHelper::setEmptyPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_DASH_NAME ); + PropertyHelper::setPropertyValueDefault( rOutMap, LinePropertiesHelper::PROP_LINE_CAP, drawing::LineCap_BUTT); + + //fill bitmap + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETX, 0 ); + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETY, 0 ); + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, 0 ); + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, 0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, drawing::RectanglePoint_MIDDLE_MIDDLE ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, true ); + + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEX, 0 ); + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEY, 0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_MODE, drawing::BitmapMode_REPEAT ); + + //others + chart2::Symbol aSymbProp; + aSymbProp.Style = chart2::SymbolStyle_NONE; + aSymbProp.StandardSymbol = 0; + aSymbProp.Size = awt::Size( 250, 250 ); // ca. 7pt x 7pt (7pt=246.94) + aSymbProp.BorderColor = 0x000000; // Black + aSymbProp.FillColor = 0xee4000; // OrangeRed2 + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_SYMBOL_PROP, aSymbProp ); + + PropertyHelper::setPropertyValueDefault< double >( rOutMap, PROP_DATAPOINT_OFFSET, 0.0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_GEOMETRY3D, chart2::DataPointGeometry3D::CUBOID ); + + //@todo maybe choose a different one here -> should be dynamically that of the attached axis + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_ERROR_BAR_X, uno::Reference< beans::XPropertySet >()); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_ERROR_BAR_Y, uno::Reference< beans::XPropertySet >()); + PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_DATAPOINT_PERCENT_DIAGONAL, 0 ); + + PropertyHelper::setPropertyValueDefault< double >( rOutMap, PROP_DATAPOINT_TEXT_ROTATION, 0.0 ); + + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, true); + + // data label + PropertyHelper::setPropertyValueDefault( + rOutMap, PROP_DATAPOINT_LABEL, + chart2::DataPointLabel( + false, // ShowNumber + false, // ShowNumberInPercent + false, // ShowCategoryName + false, // ShowLegendSymbol + false, // ShowCustomLabel + false // ShowSeriesName + )); + + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATAPOINT_TEXT_WORD_WRAP, false ); + PropertyHelper::setPropertyValueDefault< OUString >( rOutMap, PROP_DATAPOINT_LABEL_SEPARATOR, " " ); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_STYLE, sal_Int32(drawing::LineStyle_NONE)); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_COLOR); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_STYLE); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_COLOR); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_BACKGROUND); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_FILL_HATCH_NAME); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_WIDTH, 0); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_DASH, drawing::LineDash()); + PropertyHelper::setEmptyPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_DASH_NAME); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_LABEL_BORDER_TRANS, 0); + + uno::Sequence> aFields(0); + PropertyHelper::setPropertyValueDefault(rOutMap, PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, aFields); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataPointProperties.hxx b/chart2/source/model/main/DataPointProperties.hxx new file mode 100644 index 000000000..ada7907b8 --- /dev/null +++ b/chart2/source/model/main/DataPointProperties.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +namespace com::sun::star::beans { struct Property; } + +namespace chart +{ + +// implements service DataPointProperties +namespace DataPointProperties +{ + // FastProperty Ids for properties + enum + { + PROP_DATAPOINT_LABEL_FILL_STYLE, + PROP_DATAPOINT_LABEL_FILL_COLOR, + PROP_DATAPOINT_LABEL_FILL_BACKGROUND, + PROP_DATAPOINT_LABEL_FILL_HATCH_NAME, + + // common + PROP_DATAPOINT_COLOR = FAST_PROPERTY_ID_START_DATA_POINT, + PROP_DATAPOINT_TRANSPARENCY, + + // fill + PROP_DATAPOINT_FILL_STYLE, + PROP_DATAPOINT_TRANSPARENCY_GRADIENT_NAME, + PROP_DATAPOINT_GRADIENT_NAME, + PROP_DATAPOINT_GRADIENT_STEPCOUNT, + PROP_DATAPOINT_HATCH_NAME, + PROP_DATAPOINT_FILL_BITMAP_NAME, + PROP_DATAPOINT_FILL_BACKGROUND, + + // border (of filled objects) + PROP_DATAPOINT_BORDER_COLOR, + PROP_DATAPOINT_BORDER_STYLE, + PROP_DATAPOINT_BORDER_WIDTH, + PROP_DATAPOINT_BORDER_DASH_NAME, + PROP_DATAPOINT_BORDER_TRANSPARENCY, + + // others + PROP_DATAPOINT_SYMBOL_PROP, + PROP_DATAPOINT_OFFSET, + PROP_DATAPOINT_GEOMETRY3D, + PROP_DATAPOINT_NUMBER_FORMAT, + PROP_DATAPOINT_LINK_NUMBERFORMAT_TO_SOURCE, + PROP_DATAPOINT_PERCENTAGE_NUMBER_FORMAT, + PROP_DATAPOINT_LABEL_PLACEMENT, + PROP_DATAPOINT_REFERENCE_DIAGRAM_SIZE, + PROP_DATAPOINT_TEXT_ROTATION, + + // statistics + PROP_DATAPOINT_ERROR_BAR_X, + PROP_DATAPOINT_ERROR_BAR_Y, + PROP_DATAPOINT_SHOW_ERROR_BOX, + PROP_DATAPOINT_PERCENT_DIAGONAL, + + // label + PROP_DATAPOINT_LABEL, + PROP_DATAPOINT_LABEL_SEPARATOR, + PROP_DATAPOINT_TEXT_WORD_WRAP, + PROP_DATAPOINT_LABEL_BORDER_STYLE, + PROP_DATAPOINT_LABEL_BORDER_COLOR, + PROP_DATAPOINT_LABEL_BORDER_WIDTH, + PROP_DATAPOINT_LABEL_BORDER_DASH, + PROP_DATAPOINT_LABEL_BORDER_DASH_NAME, + PROP_DATAPOINT_LABEL_BORDER_TRANS, + PROP_DATAPOINT_CUSTOM_LABEL_FIELDS, + PROP_DATAPOINT_LABEL_CUSTOM_POS + + // additionally some properties from ::chart::LineProperties + }; + + void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + void AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataSeries.cxx b/chart2/source/model/main/DataSeries.cxx new file mode 100644 index 000000000..b54fa3897 --- /dev/null +++ b/chart2/source/model/main/DataSeries.cxx @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "DataSeriesProperties.hxx" +#include "DataPointProperties.hxx" +#include +#include +#include "DataPoint.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::osl::MutexGuard; + +namespace +{ + +struct StaticDataSeriesDefaults : public rtl::StaticWithInit< ::chart::tPropertyValueMap, StaticDataSeriesDefaults > +{ + ::chart::tPropertyValueMap operator()() + { + ::chart::tPropertyValueMap aStaticDefaults; + ::chart::DataSeriesProperties::AddDefaultsToMap( aStaticDefaults ); + ::chart::CharacterProperties::AddDefaultsToMap( aStaticDefaults ); + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aStaticDefaults, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + return aStaticDefaults; + } +}; + +struct StaticDataSeriesInfoHelper : public rtl::StaticWithInit< ::cppu::OPropertyArrayHelper, StaticDataSeriesInfoHelper, StaticDataSeriesInfoHelper, uno::Sequence< Property > > +{ + uno::Sequence< Property > operator()() + { + std::vector< css::beans::Property > aProperties; + ::chart::DataSeriesProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticDataSeriesInfo : public rtl::StaticWithInit< uno::Reference< beans::XPropertySetInfo >, StaticDataSeriesInfo > +{ + uno::Reference< beans::XPropertySetInfo > operator()() + { + return ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDataSeriesInfoHelper::get() ); + } +}; + +void lcl_SetParent( + const uno::Reference< uno::XInterface > & xChildInterface, + const uno::Reference< uno::XInterface > & xParentInterface ) +{ + uno::Reference< container::XChild > xChild( xChildInterface, uno::UNO_QUERY ); + if( xChild.is()) + xChild->setParent( xParentInterface ); +} + +typedef std::map< sal_Int32, css::uno::Reference< css::beans::XPropertySet > > + lcl_tDataPointMap; + +void lcl_CloneAttributedDataPoints( + const lcl_tDataPointMap & rSource, lcl_tDataPointMap & rDestination, + const uno::Reference< uno::XInterface > & xSeries ) +{ + for (auto const& elem : rSource) + { + Reference< beans::XPropertySet > xPoint( elem.second ); + if( xPoint.is()) + { + Reference< util::XCloneable > xCloneable( xPoint, uno::UNO_QUERY ); + if( xCloneable.is()) + { + xPoint.set( xCloneable->createClone(), uno::UNO_QUERY ); + if( xPoint.is()) + { + lcl_SetParent( xPoint, xSeries ); + rDestination.emplace( elem.first, xPoint ); + } + } + } + } +} + +} // anonymous namespace + +namespace chart +{ + +DataSeries::DataSeries() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +DataSeries::DataSeries( const DataSeries & rOther ) : + impl::DataSeries_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + if( ! rOther.m_aDataSequences.empty()) + { + CloneHelper::CloneRefVector(rOther.m_aDataSequences, m_aDataSequences ); + ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); + } + + CloneHelper::CloneRefVector( rOther.m_aRegressionCurves, m_aRegressionCurves ); + ModifyListenerHelper::addListenerToAllElements( m_aRegressionCurves, m_xModifyEventForwarder ); + + // add as listener to XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); +} + +// late initialization to call after copy-constructing +void DataSeries::Init( const DataSeries & rOther ) +{ + Reference< uno::XInterface > xThisInterface( static_cast< ::cppu::OWeakObject * >( this )); + if( ! rOther.m_aAttributedDataPoints.empty()) + { + lcl_CloneAttributedDataPoints( + rOther.m_aAttributedDataPoints, m_aAttributedDataPoints, xThisInterface ); + ModifyListenerHelper::addListenerToAllMapElements( m_aAttributedDataPoints, m_xModifyEventForwarder ); + } + + // add as parent to error bars + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + lcl_SetParent( xPropertySet, xThisInterface ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + lcl_SetParent( xPropertySet, xThisInterface ); +} + +DataSeries::~DataSeries() +{ + try + { + ModifyListenerHelper::removeListenerFromAllMapElements( m_aAttributedDataPoints, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllElements( m_aRegressionCurves, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListenerFromAllElements( m_aDataSequences, m_xModifyEventForwarder ); + + // remove listener from XPropertySet properties + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL DataSeries::createClone() +{ + rtl::Reference pNewSeries( new DataSeries( *this )); + // do initialization that uses uno references to the clone + pNewSeries->Init( *this ); + + return pNewSeries; +} + +// ____ OPropertySet ____ +void DataSeries::GetDefaultValue( sal_Int32 nHandle, uno::Any& rDest ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticDataSeriesDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rDest.clear(); + else + rDest = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL DataSeries::getInfoHelper() +{ + return StaticDataSeriesInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL DataSeries::getPropertySetInfo() +{ + return StaticDataSeriesInfo::get(); +} + +void SAL_CALL DataSeries::getFastPropertyValue + ( uno::Any& rValue, + sal_Int32 nHandle ) const +{ + // special handling for get. set is not possible for this property + if( nHandle == DataSeriesProperties::PROP_DATASERIES_ATTRIBUTED_DATA_POINTS ) + { + // TODO: only add those property sets that are really modified + + rValue <<= comphelper::mapKeysToSequence(m_aAttributedDataPoints); + } + else + OPropertySet::getFastPropertyValue( rValue, nHandle ); +} + +void SAL_CALL DataSeries::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const uno::Any& rValue ) +{ + if( nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_Y + || nHandle == DataPointProperties::PROP_DATAPOINT_ERROR_BAR_X ) + { + uno::Any aOldValue; + Reference< util::XModifyBroadcaster > xBroadcaster; + getFastPropertyValue( aOldValue, nHandle ); + if( aOldValue.hasValue() && + (aOldValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder ); + } + + OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ); + if( rValue.hasValue() && + (rValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder ); + } + } + + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +Reference< beans::XPropertySet > + SAL_CALL DataSeries::getDataPointByIndex( sal_Int32 nIndex ) +{ + Reference< beans::XPropertySet > xResult; + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences; + { + MutexGuard aGuard( m_aMutex ); + aSequences = m_aDataSequences; + } + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aValuesSeries( + DataSeriesHelper::getAllDataSequencesByRole( aSequences , "values" ) ); + + if (aValuesSeries.empty()) + throw lang::IndexOutOfBoundsException(); + + Reference< chart2::data::XDataSequence > xSeq( aValuesSeries.front()->getValues() ); + if( 0 <= nIndex && nIndex < xSeq->getData().getLength() ) + { + { + MutexGuard aGuard( m_aMutex ); + tDataPointAttributeContainer::iterator aIt( m_aAttributedDataPoints.find( nIndex ) ); + if( aIt != m_aAttributedDataPoints.end() ) + xResult = (*aIt).second; + } + if( !xResult.is() ) + { + Reference< beans::XPropertySet > xParentProperties; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xParentProperties = this; + xModifyEventForwarder = m_xModifyEventForwarder; + } + + // create a new XPropertySet for this data point + xResult.set( new DataPoint( xParentProperties ) ); + { + MutexGuard aGuard( m_aMutex ); + m_aAttributedDataPoints[ nIndex ] = xResult; + } + ModifyListenerHelper::addListener( xResult, xModifyEventForwarder ); + } + } + + return xResult; +} + +void SAL_CALL DataSeries::resetDataPoint( sal_Int32 nIndex ) +{ + Reference< beans::XPropertySet > xDataPointProp; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + tDataPointAttributeContainer::iterator aIt( m_aAttributedDataPoints.find( nIndex )); + if( aIt != m_aAttributedDataPoints.end()) + { + xDataPointProp = (*aIt).second; + m_aAttributedDataPoints.erase(aIt); + } + + } + if( xDataPointProp.is() ) + { + Reference< util::XModifyBroadcaster > xBroadcaster( xDataPointProp, uno::UNO_QUERY ); + if( xBroadcaster.is() && xModifyEventForwarder.is()) + xBroadcaster->removeModifyListener( xModifyEventForwarder ); + fireModifyEvent(); + } +} + +void SAL_CALL DataSeries::resetAllDataPoints() +{ + tDataPointAttributeContainer aOldAttributedDataPoints; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldAttributedDataPoints, m_aAttributedDataPoints ); + } + ModifyListenerHelper::removeListenerFromAllMapElements( aOldAttributedDataPoints, xModifyEventForwarder ); + aOldAttributedDataPoints.clear(); + fireModifyEvent(); +} + +// ____ XDataSink ____ +void SAL_CALL DataSeries::setData( const uno::Sequence< Reference< chart2::data::XLabeledDataSequence > >& aData ) +{ + tDataSequenceContainer aOldDataSequences; + tDataSequenceContainer aNewDataSequences; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldDataSequences, m_aDataSequences ); + for (const auto & i : aData) + { + aNewDataSequences.push_back(i); + } + m_aDataSequences = aNewDataSequences; + } + ModifyListenerHelper::removeListenerFromAllElements( aOldDataSequences, xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( aNewDataSequences, xModifyEventForwarder ); + fireModifyEvent(); +} + +void DataSeries::setData( const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >& aData ) +{ + tDataSequenceContainer aOldDataSequences; + tDataSequenceContainer aNewDataSequences; + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldDataSequences, m_aDataSequences ); + aNewDataSequences = aData; + m_aDataSequences = aNewDataSequences; + } + ModifyListenerHelper::removeListenerFromAllElements( aOldDataSequences, xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( aNewDataSequences, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XDataSource ____ +Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL DataSeries::getDataSequences() +{ + MutexGuard aGuard( m_aMutex ); + return comphelper::containerToSequence>( m_aDataSequences ); +} + +// ____ XRegressionCurveContainer ____ +void SAL_CALL DataSeries::addRegressionCurve( + const uno::Reference< chart2::XRegressionCurve >& xRegressionCurve ) +{ + auto pRegressionCurve = dynamic_cast(xRegressionCurve.get()); + assert(pRegressionCurve); + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + if( std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), pRegressionCurve ) + != m_aRegressionCurves.end()) + throw lang::IllegalArgumentException("curve not found", static_cast(this), 1); + m_aRegressionCurves.push_back( pRegressionCurve ); + } + ModifyListenerHelper::addListener( rtl::Reference(pRegressionCurve), xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL DataSeries::removeRegressionCurve( + const uno::Reference< chart2::XRegressionCurve >& xRegressionCurve ) +{ + if( !xRegressionCurve.is() ) + throw container::NoSuchElementException(); + auto pRegressionCurve = dynamic_cast(xRegressionCurve.get()); + assert(pRegressionCurve); + + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + tRegressionCurveContainerType::iterator aIt( + std::find( m_aRegressionCurves.begin(), m_aRegressionCurves.end(), pRegressionCurve ) ); + if( aIt == m_aRegressionCurves.end()) + throw container::NoSuchElementException( + "The given regression curve is no element of this series", + static_cast< uno::XWeak * >( this )); + m_aRegressionCurves.erase( aIt ); + } + + ModifyListenerHelper::removeListener( rtl::Reference(pRegressionCurve), xModifyEventForwarder ); + fireModifyEvent(); +} + +uno::Sequence< uno::Reference< chart2::XRegressionCurve > > SAL_CALL DataSeries::getRegressionCurves() +{ + MutexGuard aGuard( m_aMutex ); + return comphelper::containerToSequence>( m_aRegressionCurves ); +} + +void SAL_CALL DataSeries::setRegressionCurves( + const Sequence< Reference< chart2::XRegressionCurve > >& aRegressionCurves ) +{ + tRegressionCurveContainerType aOldCurves; + tRegressionCurveContainerType aNewCurves; + for (const auto & i : aRegressionCurves) + { + auto pRegressionCurve = dynamic_cast(i.get()); + assert(pRegressionCurve); + aNewCurves.push_back(pRegressionCurve); + } + Reference< util::XModifyListener > xModifyEventForwarder; + { + MutexGuard aGuard( m_aMutex ); + xModifyEventForwarder = m_xModifyEventForwarder; + std::swap( aOldCurves, m_aRegressionCurves ); + m_aRegressionCurves = aNewCurves; + } + ModifyListenerHelper::removeListenerFromAllElements( aOldCurves, xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( aNewCurves, xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL DataSeries::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL DataSeries::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL DataSeries::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL DataSeries::disposing( const lang::EventObject& ) +{ +} + +// ____ OPropertySet ____ +void DataSeries::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void DataSeries::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::DataSeries_Base; +using ::property::OPropertySet; + +IMPLEMENT_FORWARD_XINTERFACE2( DataSeries, DataSeries_Base, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( DataSeries, DataSeries_Base, OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL DataSeries::getImplementationName() +{ + return "com.sun.star.comp.chart.DataSeries"; +} + +sal_Bool SAL_CALL DataSeries::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataSeries::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.DataSeries", + "com.sun.star.chart2.DataPointProperties", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_DataSeries_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::DataSeries ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataSeriesProperties.cxx b/chart2/source/model/main/DataSeriesProperties.cxx new file mode 100644 index 000000000..d85d26475 --- /dev/null +++ b/chart2/source/model/main/DataSeriesProperties.cxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DataSeriesProperties.hxx" +#include "DataPointProperties.hxx" +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void DataSeriesProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AttributedDataPoints", + PROP_DATASERIES_ATTRIBUTED_DATA_POINTS, + cppu::UnoType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "StackingDirection", + PROP_DATASERIES_STACKING_DIRECTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "VaryColorsByPoint", + PROP_DATASERIES_VARY_COLORS_BY_POINT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "AttachedAxisIndex", + PROP_DATASERIES_ATTACHED_AXIS_INDEX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ShowLegendEntry", + PROP_DATASERIES_SHOW_LEGEND_ENTRY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "DeletedLegendEntries", + PROP_DATASERIES_DELETED_LEGEND_ENTRIES, + cppu::UnoType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ShowCustomLeaderLines", + PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // add properties of service DataPointProperties + DataPointProperties::AddPropertiesToVector( rOutProperties ); +} + +void DataSeriesProperties::AddDefaultsToMap( + tPropertyValueMap & rOutMap ) +{ + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_STACKING_DIRECTION, chart2::StackingDirection_NO_STACKING ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_VARY_COLORS_BY_POINT, false ); + PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_DATASERIES_ATTACHED_AXIS_INDEX, 0 ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_SHOW_LEGEND_ENTRY, true ); + PropertyHelper::setPropertyValueDefault( rOutMap, PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES, true ); + + // PROP_DATASERIES_ATTRIBUTED_DATA_POINTS has no default + + // add properties of service DataPointProperties + DataPointProperties::AddDefaultsToMap( rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/DataSeriesProperties.hxx b/chart2/source/model/main/DataSeriesProperties.hxx new file mode 100644 index 000000000..13636d442 --- /dev/null +++ b/chart2/source/model/main/DataSeriesProperties.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include + +namespace com::sun::star::beans { struct Property; } + +namespace chart::DataSeriesProperties +{ + enum + { + PROP_DATASERIES_ATTRIBUTED_DATA_POINTS = FAST_PROPERTY_ID_START_DATA_SERIES, + PROP_DATASERIES_STACKING_DIRECTION, + PROP_DATASERIES_VARY_COLORS_BY_POINT, + PROP_DATASERIES_ATTACHED_AXIS_INDEX, + PROP_DATASERIES_SHOW_LEGEND_ENTRY, + PROP_DATASERIES_DELETED_LEGEND_ENTRIES, + PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES + }; + + void AddPropertiesToVector( + std::vector< css::beans::Property > & rOutProperties ); + + void AddDefaultsToMap( tPropertyValueMap & rOutMap ); + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Diagram.cxx b/chart2/source/model/main/Diagram.cxx new file mode 100644 index 000000000..7791fabc1 --- /dev/null +++ b/chart2/source/model/main/Diagram.cxx @@ -0,0 +1,699 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include "Wall.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_DIAGRAM_REL_POS, + PROP_DIAGRAM_REL_SIZE, + PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, + PROP_DIAGRAM_SORT_BY_X_VALUES, + PROP_DIAGRAM_CONNECT_BARS, + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + PROP_DIAGRAM_STARTING_ANGLE, + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + PROP_DIAGRAM_PERSPECTIVE, + PROP_DIAGRAM_ROTATION_HORIZONTAL, + PROP_DIAGRAM_ROTATION_VERTICAL, + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + PROP_DIAGRAM_3DRELATIVEHEIGHT, + PROP_DIAGRAM_DATATABLEHBORDER, + PROP_DIAGRAM_DATATABLEVBORDER, + PROP_DIAGRAM_DATATABLEOUTLINE, + PROP_DIAGRAM_EXTERNALDATA +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "RelativePosition", + PROP_DIAGRAM_REL_POS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativeSize", + PROP_DIAGRAM_REL_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "PosSizeExcludeAxes", + PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( CHART_UNONAME_SORT_BY_XVALUES, + PROP_DIAGRAM_SORT_BY_X_VALUES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ConnectBars", + PROP_DIAGRAM_CONNECT_BARS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GroupBarsPerAxis", + PROP_DIAGRAM_GROUP_BARS_PER_AXIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "IncludeHiddenCells", + PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "StartingAngle", + PROP_DIAGRAM_STARTING_ANGLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "RightAngledAxes", + PROP_DIAGRAM_RIGHT_ANGLED_AXES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Perspective", + PROP_DIAGRAM_PERSPECTIVE, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationHorizontal", + PROP_DIAGRAM_ROTATION_HORIZONTAL, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RotationVertical", + PROP_DIAGRAM_ROTATION_VERTICAL, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "MissingValueTreatment", + PROP_DIAGRAM_MISSING_VALUE_TREATMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "3DRelativeHeight", + PROP_DIAGRAM_3DRELATIVEHEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "DataTableHBorder", + PROP_DIAGRAM_DATATABLEHBORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableVBorder", + PROP_DIAGRAM_DATATABLEVBORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "DataTableOutline", + PROP_DIAGRAM_DATATABLEOUTLINE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ExternalData", + PROP_DIAGRAM_EXTERNALDATA, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID ); +} + +const ::chart::tPropertyValueMap& StaticDiagramDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = []() + { + ::chart::tPropertyValueMap aMap; + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_SORT_BY_X_VALUES, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_CONNECT_BARS, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_GROUP_BARS_PER_AXIS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_RIGHT_ANGLED_AXES, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_DATATABLEHBORDER, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_DATATABLEVBORDER, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_DATATABLEOUTLINE, false ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_STARTING_ANGLE, 90 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_3DRELATIVEHEIGHT, 100 ); + ::chart::SceneProperties::AddDefaultsToMap( aMap ); + return aMap; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& StaticDiagramInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = []() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::SceneProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return ::cppu::OPropertyArrayHelper( aProperties.data(), aProperties.size() ); + }(); + return aPropHelper; +}; + +const uno::Reference< beans::XPropertySetInfo >& StaticDiagramInfo() +{ + static const uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDiagramInfoHelper() ) ); + return xPropertySetInfo; +}; + +void lcl_CloneCoordinateSystems( + const ::chart::Diagram::tCoordinateSystemContainerType & rSource, + ::chart::Diagram::tCoordinateSystemContainerType & rDestination ) +{ + for( rtl::Reference< ::chart::BaseCoordinateSystem > const & i : rSource ) + { + auto xClone = i->createClone(); + ::chart::BaseCoordinateSystem* pClone = dynamic_cast<::chart::BaseCoordinateSystem*>(xClone.get()); + assert(pClone); + rDestination.push_back( pClone ); + } +} + +} // anonymous namespace + +namespace chart +{ + +Diagram::Diagram( uno::Reference< uno::XComponentContext > const & xContext ) : + ::property::OPropertySet( m_aMutex ), + m_xContext( xContext ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + // Set camera position to a default position (that should be set hard, so + // that it will be exported. The property default is a camera looking + // straight ono the scene). These defaults have been acquired from the old + // chart implementation. + setFastPropertyValue_NoBroadcast( + SceneProperties::PROP_SCENE_CAMERA_GEOMETRY, uno::Any( + ThreeDHelper::getDefaultCameraGeometry())); +} + +Diagram::Diagram( const Diagram & rOther ) : + impl::Diagram_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xContext( rOther.m_xContext ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + lcl_CloneCoordinateSystems( rOther.m_aCoordSystems, m_aCoordSystems ); + for (auto & xSystem : m_aCoordSystems) + xSystem->addModifyListener(m_xModifyEventForwarder); + + if ( rOther.m_xWall ) + m_xWall = new Wall( *rOther.m_xWall ); + if ( rOther.m_xFloor ) + m_xFloor = new Wall( *rOther.m_xFloor ); + m_xTitle.set( CloneHelper::CreateRefClone< chart2::XTitle >()( rOther.m_xTitle )); + if (rOther.m_xLegend) + m_xLegend = new Legend(*rOther.m_xLegend); + + if ( m_xWall ) + m_xWall->addModifyListener( m_xModifyEventForwarder ); + if ( m_xFloor ) + m_xFloor->addModifyListener( m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xTitle, m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xLegend, m_xModifyEventForwarder ); +} + +Diagram::~Diagram() +{ + try + { + for (auto & xSystem : m_aCoordSystems) + xSystem->removeModifyListener(m_xModifyEventForwarder); + + if ( m_xWall ) + m_xWall->removeModifyListener( m_xModifyEventForwarder ); + if ( m_xFloor ) + m_xFloor->removeModifyListener( m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xTitle, m_xModifyEventForwarder ); + ModifyListenerHelper::removeListener( m_xLegend, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XDiagram ____ +uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getWall() +{ + rtl::Reference< Wall > xRet; + bool bAddListener = false; + { + MutexGuard aGuard( m_aMutex ); + if( !m_xWall.is() ) + { + m_xWall.set( new Wall() ); + bAddListener = true; + } + xRet = m_xWall; + } + if(bAddListener) + xRet->addModifyListener( m_xModifyEventForwarder ); + return xRet; +} + +uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getFloor() +{ + rtl::Reference< Wall > xRet; + bool bAddListener = false; + { + MutexGuard aGuard( m_aMutex ); + if( !m_xFloor.is() ) + { + m_xFloor.set( new Wall() ); + bAddListener = true; + } + xRet = m_xFloor; + } + if(bAddListener) + xRet->addModifyListener( m_xModifyEventForwarder ); + return xRet; +} + +uno::Reference< chart2::XLegend > SAL_CALL Diagram::getLegend() +{ + MutexGuard aGuard( m_aMutex ); + return m_xLegend; +} + +void SAL_CALL Diagram::setLegend( const uno::Reference< chart2::XLegend >& xNewLegend ) +{ + auto pLegend = dynamic_cast(xNewLegend.get()); + assert(!xNewLegend || pLegend); + setLegend(rtl::Reference< Legend >(pLegend)); +} + +void Diagram::setLegend( const rtl::Reference< Legend >& xNewLegend ) +{ + rtl::Reference< Legend > xOldLegend; + { + MutexGuard aGuard( m_aMutex ); + if( m_xLegend == xNewLegend ) + return; + xOldLegend = m_xLegend; + m_xLegend = xNewLegend; + } + if( xOldLegend.is()) + ModifyListenerHelper::removeListener( xOldLegend, m_xModifyEventForwarder ); + if( xNewLegend.is()) + ModifyListenerHelper::addListener( xNewLegend, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +Reference< chart2::XColorScheme > SAL_CALL Diagram::getDefaultColorScheme() +{ + Reference< chart2::XColorScheme > xRet; + { + MutexGuard aGuard( m_aMutex ); + xRet = m_xColorScheme; + } + + if( !xRet.is()) + { + xRet.set( createConfigColorScheme( m_xContext )); + MutexGuard aGuard( m_aMutex ); + m_xColorScheme = xRet; + } + return xRet; +} + +void SAL_CALL Diagram::setDefaultColorScheme( const Reference< chart2::XColorScheme >& xColorScheme ) +{ + { + MutexGuard aGuard( m_aMutex ); + m_xColorScheme.set( xColorScheme ); + } + fireModifyEvent(); +} + +void SAL_CALL Diagram::setDiagramData( + const Reference< chart2::data::XDataSource >& xDataSource, + const Sequence< beans::PropertyValue >& aArguments ) +{ + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = new ::chart::ChartTypeManager( m_xContext ); + DiagramHelper::tTemplateWithServiceName aTemplateAndService = DiagramHelper::getTemplateForDiagram( this, xChartTypeManager ); + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( aTemplateAndService.xChartTypeTemplate ); + if( !xTemplate.is() ) + xTemplate = xChartTypeManager->createTemplate( "com.sun.star.chart2.template.Column" ); + if(!xTemplate.is()) + return; + xTemplate->changeDiagramData( rtl::Reference< ::chart::Diagram >(this), xDataSource, aArguments ); +} + +// ____ XTitled ____ +uno::Reference< chart2::XTitle > SAL_CALL Diagram::getTitleObject() +{ + MutexGuard aGuard( m_aMutex ); + return m_xTitle; +} + +void SAL_CALL Diagram::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle ) +{ + Reference< chart2::XTitle > xOldTitle; + { + MutexGuard aGuard( m_aMutex ); + if( m_xTitle == xNewTitle ) + return; + xOldTitle = m_xTitle; + m_xTitle = xNewTitle; + } + if( xOldTitle.is()) + ModifyListenerHelper::removeListener( xOldTitle, m_xModifyEventForwarder ); + if( xNewTitle.is()) + ModifyListenerHelper::addListener( xNewTitle, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ X3DDefaultSetter ____ +void SAL_CALL Diagram::set3DSettingsToDefault() +{ + ThreeDHelper::set3DSettingsToDefault( this ); +} + +void SAL_CALL Diagram::setDefaultRotation() +{ + ThreeDHelper::setDefaultRotation( this ); +} + +void SAL_CALL Diagram::setDefaultIllumination() +{ + ThreeDHelper::setDefaultIllumination( this ); +} + +// ____ XCoordinateSystemContainer ____ +void SAL_CALL Diagram::addCoordinateSystem( + const uno::Reference< chart2::XCoordinateSystem >& aCoordSys ) +{ + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get()); + assert(pCoordSys); + { + MutexGuard aGuard( m_aMutex ); + if( std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys ) + != m_aCoordSystems.end()) + throw lang::IllegalArgumentException("coordsys not found", static_cast(this), 1); + + if( !m_aCoordSystems.empty() ) + { + OSL_FAIL( "more than one coordinatesystem is not supported yet by the fileformat" ); + return; + } + m_aCoordSystems.push_back( pCoordSys ); + } + ModifyListenerHelper::addListener( aCoordSys, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +void SAL_CALL Diagram::removeCoordinateSystem( + const uno::Reference< chart2::XCoordinateSystem >& aCoordSys ) +{ + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get()); + assert(pCoordSys); + { + MutexGuard aGuard( m_aMutex ); + auto aIt = std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys ); + if( aIt == m_aCoordSystems.end()) + throw container::NoSuchElementException( + "The given coordinate-system is no element of the container", + static_cast< uno::XWeak * >( this )); + m_aCoordSystems.erase( aIt ); + } + ModifyListenerHelper::removeListener( aCoordSys, m_xModifyEventForwarder ); + fireModifyEvent(); +} + +uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > SAL_CALL Diagram::getCoordinateSystems() +{ + MutexGuard aGuard( m_aMutex ); + return comphelper::containerToSequence>( m_aCoordSystems ); +} + +void SAL_CALL Diagram::setCoordinateSystems( + const Sequence< Reference< chart2::XCoordinateSystem > >& aCoordinateSystems ) +{ + tCoordinateSystemContainerType aNew; + tCoordinateSystemContainerType aOld; + if( aCoordinateSystems.hasElements() ) + { + OSL_ENSURE( aCoordinateSystems.getLength()<=1, "more than one coordinatesystem is not supported yet by the fileformat" ); + ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordinateSystems[0].get()); + assert(pCoordSys); + aNew.push_back( pCoordSys ); + } + { + MutexGuard aGuard( m_aMutex ); + std::swap( aOld, m_aCoordSystems ); + m_aCoordSystems = aNew; + } + for (auto & xSystem : aOld) + xSystem->removeModifyListener(m_xModifyEventForwarder); + for (auto & xSystem : aNew) + xSystem->addModifyListener(m_xModifyEventForwarder); + fireModifyEvent(); +} + +void Diagram::setCoordinateSystems( + const std::vector< rtl::Reference< BaseCoordinateSystem > >& aCoordinateSystems ) +{ + tCoordinateSystemContainerType aNew; + tCoordinateSystemContainerType aOld; + if( !aCoordinateSystems.empty() ) + { + OSL_ENSURE( aCoordinateSystems.size()<=1, "more than one coordinatesystem is not supported yet by the fileformat" ); + aNew.push_back( aCoordinateSystems[0] ); + } + { + MutexGuard aGuard( m_aMutex ); + std::swap( aOld, m_aCoordSystems ); + m_aCoordSystems = aNew; + } + for (auto & xSystem : aOld) + xSystem->removeModifyListener(m_xModifyEventForwarder); + for (auto & xSystem : aNew) + xSystem->addModifyListener(m_xModifyEventForwarder); + fireModifyEvent(); +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Diagram::createClone() +{ + MutexGuard aGuard( m_aMutex ); + return Reference< util::XCloneable >( new Diagram( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Diagram::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Diagram::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Diagram::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Diagram::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Diagram::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Diagram::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Diagram::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticDiagramDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL Diagram::getInfoHelper() +{ + return StaticDiagramInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Diagram::getPropertySetInfo() +{ + return StaticDiagramInfo(); +} + +// ____ XFastPropertySet ____ +void SAL_CALL Diagram::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) +{ + //special treatment for some 3D properties + if( nHandle == PROP_DIAGRAM_PERSPECTIVE ) + { + sal_Int32 fPerspective = 20; + if( rValue >>=fPerspective ) + ThreeDHelper::setCameraDistance( this, ThreeDHelper::PerspectiveToCameraDistance( fPerspective ) ); + } + else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL + || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL ) + { + sal_Int32 nNewAngleDegree = 0; + if( rValue >>=nNewAngleDegree ) + { + sal_Int32 nHorizontal, nVertical; + ThreeDHelper::getRotationFromDiagram( this, nHorizontal, nVertical ); + if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL ) + nHorizontal = nNewAngleDegree; + else + nVertical = nNewAngleDegree; + ThreeDHelper::setRotationToDiagram( this, nHorizontal, nVertical ); + } + } + else + ::property::OPropertySet::setFastPropertyValue( nHandle, rValue ); +} + +void SAL_CALL Diagram::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + //special treatment for some 3D properties + if( nHandle == PROP_DIAGRAM_PERSPECTIVE ) + { + sal_Int32 nPerspective = ::basegfx::fround( ThreeDHelper::CameraDistanceToPerspective( + ThreeDHelper::getCameraDistance( const_cast< Diagram* >( this ) ) ) ); + rValue <<= nPerspective; + } + else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL + || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL ) + { + sal_Int32 nHorizontal, nVertical; + ThreeDHelper::getRotationFromDiagram( const_cast< Diagram* >( this ), nHorizontal, nVertical ); + sal_Int32 nAngleDegree = 0; + if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL ) + nAngleDegree = nHorizontal; + else + nAngleDegree = nVertical; + rValue <<= nAngleDegree; + } + else + ::property::OPropertySet::getFastPropertyValue( rValue,nHandle ); +} + +using impl::Diagram_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Diagram, Diagram_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Diagram, Diagram_Base, ::property::OPropertySet ) + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Diagram::getImplementationName() +{ + return "com.sun.star.comp.chart2.Diagram"; +} + +sal_Bool SAL_CALL Diagram::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Diagram::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Diagram", + "com.sun.star.layout.LayoutElement", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Diagram_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::Diagram(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/FormattedString.cxx b/chart2/source/model/main/FormattedString.cxx new file mode 100644 index 000000000..69f871ddc --- /dev/null +++ b/chart2/source/model/main/FormattedString.cxx @@ -0,0 +1,300 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "FormattedString.hxx" + +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::osl::MutexGuard; + +namespace +{ + +struct StaticFormattedStringDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + ::chart::CharacterProperties::AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +}; + +struct StaticFormattedStringDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticFormattedStringDefaults_Initializer > +{ +}; + +struct StaticFormattedStringInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticFormattedStringInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticFormattedStringInfoHelper_Initializer > +{ +}; + +struct StaticFormattedStringInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticFormattedStringInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticFormattedStringInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticFormattedStringInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +FormattedString::FormattedString() : + ::property::OPropertySet( m_aMutex ), + m_aType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT), + m_bDataLabelsRange(false), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +FormattedString::FormattedString( const FormattedString & rOther ) : + impl::FormattedString_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_aString( rOther.m_aString ), + m_aType(rOther.m_aType), + m_aGuid(rOther.m_aGuid), + m_bDataLabelsRange(rOther.m_bDataLabelsRange), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +FormattedString::~FormattedString() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL FormattedString::createClone() +{ + return uno::Reference< util::XCloneable >( new FormattedString( *this )); +} + +// ____ XFormattedString ____ +OUString SAL_CALL FormattedString::getString() +{ + MutexGuard aGuard( m_aMutex); + return m_aString; +} + +void SAL_CALL FormattedString::setString( const OUString& String ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aString = String; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); + +} + +// ____ XDataPointCustomLabelField ____ +css::chart2::DataPointCustomLabelFieldType SAL_CALL FormattedString::getFieldType() +{ + MutexGuard aGuard(m_aMutex); + return m_aType; +} + +void SAL_CALL +FormattedString::setFieldType(const css::chart2::DataPointCustomLabelFieldType Type) +{ + { + MutexGuard aGuard(m_aMutex); + m_aType = Type; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +OUString SAL_CALL FormattedString::getGuid() +{ + MutexGuard aGuard( m_aMutex); + return m_aGuid; +} + +void SAL_CALL FormattedString::setGuid( const OUString& guid ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aGuid= guid; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); + +} + +sal_Bool SAL_CALL FormattedString::getDataLabelsRange() +{ + MutexGuard aGuard( m_aMutex); + return m_bDataLabelsRange; +} + +void SAL_CALL FormattedString::setDataLabelsRange( sal_Bool dataLabelsRange ) +{ + { + MutexGuard aGuard( m_aMutex); + m_bDataLabelsRange = dataLabelsRange; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +OUString SAL_CALL FormattedString::getCellRange() +{ + MutexGuard aGuard( m_aMutex); + return m_aCellRange; +} + +void SAL_CALL FormattedString::setCellRange( const OUString& cellRange ) +{ + { + MutexGuard aGuard( m_aMutex); + m_aCellRange = cellRange; + } + //don't keep the mutex locked while calling out + fireModifyEvent(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL FormattedString::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL FormattedString::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL FormattedString::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL FormattedString::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void FormattedString::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void FormattedString::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void FormattedString::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticFormattedStringDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL FormattedString::getInfoHelper() +{ + return *StaticFormattedStringInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL FormattedString::getPropertySetInfo() +{ + return *StaticFormattedStringInfo::get(); +} + +using impl::FormattedString_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( FormattedString, FormattedString_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( FormattedString, FormattedString_Base, ::property::OPropertySet ) + +// do this in derived classes! + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL FormattedString::getImplementationName() +{ + return "com.sun.star.comp.chart.FormattedString"; +} + +sal_Bool SAL_CALL FormattedString::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FormattedString::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.DataPointCustomLabelField", + "com.sun.star.chart2.FormattedString", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_FormattedString_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::FormattedString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/FormattedString.hxx b/chart2/source/model/main/FormattedString.hxx new file mode 100644 index 000000000..878c30015 --- /dev/null +++ b/chart2/source/model/main/FormattedString.hxx @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::chart2::XDataPointCustomLabelField, // inherits from XFormattedString2 + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + FormattedString_Base; +} + +class FormattedString final : + public cppu::BaseMutex, + public impl::FormattedString_Base, + public ::property::OPropertySet +{ +public: + explicit FormattedString(); + virtual ~FormattedString() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + + virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override + { ::property::OPropertySet::setPropertyValue(p1, p2); } + virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override + { return ::property::OPropertySet::getPropertyValue(p1); } + virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ::property::OPropertySet::addPropertyChangeListener(p1, p2); } + virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ::property::OPropertySet::removePropertyChangeListener(p1, p2); } + virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ::property::OPropertySet::addVetoableChangeListener(p1, p2); } + virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ::property::OPropertySet::removeVetoableChangeListener(p1, p2); } + +private: + explicit FormattedString( const FormattedString & rOther ); + + // ____ XFormattedString ____ + virtual OUString SAL_CALL getString() override; + virtual void SAL_CALL setString( const OUString& String ) override; + + // ____ XDataPointCustomLabelField ____ + virtual css::chart2::DataPointCustomLabelFieldType SAL_CALL getFieldType() override; + virtual void SAL_CALL + setFieldType( const css::chart2::DataPointCustomLabelFieldType FieldType ) override; + virtual OUString SAL_CALL getGuid() override; + void SAL_CALL setGuid( const OUString& guid ) override; + virtual sal_Bool SAL_CALL getDataLabelsRange() override; + virtual void SAL_CALL setDataLabelsRange( sal_Bool dataLabelsRange ) override; + virtual OUString SAL_CALL getCellRange() override; + virtual void SAL_CALL setCellRange( const OUString& cellRange ) override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + void fireModifyEvent(); + + // ____ XFormattedString ____ + OUString m_aString; + + // ____ XDataPointCustomLabelField ____ + css::chart2::DataPointCustomLabelFieldType m_aType; + OUString m_aGuid; + OUString m_aCellRange; + bool m_bDataLabelsRange; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/GridProperties.cxx b/chart2/source/model/main/GridProperties.cxx new file mode 100644 index 000000000..7bfb4453e --- /dev/null +++ b/chart2/source/model/main/GridProperties.cxx @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "GridProperties.hxx" +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySetInfo; } +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_GRID_SHOW +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Show", + PROP_GRID_SHOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticGridDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_GRID_SHOW, false ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue< sal_Int32 >( + rOutMap, ::chart::LinePropertiesHelper::PROP_LINE_COLOR, 0xb3b3b3 ); // gray30 + } +}; + +struct StaticGridDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticGridDefaults_Initializer > +{ +}; + +struct StaticGridInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticGridInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticGridInfoHelper_Initializer > +{ +}; + +struct StaticGridInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticGridInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticGridInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticGridInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +GridProperties::GridProperties() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +GridProperties::GridProperties( const GridProperties & rOther ) : + impl::GridProperties_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +GridProperties::~GridProperties() +{} + +// ____ OPropertySet ____ +void GridProperties::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticGridDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL GridProperties::getInfoHelper() +{ + return *StaticGridInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL GridProperties::getPropertySetInfo() +{ + return *StaticGridInfo::get(); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL GridProperties::createClone() +{ + return uno::Reference< util::XCloneable >( new GridProperties( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL GridProperties::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL GridProperties::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL GridProperties::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL GridProperties::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void GridProperties::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL GridProperties::getImplementationName() +{ + return "com.sun.star.comp.chart2.GridProperties"; +} + +sal_Bool SAL_CALL GridProperties::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL GridProperties::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.GridProperties", + "com.sun.star.beans.PropertySet" }; +} + +// needed by MSC compiler +using impl::GridProperties_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( GridProperties, GridProperties_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( GridProperties, GridProperties_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_GridProperties_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::GridProperties); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/GridProperties.hxx b/chart2/source/model/main/GridProperties.hxx new file mode 100644 index 000000000..43ab136c8 --- /dev/null +++ b/chart2/source/model/main/GridProperties.hxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + GridProperties_Base; +} + +class GridProperties final : + public cppu::BaseMutex, + public impl::GridProperties_Base, + public ::property::OPropertySet +{ +public: + explicit GridProperties(); + virtual ~GridProperties() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +private: + explicit GridProperties( const GridProperties & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Legend.cxx b/chart2/source/model/main/Legend.cxx new file mode 100644 index 000000000..8a0676e74 --- /dev/null +++ b/chart2/source/model/main/Legend.cxx @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_LEGEND_ANCHOR_POSITION, + PROP_LEGEND_EXPANSION, + PROP_LEGEND_SHOW, + PROP_LEGEND_OVERLAY, + PROP_LEGEND_REF_PAGE_SIZE, + PROP_LEGEND_REL_POS, + PROP_LEGEND_REL_SIZE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "AnchorPosition", + PROP_LEGEND_ANCHOR_POSITION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Expansion", + PROP_LEGEND_EXPANSION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Show", + PROP_LEGEND_SHOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "Overlay", + PROP_LEGEND_OVERLAY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_LEGEND_REF_PAGE_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativePosition", + PROP_LEGEND_REL_POS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativeSize", + PROP_LEGEND_REL_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + +} + +struct StaticLegendDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + ::chart::CharacterProperties::AddDefaultsToMap( rOutMap ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LEGEND_ANCHOR_POSITION, chart2::LegendPosition_LINE_END ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LEGEND_EXPANSION, css::chart::ChartLegendExpansion_HIGH ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LEGEND_SHOW, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LEGEND_OVERLAY, false ); + + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + } +}; + +struct StaticLegendDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticLegendDefaults_Initializer > +{ +}; + +struct StaticLegendInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticLegendInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticLegendInfoHelper_Initializer > +{ +}; + +struct StaticLegendInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticLegendInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticLegendInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticLegendInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +Legend::Legend() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +Legend::Legend( const Legend & rOther ) : + impl::Legend_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ +} + +Legend::~Legend() +{ +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL Legend::createClone() +{ + return Reference< util::XCloneable >( new Legend( *this )); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Legend::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Legend::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Legend::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Legend::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Legend::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void Legend::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticLegendDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Legend::getInfoHelper() +{ + return *StaticLegendInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL Legend::getPropertySetInfo() +{ + return *StaticLegendInfo::get(); +} + +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +OUString SAL_CALL Legend::getImplementationName() +{ + return "com.sun.star.comp.chart2.Legend"; +} + +sal_Bool SAL_CALL Legend::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Legend::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Legend", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties", + "com.sun.star.layout.LayoutElement" + }; +} + +// needed by MSC compiler +using impl::Legend_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Legend, Legend_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Legend, Legend_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Legend_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::Legend); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PageBackground.cxx b/chart2/source/model/main/PageBackground.cxx new file mode 100644 index 000000000..b61720318 --- /dev/null +++ b/chart2/source/model/main/PageBackground.cxx @@ -0,0 +1,222 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PageBackground.hxx" +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace +{ + +struct StaticPageBackgroundDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue< sal_Int32 >( rOutMap, ::chart::FillProperties::PROP_FILL_COLOR, 0xffffff ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + } +}; + +struct StaticPageBackgroundDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticPageBackgroundDefaults_Initializer > +{ +}; + +struct StaticPageBackgroundInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticPageBackgroundInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticPageBackgroundInfoHelper_Initializer > +{ +}; + +struct StaticPageBackgroundInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticPageBackgroundInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticPageBackgroundInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticPageBackgroundInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +PageBackground::PageBackground() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +PageBackground::PageBackground( const PageBackground & rOther ) : + impl::PageBackground_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +PageBackground::~PageBackground() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL PageBackground::getTypes() +{ + return ::comphelper::concatSequences( + impl::PageBackground_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL PageBackground::createClone() +{ + return uno::Reference< util::XCloneable >( new PageBackground( *this )); +} + +// ____ OPropertySet ____ +void PageBackground::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticPageBackgroundDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL PageBackground::getInfoHelper() +{ + return *StaticPageBackgroundInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL PageBackground::getPropertySetInfo() +{ + return *StaticPageBackgroundInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL PageBackground::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL PageBackground::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL PageBackground::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL PageBackground::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void PageBackground::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +OUString SAL_CALL PageBackground::getImplementationName() +{ + return "com.sun.star.comp.chart2.PageBackground"; +} + +sal_Bool SAL_CALL PageBackground::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PageBackground::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.PageBackground", + "com.sun.star.beans.PropertySet" }; +} + +using impl::PageBackground_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( PageBackground, PageBackground_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PageBackground_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PageBackground ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PageBackground.hxx b/chart2/source/model/main/PageBackground.hxx new file mode 100644 index 000000000..15c32234c --- /dev/null +++ b/chart2/source/model/main/PageBackground.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::lang::XServiceInfo > + PageBackground_Base; +} + +class PageBackground final : + public cppu::BaseMutex, + public impl::PageBackground_Base, + public ::property::OPropertySet +{ +public: + explicit PageBackground(); + virtual ~PageBackground() override; + + /// XServiceInfo declarations + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + + explicit PageBackground( const PageBackground & rOther ); + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/PolarCoordinateSystem.cxx b/chart2/source/model/main/PolarCoordinateSystem.cxx new file mode 100644 index 000000000..5c891989e --- /dev/null +++ b/chart2/source/model/main/PolarCoordinateSystem.cxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +constexpr OUStringLiteral CHART2_COOSYSTEM_POLAR_SERVICE_NAME + = u"com.sun.star.chart2.CoordinateSystems.Polar"; + +} + +namespace chart +{ + +// explicit +PolarCoordinateSystem::PolarCoordinateSystem( sal_Int32 nDimensionCount /* = 2 */ ) : + BaseCoordinateSystem( nDimensionCount ) +{} + +PolarCoordinateSystem::PolarCoordinateSystem( + const PolarCoordinateSystem & rSource ) : + BaseCoordinateSystem( rSource ) +{} + +PolarCoordinateSystem::~PolarCoordinateSystem() +{} + +// ____ XCoordinateSystem ____ +OUString SAL_CALL PolarCoordinateSystem::getCoordinateSystemType() +{ + return CHART2_COOSYSTEM_POLAR_SERVICE_NAME; +} + +OUString SAL_CALL PolarCoordinateSystem::getViewServiceName() +{ + return CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME; +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL PolarCoordinateSystem::createClone() +{ + return Reference< util::XCloneable >( new PolarCoordinateSystem( *this )); +} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem::getImplementationName() +{ + return "com.sun.star.comp.chart.PolarCoordinateSystem"; +} + +sal_Bool SAL_CALL PolarCoordinateSystem::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem::getSupportedServiceNames() +{ + return { CHART2_COOSYSTEM_POLAR_SERVICE_NAME }; +} + +// ==== PolarCoordinateSystem2d ==== + +PolarCoordinateSystem2d::PolarCoordinateSystem2d() : + PolarCoordinateSystem( 2 ) +{} + +PolarCoordinateSystem2d::~PolarCoordinateSystem2d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem2d::getImplementationName() +{ + return "com.sun.star.comp.chart2.PolarCoordinateSystem2d" ; +} + +sal_Bool SAL_CALL PolarCoordinateSystem2d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem2d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_POLAR_SERVICE_NAME, + "com.sun.star.chart2.PolarCoordinateSystem2d" }; +} + +// ==== PolarCoordinateSystem3d ==== + +PolarCoordinateSystem3d::PolarCoordinateSystem3d() : + PolarCoordinateSystem( 3 ) +{} + +PolarCoordinateSystem3d::~PolarCoordinateSystem3d() +{} + +// ____ XServiceInfo ____ +OUString SAL_CALL PolarCoordinateSystem3d::getImplementationName() +{ + return "com.sun.star.comp.chart2.PolarCoordinateSystem3d"; +} + +sal_Bool SAL_CALL PolarCoordinateSystem3d::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolarCoordinateSystem3d::getSupportedServiceNames() +{ + return { + CHART2_COOSYSTEM_POLAR_SERVICE_NAME, + "com.sun.star.chart2.PolarCoordinateSystem3d" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PolarCoordinateSystem2d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PolarCoordinateSystem2d); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PolarCoordinateSystem3d_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PolarCoordinateSystem3d); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/StockBar.cxx b/chart2/source/model/main/StockBar.cxx new file mode 100644 index 000000000..f319478e0 --- /dev/null +++ b/chart2/source/model/main/StockBar.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::beans { class XPropertySetInfo; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; + +namespace +{ + +struct StaticStockBarInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticStockBarInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticStockBarInfoHelper_Initializer > +{ +}; + +struct StaticStockBarInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticStockBarInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticStockBarInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticStockBarInfo_Initializer > +{ +}; + +struct StaticStockBarDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue< sal_Int32 >( rOutMap, ::chart::FillProperties::PROP_FILL_COLOR, 0xffffff ); // white + } +}; + +struct StaticStockBarDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticStockBarDefaults_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +StockBar::StockBar( bool bRisingCourse ) : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + if( ! bRisingCourse ) + { + setFastPropertyValue_NoBroadcast( + ::chart::FillProperties::PROP_FILL_COLOR, + uno::Any( sal_Int32( 0x000000 ))); // black + setFastPropertyValue_NoBroadcast( + ::chart::LinePropertiesHelper::PROP_LINE_COLOR, + uno::Any( sal_Int32( 0xb3b3b3 ))); // gray30 + } +} + +StockBar::StockBar( const StockBar & rOther ) : + impl::StockBar_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +StockBar::~StockBar() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL StockBar::getTypes() +{ + return ::comphelper::concatSequences( + impl::StockBar_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL StockBar::createClone() +{ + return uno::Reference< util::XCloneable >( new StockBar( *this )); +} + +// ____ OPropertySet ____ +void StockBar::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticStockBarDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL StockBar::getInfoHelper() +{ + return *StaticStockBarInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL StockBar::getPropertySetInfo() +{ + return *StaticStockBarInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL StockBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL StockBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL StockBar::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL StockBar::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void StockBar::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::StockBar_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( StockBar, StockBar_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Title.cxx b/chart2/source/model/main/Title.cxx new file mode 100644 index 000000000..98004e30a --- /dev/null +++ b/chart2/source/model/main/Title.cxx @@ -0,0 +1,374 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans::PropertyAttribute; + +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_TITLE_PARA_ADJUST, + PROP_TITLE_PARA_LAST_LINE_ADJUST, + PROP_TITLE_PARA_LEFT_MARGIN, + PROP_TITLE_PARA_RIGHT_MARGIN, + PROP_TITLE_PARA_TOP_MARGIN, + PROP_TITLE_PARA_BOTTOM_MARGIN, + PROP_TITLE_PARA_IS_HYPHENATION, + PROP_TITLE_VISIBLE, + + PROP_TITLE_TEXT_ROTATION, + PROP_TITLE_TEXT_STACKED, + PROP_TITLE_REL_POS, + + PROP_TITLE_REF_PAGE_SIZE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ParaAdjust", + PROP_TITLE_PARA_ADJUST, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaLastLineAdjust", + PROP_TITLE_PARA_LAST_LINE_ADJUST, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaLeftMargin", + PROP_TITLE_PARA_LEFT_MARGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaRightMargin", + PROP_TITLE_PARA_RIGHT_MARGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaTopMargin", + PROP_TITLE_PARA_TOP_MARGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaBottomMargin", + PROP_TITLE_PARA_BOTTOM_MARGIN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaIsHyphenation", + PROP_TITLE_PARA_IS_HYPHENATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + + rOutProperties.emplace_back( "Visible", + PROP_TITLE_VISIBLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "TextRotation", + PROP_TITLE_TEXT_ROTATION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "StackCharacters", + PROP_TITLE_TEXT_STACKED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "RelativePosition", + PROP_TITLE_REL_POS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_TITLE_REF_PAGE_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +struct StaticTitleDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + + // ParagraphProperties + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_TITLE_PARA_ADJUST, + css::style::ParagraphAdjust_CENTER ); + // PROP_TITLE_PARA_LAST_LINE_ADJUST + + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_TITLE_PARA_LEFT_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_TITLE_PARA_RIGHT_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_TITLE_PARA_TOP_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_TITLE_PARA_BOTTOM_MARGIN, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_TITLE_PARA_IS_HYPHENATION, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_TITLE_VISIBLE, true ); + + // own properties + ::chart::PropertyHelper::setPropertyValueDefault< double >( rOutMap, PROP_TITLE_TEXT_ROTATION, 0.0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_TITLE_TEXT_STACKED, false ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::FillProperties::PROP_FILL_STYLE, drawing::FillStyle_NONE ); + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + } +}; + +struct StaticTitleDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticTitleDefaults_Initializer > +{ +}; + +struct StaticTitleInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticTitleInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticTitleInfoHelper_Initializer > +{ +}; + +struct StaticTitleInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticTitleInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticTitleInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticTitleInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +Title::Title() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Title::Title( const Title & rOther ) : + impl::Title_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + CloneHelper::CloneRefSequence( + rOther.m_aStrings, m_aStrings ); + ModifyListenerHelper::addListenerToAllElements( + comphelper::sequenceToContainer > >( m_aStrings ), + m_xModifyEventForwarder ); +} + +Title::~Title() +{ + ModifyListenerHelper::removeListenerFromAllElements( + comphelper::sequenceToContainer > >( m_aStrings ), + m_xModifyEventForwarder ); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL Title::createClone() +{ + return uno::Reference< util::XCloneable >( new Title( *this )); +} + +// ____ XTitle ____ +uno::Sequence< uno::Reference< chart2::XFormattedString > > SAL_CALL Title::getText() +{ + MutexGuard aGuard( m_aMutex ); + return m_aStrings; +} + +void SAL_CALL Title::setText( const uno::Sequence< uno::Reference< chart2::XFormattedString > >& rNewStrings ) +{ + uno::Sequence< uno::Reference< chart2::XFormattedString > > aOldStrings; + { + MutexGuard aGuard( m_aMutex ); + std::swap( m_aStrings, aOldStrings ); + m_aStrings = rNewStrings; + } + //don't keep the mutex locked while calling out + ModifyListenerHelper::removeListenerFromAllElements( + comphelper::sequenceToContainer > >( aOldStrings ), + m_xModifyEventForwarder ); + ModifyListenerHelper::addListenerToAllElements( + comphelper::sequenceToContainer > >( rNewStrings ), + m_xModifyEventForwarder ); + fireModifyEvent(); +} + +// ____ OPropertySet ____ +void Title::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticTitleDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Title::getInfoHelper() +{ + return *StaticTitleInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Title::getPropertySetInfo() +{ + return *StaticTitleInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Title::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Title::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Title::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Title::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Title::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void Title::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +OUString SAL_CALL Title::getImplementationName() +{ + return "com.sun.star.comp.chart2.Title"; +} + +sal_Bool SAL_CALL Title::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL Title::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.Title", + "com.sun.star.style.ParagraphProperties", + "com.sun.star.beans.PropertySet", + "com.sun.star.layout.LayoutElement" }; +} + +// needed by MSC compiler +using impl::Title_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Title, Title_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( Title, Title_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_Title_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::Title); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/UndoManager.cxx b/chart2/source/model/main/UndoManager.cxx new file mode 100644 index 000000000..63dacf484 --- /dev/null +++ b/chart2/source/model/main/UndoManager.cxx @@ -0,0 +1,349 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "UndoManager.hxx" +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace chart +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::document::XUndoAction; + using ::com::sun::star::document::XUndoManagerListener; + using ::com::sun::star::lang::NoSupportException; + using ::com::sun::star::util::XModifyListener; + using ::com::sun::star::frame::XModel; + + namespace impl + { + class UndoManager_Impl : public ::framework::IUndoManagerImplementation + { + public: + UndoManager_Impl( UndoManager& i_antiImpl, ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :m_rAntiImpl( i_antiImpl ) + ,m_rParent( i_parent ) + ,m_rMutex( i_mutex ) + ,m_bDisposed( false ) + ,m_aUndoHelper( *this ) + { + m_aUndoManager.SetMaxUndoActionCount( + officecfg::Office::Common::Undo::Steps::get()); + } + + virtual ~UndoManager_Impl() + { + } + + ::osl::Mutex& getMutex(); + // IUndoManagerImplementation + virtual SfxUndoManager& getImplUndoManager() override; + virtual Reference< XUndoManager > getThis() override; + + // attribute access + ::cppu::OWeakObject& getParent() { return m_rParent; } + ::framework::UndoManagerHelper& getUndoHelper() { return m_aUndoHelper; } + + // public interface + + /// is called when the owner of the UndoManager is being disposed + void disposing(); + + /// checks whether we're already disposed, throws a DisposedException if so + void checkDisposed_lck(); + + private: + UndoManager& m_rAntiImpl; + ::cppu::OWeakObject& m_rParent; + ::osl::Mutex& m_rMutex; + bool m_bDisposed; + + SfxUndoManager m_aUndoManager; + ::framework::UndoManagerHelper m_aUndoHelper; + }; + + ::osl::Mutex& UndoManager_Impl::getMutex() + { + return m_rMutex; + } + + SfxUndoManager& UndoManager_Impl::getImplUndoManager() + { + return m_aUndoManager; + } + + Reference< XUndoManager > UndoManager_Impl::getThis() + { + return &m_rAntiImpl; + } + + void UndoManager_Impl::disposing() + { + { + ::osl::MutexGuard aGuard( m_rMutex ); + m_bDisposed = true; + } + m_aUndoHelper.disposing(); + } + + void UndoManager_Impl::checkDisposed_lck() + { + if ( m_bDisposed ) + throw DisposedException( OUString(), getThis() ); + } + + namespace { + + /** guard for public UNO methods of the UndoManager + + The only purpose of this guard is to check for the instance being disposed already. Everything else, + in particular the IMutexGuard functionality required by the UndoManagerHelper class, is a dummy only, + as all involved classes (means we ourselves, the UndoManagerHelper, the SfxUndoManager, and the Undo actions + we create) are inherently thread-safe, thus need no external lock (in particular no SolarMutex!). + */ + class UndoManagerMethodGuard : public ::framework::IMutexGuard + { + public: + explicit UndoManagerMethodGuard( UndoManager_Impl& i_impl ) + { + ::osl::MutexGuard aGuard( i_impl.getMutex() ); + // throw if the instance is already disposed + i_impl.checkDisposed_lck(); + } + virtual ~UndoManagerMethodGuard() + { + } + + // IMutexGuard + virtual void clear() override; + virtual ::framework::IMutex& getGuardedMutex() override; + }; + + class DummyMutex : public ::framework::IMutex + { + public: + virtual ~DummyMutex() {} + virtual void acquire() override { } + virtual void release() override { } + }; + + } + + ::framework::IMutex& UndoManagerMethodGuard::getGuardedMutex() + { + static DummyMutex s_aDummyMutex; + return s_aDummyMutex; + } + + void UndoManagerMethodGuard::clear() + { + // nothing to do. This interface implementation is a dummy. + } + } + + using impl::UndoManagerMethodGuard; + + UndoManager::UndoManager( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + :m_pImpl( new impl::UndoManager_Impl( *this, i_parent, i_mutex ) ) + { + } + + UndoManager::~UndoManager() + { + } + + void SAL_CALL UndoManager::acquire() noexcept + { + m_pImpl->getParent().acquire(); + } + + void SAL_CALL UndoManager::release() noexcept + { + m_pImpl->getParent().release(); + } + + void UndoManager::disposing() + { + m_pImpl->disposing(); + } + + void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().enterUndoContext( i_title, aGuard ); + } + + void SAL_CALL UndoManager::enterHiddenUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().enterHiddenUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::leaveUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().leaveUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addUndoAction( i_action, aGuard ); + } + + void SAL_CALL UndoManager::undo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().undo( aGuard ); + + ChartViewHelper::setViewToDirtyState( Reference< XModel >( getParent(), UNO_QUERY ) ); + } + + void SAL_CALL UndoManager::redo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().redo( aGuard ); + + ChartViewHelper::setViewToDirtyState( Reference< XModel >( getParent(), UNO_QUERY ) ); + } + + sal_Bool SAL_CALL UndoManager::isUndoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isUndoPossible(); + } + + sal_Bool SAL_CALL UndoManager::isRedoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isRedoPossible(); + } + + OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getCurrentUndoActionTitle(); + } + + OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getCurrentRedoActionTitle(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getAllUndoActionTitles(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().getAllRedoActionTitles(); + } + + void SAL_CALL UndoManager::clear( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().clear( aGuard ); + } + + void SAL_CALL UndoManager::clearRedo( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().clearRedo( aGuard ); + } + + void SAL_CALL UndoManager::reset( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().reset( aGuard ); + } + + void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().removeUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::lock( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().lock(); + } + + void SAL_CALL UndoManager::unlock( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().unlock(); + } + + sal_Bool SAL_CALL UndoManager::isLocked( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getUndoHelper().isLocked(); + } + + Reference< XInterface > SAL_CALL UndoManager::getParent( ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + return m_pImpl->getParent(); + } + + void SAL_CALL UndoManager::setParent( const Reference< XInterface >& ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + throw NoSupportException( OUString(), m_pImpl->getThis() ); + } + + void SAL_CALL UndoManager::addModifyListener( const Reference< XModifyListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().addModifyListener( i_listener ); + } + + void SAL_CALL UndoManager::removeModifyListener( const Reference< XModifyListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_pImpl ); + m_pImpl->getUndoHelper().removeModifyListener( i_listener ); + } + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/UndoManager.hxx b/chart2/source/model/main/UndoManager.hxx new file mode 100644 index 000000000..4d0a214e5 --- /dev/null +++ b/chart2/source/model/main/UndoManager.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace chart +{ + + namespace impl + { + class UndoManager_Impl; + typedef ::cppu::ImplHelper2 < css::document::XUndoManager + , css::util::XModifyBroadcaster + > UndoManager_Base; + } + + class UndoManager : public impl::UndoManager_Base + { + public: + UndoManager( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ); + virtual ~UndoManager(); + + // XInterface + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + // XComponent equivalents + void disposing(); + + // XUndoManager + virtual void SAL_CALL enterUndoContext( const OUString& i_title ) override; + virtual void SAL_CALL enterHiddenUndoContext( ) override; + virtual void SAL_CALL leaveUndoContext( ) override; + virtual void SAL_CALL addUndoAction( const css::uno::Reference< css::document::XUndoAction >& i_action ) override; + virtual void SAL_CALL undo( ) override; + virtual void SAL_CALL redo( ) override; + virtual sal_Bool SAL_CALL isUndoPossible( ) override; + virtual sal_Bool SAL_CALL isRedoPossible( ) override; + virtual OUString SAL_CALL getCurrentUndoActionTitle( ) override; + virtual OUString SAL_CALL getCurrentRedoActionTitle( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAllUndoActionTitles( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getAllRedoActionTitles( ) override; + virtual void SAL_CALL clear( ) override; + virtual void SAL_CALL clearRedo( ) override; + virtual void SAL_CALL reset( ) override; + virtual void SAL_CALL addUndoManagerListener( const css::uno::Reference< css::document::XUndoManagerListener >& i_listener ) override; + virtual void SAL_CALL removeUndoManagerListener( const css::uno::Reference< css::document::XUndoManagerListener >& i_listener ) override; + + // XLockable (base of XUndoManager) + virtual void SAL_CALL lock( ) override; + virtual void SAL_CALL unlock( ) override; + virtual sal_Bool SAL_CALL isLocked( ) override; + + // XChild (base of XUndoManager) + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override; + virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + private: + std::unique_ptr< impl::UndoManager_Impl > m_pImpl; + }; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Wall.cxx b/chart2/source/model/main/Wall.cxx new file mode 100644 index 000000000..f139a3e9d --- /dev/null +++ b/chart2/source/model/main/Wall.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Wall.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace +{ + +struct StaticWallDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::LinePropertiesHelper::AddDefaultsToMap( rOutMap ); + ::chart::FillProperties::AddDefaultsToMap( rOutMap ); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue( rOutMap, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + } +}; + +struct StaticWallDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticWallDefaults_Initializer > +{ +}; + +struct StaticWallInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticWallInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticWallInfoHelper_Initializer > +{ +}; + +struct StaticWallInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticWallInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticWallInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticWallInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +Wall::Wall() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Wall::Wall( const Wall & rOther ) : + impl::Wall_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +Wall::~Wall() +{} + +// ____ XTypeProvider ____ +uno::Sequence< css::uno::Type > SAL_CALL Wall::getTypes() +{ + return ::comphelper::concatSequences( + impl::Wall_Base::getTypes(), + ::property::OPropertySet::getTypes()); +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL Wall::createClone() +{ + return uno::Reference< util::XCloneable >( new Wall( *this )); +} + +// ____ OPropertySet ____ +void Wall::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticWallDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL Wall::getInfoHelper() +{ + return *StaticWallInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL Wall::getPropertySetInfo() +{ + return *StaticWallInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL Wall::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL Wall::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL Wall::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL Wall::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void Wall::firePropertyChangeEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::Wall_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( Wall, Wall_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/main/Wall.hxx b/chart2/source/model/main/Wall.hxx new file mode 100644 index 000000000..696772438 --- /dev/null +++ b/chart2/source/model/main/Wall.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener > + Wall_Base; +} + +class Wall final : + public cppu::BaseMutex, + public impl::Wall_Base, + public ::property::OPropertySet +{ +public: + Wall(); + virtual ~Wall() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + + explicit Wall( const Wall & rOther ); + + // ____ XTypeProvider ____ + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + +private: + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + using OPropertySet::disposing; + +private: + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/AreaChartType.cxx b/chart2/source/model/template/AreaChartType.cxx new file mode 100644 index 000000000..b0581ddc8 --- /dev/null +++ b/chart2/source/model/template/AreaChartType.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AreaChartType.hxx" +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +namespace chart +{ + +AreaChartType::AreaChartType() +{} + +AreaChartType::AreaChartType( const AreaChartType & rOther ) : + ChartType( rOther ) +{} + +AreaChartType::~AreaChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL AreaChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new AreaChartType( *this )); +} + +rtl::Reference< ChartType > AreaChartType::cloneChartType() const +{ + return new AreaChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL AreaChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_AREA; +} + +OUString SAL_CALL AreaChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.AreaChartType"; +} + +sal_Bool SAL_CALL AreaChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL AreaChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_AREA, + "com.sun.star.chart2.ChartType" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_AreaChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::AreaChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/AreaChartType.hxx b/chart2/source/model/template/AreaChartType.hxx new file mode 100644 index 000000000..8ca01e1f3 --- /dev/null +++ b/chart2/source/model/template/AreaChartType.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class AreaChartType final : public ChartType +{ +public: + explicit AreaChartType(); + virtual ~AreaChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit AreaChartType( const AreaChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/AreaChartTypeTemplate.cxx b/chart2/source/model/template/AreaChartTypeTemplate.cxx new file mode 100644 index 000000000..32df26a18 --- /dev/null +++ b/chart2/source/model/template/AreaChartTypeTemplate.cxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AreaChartTypeTemplate.hxx" +#include "AreaChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +enum +{ + PROP_AREA_TEMPLATE_DIMENSION +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Dimension", + PROP_AREA_TEMPLATE_DIMENSION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticAreaChartTypeTemplateDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aStaticDefaults, PROP_AREA_TEMPLATE_DIMENSION, 2 ); + return &aStaticDefaults; + } +}; + +struct StaticAreaChartTypeTemplateDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticAreaChartTypeTemplateDefaults_Initializer > +{ +}; + +struct StaticAreaChartTypeTemplateInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static uno::Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticAreaChartTypeTemplateInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticAreaChartTypeTemplateInfoHelper_Initializer > +{ +}; + +struct StaticAreaChartTypeTemplateInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticAreaChartTypeTemplateInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticAreaChartTypeTemplateInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticAreaChartTypeTemplateInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +AreaChartTypeTemplate::AreaChartTypeTemplate( + uno::Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + sal_Int32 nDim /* = 2 */ ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_eStackMode( eStackMode ) +{ + setFastPropertyValue_NoBroadcast( PROP_AREA_TEMPLATE_DIMENSION, uno::Any( nDim )); +} + +AreaChartTypeTemplate::~AreaChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void AreaChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticAreaChartTypeTemplateDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL AreaChartTypeTemplate::getInfoHelper() +{ + return *StaticAreaChartTypeTemplateInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL AreaChartTypeTemplate::getPropertySetInfo() +{ + return *StaticAreaChartTypeTemplateInfo::get(); +} + +sal_Int32 AreaChartTypeTemplate::getDimension() const +{ + sal_Int32 nDim = 2; + try + { + // note: UNO-methods are never const + const_cast< AreaChartTypeTemplate * >( this )-> + getFastPropertyValue( PROP_AREA_TEMPLATE_DIMENSION ) >>= nDim; + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nDim; +} + +StackMode AreaChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return m_eStackMode; +} + +// ____ ChartTypeTemplate ____ +void AreaChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); +} + +void AreaChartTypeTemplate::resetStyles2( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + ChartTypeTemplate::resetStyles2( xDiagram ); + std::vector< rtl::Reference< ::chart::DataSeries > > aSeriesVec( + DiagramHelper::getDataSeriesFromDiagram( xDiagram )); + uno::Any aLineStyleAny( drawing::LineStyle_NONE ); + for (auto const& series : aSeriesVec) + { + if( series->getPropertyValue( "BorderStyle") == aLineStyleAny ) + { + series->setPropertyToDefault( "BorderStyle"); + } + } +} + +rtl::Reference< ChartType > AreaChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + return new AreaChartType(); +} + +rtl::Reference< ChartType > AreaChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult( getChartTypeForIndex( 0 ) ); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + return xResult; +} + +IMPLEMENT_FORWARD_XINTERFACE2( AreaChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( AreaChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/AreaChartTypeTemplate.hxx b/chart2/source/model/template/AreaChartTypeTemplate.hxx new file mode 100644 index 000000000..3116c0d59 --- /dev/null +++ b/chart2/source/model/template/AreaChartTypeTemplate.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include + +namespace chart +{ + +class AreaChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + explicit AreaChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + sal_Int32 nDim = 2 ); + virtual ~AreaChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual void resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) override; + + // ____ ChartTypeTemplate ____ + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual sal_Int32 getDimension() const override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + +private: + StackMode m_eStackMode; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BarChartType.cxx b/chart2/source/model/template/BarChartType.cxx new file mode 100644 index 000000000..2a94db82b --- /dev/null +++ b/chart2/source/model/template/BarChartType.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BarChartType.hxx" +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +namespace chart +{ + +BarChartType::BarChartType() +{} + +BarChartType::BarChartType( const BarChartType & rOther ) : + ChartType( rOther ) +{ +} + +BarChartType::~BarChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL BarChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new BarChartType( *this )); +} + +rtl::Reference< ChartType > BarChartType::cloneChartType() const +{ + return new BarChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL BarChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_BAR; +} + +uno::Sequence< OUString > BarChartType::getSupportedPropertyRoles() +{ + return { "FillColor", "BorderColor" }; +} + +OUString SAL_CALL BarChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.BarChartType"; +} + +sal_Bool SAL_CALL BarChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL BarChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_BAR, + "com.sun.star.chart2.ChartType" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_BarChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::BarChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BarChartType.hxx b/chart2/source/model/template/BarChartType.hxx new file mode 100644 index 000000000..cceaf0577 --- /dev/null +++ b/chart2/source/model/template/BarChartType.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class BarChartType final : public ChartType +{ +public: + explicit BarChartType(); + virtual ~BarChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit BarChartType( const BarChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedPropertyRoles() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BarChartTypeTemplate.cxx b/chart2/source/model/template/BarChartTypeTemplate.cxx new file mode 100644 index 000000000..0c3ca6566 --- /dev/null +++ b/chart2/source/model/template/BarChartTypeTemplate.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BarChartTypeTemplate.hxx" +#include "ColumnChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_BAR_TEMPLATE_DIMENSION, + PROP_BAR_TEMPLATE_GEOMETRY3D +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Dimension", + PROP_BAR_TEMPLATE_DIMENSION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Geometry3D", + PROP_BAR_TEMPLATE_GEOMETRY3D, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticBarChartTypeTemplateDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_BAR_TEMPLATE_DIMENSION, 2 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_BAR_TEMPLATE_GEOMETRY3D, ::chart2::DataPointGeometry3D::CUBOID ); + } +}; + +struct StaticBarChartTypeTemplateDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticBarChartTypeTemplateDefaults_Initializer > +{ +}; + +struct StaticBarChartTypeTemplateInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticBarChartTypeTemplateInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticBarChartTypeTemplateInfoHelper_Initializer > +{ +}; + +struct StaticBarChartTypeTemplateInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticBarChartTypeTemplateInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticBarChartTypeTemplateInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticBarChartTypeTemplateInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +BarChartTypeTemplate::BarChartTypeTemplate( + Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + BarDirection eDirection, + sal_Int32 nDim /* = 2 */ ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_eStackMode( eStackMode ), + m_eBarDirection( eDirection ), + m_nDim( nDim ) +{} + +BarChartTypeTemplate::~BarChartTypeTemplate() +{} + +sal_Int32 BarChartTypeTemplate::getDimension() const +{ + return m_nDim; +} + +StackMode BarChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return m_eStackMode; +} + +bool BarChartTypeTemplate::isSwapXAndY() const +{ + return (m_eBarDirection == HORIZONTAL); +} + +// ____ ChartTypeTemplate ____ +bool BarChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = ChartTypeTemplate::matchesTemplate2( xDiagram, bAdaptProperties ); + + //check BarDirection + if( bResult ) + { + bool bFound = false; + bool bAmbiguous = false; + bool bVertical = DiagramHelper::getVertical( xDiagram, bFound, bAmbiguous ); + if( m_eBarDirection == HORIZONTAL ) + bResult = bVertical; + else if( m_eBarDirection == VERTICAL ) + bResult = !bVertical; + } + + // adapt solid-type of template according to values in series + if( bAdaptProperties && + bResult && + getDimension() == 3 ) + { + + bool bGeomFound = false, bGeomAmbiguous = false; + sal_Int32 aCommonGeom = DiagramHelper::getGeometry3D( xDiagram, bGeomFound, bGeomAmbiguous ); + + if( !bGeomAmbiguous ) + { + setFastPropertyValue_NoBroadcast( + PROP_BAR_TEMPLATE_GEOMETRY3D, uno::Any( aCommonGeom )); + } + } + + return bResult; +} + +rtl::Reference< ChartType > BarChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + return new ColumnChartType(); +} + +rtl::Reference< ChartType > BarChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult( getChartTypeForIndex( 0 ) ); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + return xResult; +} + +// ____ OPropertySet ____ +void BarChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticBarChartTypeTemplateDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL BarChartTypeTemplate::getInfoHelper() +{ + return *StaticBarChartTypeTemplateInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL BarChartTypeTemplate::getPropertySetInfo() +{ + return *StaticBarChartTypeTemplateInfo::get(); +} + +void BarChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); + if( getDimension() != 3 ) + return; + + try + { + //apply Geometry3D + uno::Any aAGeometry3D; + getFastPropertyValue( aAGeometry3D, PROP_BAR_TEMPLATE_GEOMETRY3D ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "Geometry3D", aAGeometry3D ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void BarChartTypeTemplate::resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + ChartTypeTemplate::resetStyles2( xDiagram ); + std::vector< rtl::Reference< DataSeries > > aSeriesVec( + DiagramHelper::getDataSeriesFromDiagram( xDiagram )); + uno::Any aLineStyleAny( drawing::LineStyle_NONE ); + for (auto const& series : aSeriesVec) + { + if( getDimension() == 3 ) + series->setPropertyToDefault( "Geometry3D"); + if( series->getPropertyValue( "BorderStyle") == aLineStyleAny ) + { + series->setPropertyToDefault( "BorderStyle"); + } + } + + DiagramHelper::setVertical( xDiagram, false ); +} + +void BarChartTypeTemplate::createCoordinateSystems( + const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + ChartTypeTemplate::createCoordinateSystems( xDiagram ); + + DiagramHelper::setVertical( xDiagram, m_eBarDirection == HORIZONTAL ); +} + +IMPLEMENT_FORWARD_XINTERFACE2( BarChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( BarChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BarChartTypeTemplate.hxx b/chart2/source/model/template/BarChartTypeTemplate.hxx new file mode 100644 index 000000000..62188279e --- /dev/null +++ b/chart2/source/model/template/BarChartTypeTemplate.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace chart +{ + +class BarChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + enum BarDirection + { + HORIZONTAL, + VERTICAL + }; + + explicit BarChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + BarDirection eDirection, + sal_Int32 nDim = 2 ); + virtual ~BarChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual void resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual sal_Int32 getDimension() const override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + virtual bool isSwapXAndY() const override; + + virtual void createCoordinateSystems( + const rtl::Reference< ::chart::Diagram > & xDiagram ) override; + +private: + StackMode m_eStackMode; + BarDirection m_eBarDirection; + sal_Int32 m_nDim; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleChartType.cxx b/chart2/source/model/template/BubbleChartType.cxx new file mode 100644 index 000000000..3521f7909 --- /dev/null +++ b/chart2/source/model/template/BubbleChartType.cxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BubbleChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +struct StaticBubbleChartTypeDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + return &aStaticDefaults; + } +}; + +struct StaticBubbleChartTypeDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticBubbleChartTypeDefaults_Initializer > +{ +}; + +struct StaticBubbleChartTypeInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } +}; + +struct StaticBubbleChartTypeInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticBubbleChartTypeInfoHelper_Initializer > +{ +}; + +struct StaticBubbleChartTypeInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticBubbleChartTypeInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticBubbleChartTypeInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticBubbleChartTypeInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +BubbleChartType::BubbleChartType() +{ +} + +BubbleChartType::BubbleChartType( const BubbleChartType & rOther ) : + ChartType( rOther ) +{ +} + +BubbleChartType::~BubbleChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL BubbleChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new BubbleChartType( *this )); +} + +rtl::Reference< ChartType > BubbleChartType::cloneChartType() const +{ + return new BubbleChartType( *this ); +} + +// ____ XChartType ____ +rtl::Reference< ::chart::BaseCoordinateSystem > + BubbleChartType::createCoordinateSystem2( sal_Int32 DimensionCount ) +{ + rtl::Reference< CartesianCoordinateSystem > xResult = + new CartesianCoordinateSystem( DimensionCount ); + + for( sal_Int32 i=0; i xAxis = xResult->getAxisByDimension2( i, MAIN_AXIS_INDEX ); + if( !xAxis.is() ) + { + OSL_FAIL("a created coordinate system should have an axis for each dimension"); + continue; + } + + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + aScaleData.Scaling = AxisHelper::createLinearScaling(); + + if( i == 2 ) + aScaleData.AxisType = chart2::AxisType::SERIES; + else + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + + xAxis->setScaleData( aScaleData ); + } + + return xResult; +} + +OUString SAL_CALL BubbleChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE; +} + +uno::Sequence< OUString > SAL_CALL BubbleChartType::getSupportedMandatoryRoles() +{ + return { "label", "values-x", "values-y", "values-size" }; +} + +uno::Sequence< OUString > SAL_CALL BubbleChartType::getSupportedPropertyRoles() +{ + return { "FillColor", "BorderColor" }; +} + +OUString SAL_CALL BubbleChartType::getRoleOfSequenceForSeriesLabel() +{ + return "values-size"; +} + +// ____ OPropertySet ____ +void BubbleChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticBubbleChartTypeDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL BubbleChartType::getInfoHelper() +{ + return *StaticBubbleChartTypeInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL BubbleChartType::getPropertySetInfo() +{ + return *StaticBubbleChartTypeInfo::get(); +} + +OUString SAL_CALL BubbleChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.BubbleChartType"; +} + +sal_Bool SAL_CALL BubbleChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL BubbleChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_BubbleChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::BubbleChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleChartType.hxx b/chart2/source/model/template/BubbleChartType.hxx new file mode 100644 index 000000000..a2afa7e69 --- /dev/null +++ b/chart2/source/model/template/BubbleChartType.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class BubbleChartType final : public ChartType +{ +public: + explicit BubbleChartType(); + virtual ~BubbleChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit BubbleChartType( const BubbleChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedMandatoryRoles() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedPropertyRoles() override; + virtual OUString SAL_CALL getRoleOfSequenceForSeriesLabel() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + virtual rtl::Reference< ::chart::BaseCoordinateSystem > + createCoordinateSystem2( sal_Int32 DimensionCount ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleChartTypeTemplate.cxx b/chart2/source/model/template/BubbleChartTypeTemplate.cxx new file mode 100644 index 000000000..b09c9b9da --- /dev/null +++ b/chart2/source/model/template/BubbleChartTypeTemplate.cxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BubbleChartTypeTemplate.hxx" +#include "BubbleChartType.hxx" +#include "BubbleDataInterpreter.hxx" +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +struct StaticBubbleChartTypeTemplateDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + return &aStaticDefaults; + } +}; + +struct StaticBubbleChartTypeTemplateDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticBubbleChartTypeTemplateDefaults_Initializer > +{ +}; + +struct StaticBubbleChartTypeTemplateInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticBubbleChartTypeTemplateInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticBubbleChartTypeTemplateInfoHelper_Initializer > +{ +}; + +struct StaticBubbleChartTypeTemplateInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticBubbleChartTypeTemplateInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticBubbleChartTypeTemplateInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticBubbleChartTypeTemplateInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +BubbleChartTypeTemplate::BubbleChartTypeTemplate( + Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ) +{ +} + +BubbleChartTypeTemplate::~BubbleChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void BubbleChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticBubbleChartTypeTemplateDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL BubbleChartTypeTemplate::getInfoHelper() +{ + return *StaticBubbleChartTypeTemplateInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL BubbleChartTypeTemplate::getPropertySetInfo() +{ + return *StaticBubbleChartTypeTemplateInfo::get(); +} + +sal_Int32 BubbleChartTypeTemplate::getDimension() const +{ + return 2; +} + +StackMode BubbleChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return StackMode::NONE; +} + +void BubbleChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); +} + +// ____ XChartTypeTemplate ____ +sal_Bool SAL_CALL BubbleChartTypeTemplate::supportsCategories() +{ + return false; +} + +rtl::Reference< ChartType > BubbleChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + return new BubbleChartType(); +} + +rtl::Reference< ChartType > BubbleChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new BubbleChartType(); + + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< DataInterpreter > BubbleChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new BubbleDataInterpreter ); + + return m_xDataInterpreter; +} + +IMPLEMENT_FORWARD_XINTERFACE2( BubbleChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( BubbleChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleChartTypeTemplate.hxx b/chart2/source/model/template/BubbleChartTypeTemplate.hxx new file mode 100644 index 000000000..f4e5c9b3c --- /dev/null +++ b/chart2/source/model/template/BubbleChartTypeTemplate.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +class BubbleChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + explicit BubbleChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName ); + virtual ~BubbleChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual sal_Bool SAL_CALL supportsCategories() override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual rtl::Reference< ::chart::DataInterpreter > getDataInterpreter2() override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + + // ____ ChartTypeTemplate ____ + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual sal_Int32 getDimension() const override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleDataInterpreter.cxx b/chart2/source/model/template/BubbleDataInterpreter.cxx new file mode 100644 index 000000000..7243b43aa --- /dev/null +++ b/chart2/source/model/template/BubbleDataInterpreter.cxx @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "BubbleDataInterpreter.hxx" +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +BubbleDataInterpreter::BubbleDataInterpreter() +{ +} + +BubbleDataInterpreter::~BubbleDataInterpreter() +{ +} + +// ____ XDataInterpreter ____ +InterpretedData BubbleDataInterpreter::interpretDataSource( + const Reference< chart2::data::XDataSource >& xSource, + const Sequence< beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse ) +{ + if( ! xSource.is()) + return InterpretedData(); + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = DataInterpreter::getDataSequences(xSource); + + uno::Reference< chart2::data::XLabeledDataSequence > xValuesX; + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aYValuesVector; + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSizeValuesVector; + + uno::Reference< chart2::data::XLabeledDataSequence > xCategories; + bool bHasCategories = HasCategories( aArguments, aData ); + bool bUseCategoriesAsX = UseCategoriesAsX( aArguments ); + + sal_Int32 nDataSeqCount = aData.size(); + + bool bSetXValues = bHasCategories ? ( (nDataSeqCount-1) > 2 && (nDataSeqCount-1) % 2 != 0 ) + :( nDataSeqCount > 2 && nDataSeqCount % 2 != 0 ); + + bool bCategoriesUsed = false; + bool bNextIsYValues = bHasCategories ? nDataSeqCount>2 : nDataSeqCount>1; + for( sal_Int32 nDataIdx = 0; nDataIdx < nDataSeqCount; ++nDataIdx ) + { + try + { + if( bHasCategories && !bCategoriesUsed ) + { + xCategories = aData[nDataIdx]; + if( xCategories.is()) + { + SetRole( xCategories->getValues(), "categories"); + if( bUseCategoriesAsX ) + { + bSetXValues = false; + bNextIsYValues = nDataSeqCount > 2; + } + } + bCategoriesUsed = true; + } + else if( !xValuesX.is() && bSetXValues ) + { + xValuesX = aData[nDataIdx]; + if( xValuesX.is()) + SetRole( xValuesX->getValues(), "values-x"); + } + else if( bNextIsYValues ) + { + aYValuesVector.push_back( aData[nDataIdx] ); + if( aData[nDataIdx].is()) + SetRole( aData[nDataIdx]->getValues(), "values-y"); + bNextIsYValues = false; + } + else if( !bNextIsYValues ) + { + aSizeValuesVector.push_back( aData[nDataIdx] ); + if( aData[nDataIdx].is()) + SetRole( aData[nDataIdx]->getValues(), "values-size"); + bNextIsYValues = (nDataSeqCount-(nDataIdx+1)) >= 2;//two or more left + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + // create DataSeries + std::size_t nSeriesIndex = 0; + vector< rtl::Reference< DataSeries > > aSeriesVec; + aSeriesVec.reserve( aSizeValuesVector.size()); + + Reference< data::XLabeledDataSequence > xClonedXValues = xValuesX; + Reference< util::XCloneable > xCloneableX( xValuesX, uno::UNO_QUERY ); + + for( size_t nN = 0; nN < aSizeValuesVector.size(); ++nN, ++nSeriesIndex ) + { + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewData; + if( xValuesX.is() ) + { + if( nN > 0 && xCloneableX.is() ) + xClonedXValues.set( xCloneableX->createClone(), uno::UNO_QUERY ); + aNewData.push_back( xClonedXValues ); + } + if( aYValuesVector.size() > nN ) + aNewData.push_back( aYValuesVector[nN] ); + aNewData.push_back(aSizeValuesVector[nN]); + + rtl::Reference< DataSeries > xSeries; + if( nSeriesIndex < aSeriesToReUse.size()) + xSeries = aSeriesToReUse[nSeriesIndex]; + else + xSeries = new DataSeries; + assert( xSeries.is() ); + xSeries->setData( aNewData ); + + aSeriesVec.push_back( xSeries ); + } + + return { { aSeriesVec }, xCategories }; +} + +InterpretedData BubbleDataInterpreter::reinterpretDataSeries( + const InterpretedData& aInterpretedData ) +{ + InterpretedData aResult( aInterpretedData ); + + sal_Int32 i=0; + std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); + const sal_Int32 nCount = aSeries.size(); + for( ; i > aNewSequences; + + uno::Reference< chart2::data::XLabeledDataSequence > xValuesSize( + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-size" )); + uno::Reference< chart2::data::XLabeledDataSequence > xValuesY( + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-y" )); + uno::Reference< chart2::data::XLabeledDataSequence > xValuesX( + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-x" )); + + if( ! xValuesX.is() || + ! xValuesY.is() || + ! xValuesSize.is() ) + { + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aValueSeqVec( + DataSeriesHelper::getAllDataSequencesByRole( + aSeries[i]->getDataSequences2(), "values" )); + if( xValuesX.is()) + aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesX )); + if( xValuesY.is()) + aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesY )); + if( xValuesSize.is()) + aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesSize )); + + size_t nIndex = 0; + + if( ! xValuesSize.is() && + aValueSeqVec.size() > nIndex ) + { + xValuesSize = aValueSeqVec[nIndex++]; + if( xValuesSize.is()) + SetRole( xValuesSize->getValues(), "values-size"); + } + + if( ! xValuesY.is() && + aValueSeqVec.size() > nIndex ) + { + xValuesY = aValueSeqVec[nIndex++]; + if( xValuesY.is()) + SetRole( xValuesY->getValues(), "values-y"); + } + + if( ! xValuesX.is() && + aValueSeqVec.size() > nIndex ) + { + xValuesX = aValueSeqVec[nIndex++]; + if( xValuesX.is()) + SetRole( xValuesY->getValues(), "values-x"); + } + } + if( xValuesSize.is()) + { + if( xValuesY.is() ) + { + if( xValuesX.is() ) + { + aNewSequences = { xValuesX, xValuesY, xValuesSize }; + } + else + { + aNewSequences = { xValuesY, xValuesSize }; + } + } + else + { + aNewSequences = { xValuesSize }; + } + } + + const std::vector< uno::Reference< data::XLabeledDataSequence > > & aSeqs = aSeries[i]->getDataSequences2(); + if( aSeqs.size() != aNewSequences.size() ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + for( auto const & j : aSeqs ) + { + assert( (j == xValuesY || j == xValuesX || j == xValuesSize) && "All sequences should be used" ); + } +#endif + aSeries[i]->setData( aNewSequences ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +bool BubbleDataInterpreter::isDataCompatible( + const InterpretedData& aInterpretedData ) +{ + const std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + try + { + if( dataSeries->getDataSequences2().size() != 3 ) + return false; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return true; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/BubbleDataInterpreter.hxx b/chart2/source/model/template/BubbleDataInterpreter.hxx new file mode 100644 index 000000000..ff4b56de6 --- /dev/null +++ b/chart2/source/model/template/BubbleDataInterpreter.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class BubbleDataInterpreter : public DataInterpreter +{ +public: + explicit BubbleDataInterpreter(); + virtual ~BubbleDataInterpreter() override; + +protected: + // ____ DataInterpreter ____ + virtual InterpretedData interpretDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< ::chart::DataSeries > >& aSeriesToReUse ) override; + virtual InterpretedData reinterpretDataSeries( + const InterpretedData& aInterpretedData ) override; + virtual bool isDataCompatible( + const InterpretedData& aInterpretedData ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/CandleStickChartType.cxx b/chart2/source/model/template/CandleStickChartType.cxx new file mode 100644 index 000000000..553a13748 --- /dev/null +++ b/chart2/source/model/template/CandleStickChartType.cxx @@ -0,0 +1,348 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "CandleStickChartType.hxx" +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +enum +{ + PROP_CANDLESTICKCHARTTYPE_JAPANESE, + PROP_CANDLESTICKCHARTTYPE_WHITE_DAY, + PROP_CANDLESTICKCHARTTYPE_BLACK_DAY, + + PROP_CANDLESTICKCHARTTYPE_SHOW_FIRST, + PROP_CANDLESTICKCHARTTYPE_SHOW_HIGH_LOW +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Japanese", + PROP_CANDLESTICKCHARTTYPE_JAPANESE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "WhiteDay", + PROP_CANDLESTICKCHARTTYPE_WHITE_DAY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "BlackDay", + PROP_CANDLESTICKCHARTTYPE_BLACK_DAY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "ShowFirst", + PROP_CANDLESTICKCHARTTYPE_SHOW_FIRST, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "ShowHighLow", + PROP_CANDLESTICKCHARTTYPE_SHOW_HIGH_LOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticCandleStickChartTypeDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + // must match default in CTOR! + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CANDLESTICKCHARTTYPE_JAPANESE, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CANDLESTICKCHARTTYPE_SHOW_FIRST, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CANDLESTICKCHARTTYPE_SHOW_HIGH_LOW, true ); + } +}; + +struct StaticCandleStickChartTypeDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticCandleStickChartTypeDefaults_Initializer > +{ +}; + +struct StaticCandleStickChartTypeInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticCandleStickChartTypeInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticCandleStickChartTypeInfoHelper_Initializer > +{ +}; + +struct StaticCandleStickChartTypeInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticCandleStickChartTypeInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticCandleStickChartTypeInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticCandleStickChartTypeInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +CandleStickChartType::CandleStickChartType() +{ + Reference< beans::XPropertySet > xWhiteDayProps( new ::chart::StockBar( true )); + Reference< beans::XPropertySet > xBlackDayProps( new ::chart::StockBar( false )); + + ModifyListenerHelper::addListener( xWhiteDayProps, m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( xBlackDayProps, m_xModifyEventForwarder ); + + setFastPropertyValue_NoBroadcast( + PROP_CANDLESTICKCHARTTYPE_WHITE_DAY, uno::Any( xWhiteDayProps )); + setFastPropertyValue_NoBroadcast( + PROP_CANDLESTICKCHARTTYPE_BLACK_DAY, uno::Any( xBlackDayProps )); +} + +CandleStickChartType::CandleStickChartType( const CandleStickChartType & rOther ) : + ChartType( rOther ) +{ + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, PROP_CANDLESTICKCHARTTYPE_WHITE_DAY ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, PROP_CANDLESTICKCHARTTYPE_BLACK_DAY ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::addListener( xPropertySet, m_xModifyEventForwarder ); +} + +CandleStickChartType::~CandleStickChartType() +{ + try + { + Reference< beans::XPropertySet > xPropertySet; + uno::Any aValue; + + getFastPropertyValue( aValue, PROP_CANDLESTICKCHARTTYPE_WHITE_DAY ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + + getFastPropertyValue( aValue, PROP_CANDLESTICKCHARTTYPE_BLACK_DAY ); + if( ( aValue >>= xPropertySet ) + && xPropertySet.is()) + ModifyListenerHelper::removeListener( xPropertySet, m_xModifyEventForwarder ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL CandleStickChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new CandleStickChartType( *this )); +} + +rtl::Reference< ChartType > CandleStickChartType::cloneChartType() const +{ + return new CandleStickChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL CandleStickChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK; +} + +uno::Sequence< OUString > SAL_CALL CandleStickChartType::getSupportedMandatoryRoles() +{ + bool bShowFirst = true; + bool bShowHiLow = false; + getFastPropertyValue( PROP_CANDLESTICKCHARTTYPE_SHOW_FIRST ) >>= bShowFirst; + getFastPropertyValue( PROP_CANDLESTICKCHARTTYPE_SHOW_HIGH_LOW ) >>= bShowHiLow; + + std::vector< OUString > aMandRoles; + + aMandRoles.emplace_back("label"); + if( bShowFirst ) + aMandRoles.emplace_back("values-first"); + + if( bShowHiLow ) + { + aMandRoles.emplace_back("values-min"); + aMandRoles.emplace_back("values-max"); + } + + aMandRoles.emplace_back("values-last"); + + return comphelper::containerToSequence( aMandRoles ); +} + +Sequence< OUString > SAL_CALL CandleStickChartType::getSupportedOptionalRoles() +{ + bool bShowFirst = true; + bool bShowHiLow = false; + getFastPropertyValue( PROP_CANDLESTICKCHARTTYPE_SHOW_FIRST ) >>= bShowFirst; + getFastPropertyValue( PROP_CANDLESTICKCHARTTYPE_SHOW_HIGH_LOW ) >>= bShowHiLow; + + std::vector< OUString > aOptRoles; + + if( ! bShowFirst ) + aOptRoles.emplace_back("values-first"); + + if( ! bShowHiLow ) + { + aOptRoles.emplace_back("values-min"); + aOptRoles.emplace_back("values-max"); + } + + return comphelper::containerToSequence( aOptRoles ); +} + +OUString SAL_CALL CandleStickChartType::getRoleOfSequenceForSeriesLabel() +{ + return "values-last"; +} + +// ____ OPropertySet ____ +void CandleStickChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticCandleStickChartTypeDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL CandleStickChartType::getInfoHelper() +{ + return *StaticCandleStickChartTypeInfoHelper::get(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL CandleStickChartType::getPropertySetInfo() +{ + return *StaticCandleStickChartTypeInfo::get(); +} + +void SAL_CALL CandleStickChartType::setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, const uno::Any& rValue ) +{ + if( nHandle == PROP_CANDLESTICKCHARTTYPE_WHITE_DAY + || nHandle == PROP_CANDLESTICKCHARTTYPE_BLACK_DAY ) + { + uno::Any aOldValue; + Reference< util::XModifyBroadcaster > xBroadcaster; + getFastPropertyValue( aOldValue, nHandle ); + if( aOldValue.hasValue() && + (aOldValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::removeListener( xBroadcaster, m_xModifyEventForwarder ); + } + + OSL_ASSERT( rValue.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ); + if( rValue.hasValue() && + (rValue >>= xBroadcaster) && + xBroadcaster.is()) + { + ModifyListenerHelper::addListener( xBroadcaster, m_xModifyEventForwarder ); + } + } + + ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +OUString SAL_CALL CandleStickChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.CandleStickChartType" ; +} + +sal_Bool SAL_CALL CandleStickChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CandleStickChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_CandleStickChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::CandleStickChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/CandleStickChartType.hxx b/chart2/source/model/template/CandleStickChartType.hxx new file mode 100644 index 000000000..e76107507 --- /dev/null +++ b/chart2/source/model/template/CandleStickChartType.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +// see "[10/11/12 Regression] using +// declaration causing virtual call with wrongly adjusted this pointer" before restoring 'final' +class CandleStickChartType /* final */ : public ChartType +{ +public: + explicit CandleStickChartType(); + virtual ~CandleStickChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit CandleStickChartType( const CandleStickChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedMandatoryRoles() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedOptionalRoles() override; + virtual OUString SAL_CALL getRoleOfSequenceForSeriesLabel() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ OPropertySet ____ + virtual void SAL_CALL setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ChartType.cxx b/chart2/source/model/template/ChartType.cxx new file mode 100644 index 000000000..eff91f9cc --- /dev/null +++ b/chart2/source/model/template/ChartType.cxx @@ -0,0 +1,335 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +ChartType::ChartType() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNotifyChanges( true ) +{} + +ChartType::ChartType( const ChartType & rOther ) : + impl::ChartType_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_bNotifyChanges( true ) +{ + { + SolarMutexGuard g; // access to rOther.m_aDataSeries + CloneHelper::CloneRefVector( + rOther.m_aDataSeries, m_aDataSeries); + } + ModifyListenerHelper::addListenerToAllElements( m_aDataSeries, m_xModifyEventForwarder ); +} + +ChartType::~ChartType() +{ + ModifyListenerHelper::removeListenerFromAllElements( m_aDataSeries, m_xModifyEventForwarder ); + m_aDataSeries.clear(); +} + +// ____ XChartType ____ +Reference< chart2::XCoordinateSystem > SAL_CALL + ChartType::createCoordinateSystem( ::sal_Int32 DimensionCount ) +{ + return createCoordinateSystem2(DimensionCount); +} + +rtl::Reference< BaseCoordinateSystem > + ChartType::createCoordinateSystem2( ::sal_Int32 DimensionCount ) +{ + rtl::Reference< CartesianCoordinateSystem > xResult = + new CartesianCoordinateSystem( DimensionCount ); + + for( sal_Int32 i=0; i xAxis = xResult->getAxisByDimension2( i, MAIN_AXIS_INDEX ); + if( !xAxis.is() ) + { + OSL_FAIL("a created coordinate system should have an axis for each dimension"); + continue; + } + + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + aScaleData.Scaling = AxisHelper::createLinearScaling(); + + switch( i ) + { + case 0: aScaleData.AxisType = chart2::AxisType::CATEGORY; break; + case 2: aScaleData.AxisType = chart2::AxisType::SERIES; break; + default: aScaleData.AxisType = chart2::AxisType::REALNUMBER; break; + } + + xAxis->setScaleData( aScaleData ); + } + + return xResult; +} + +Sequence< OUString > SAL_CALL ChartType::getSupportedMandatoryRoles() +{ + return { "label", "values-y" }; +} + +Sequence< OUString > SAL_CALL ChartType::getSupportedOptionalRoles() +{ + return Sequence< OUString >(); +} + +Sequence< OUString > SAL_CALL ChartType::getSupportedPropertyRoles() +{ + return Sequence< OUString >(); +} + +OUString SAL_CALL ChartType::getRoleOfSequenceForSeriesLabel() +{ + return "values-y"; +} + +void ChartType::impl_addDataSeriesWithoutNotification( + const rtl::Reference< DataSeries >& xDataSeries ) +{ + if( std::find( m_aDataSeries.begin(), m_aDataSeries.end(), xDataSeries ) + != m_aDataSeries.end()) + throw lang::IllegalArgumentException("dataseries not found", static_cast(this), 1); + + m_aDataSeries.push_back( xDataSeries ); + ModifyListenerHelper::addListener( xDataSeries, m_xModifyEventForwarder ); +} + +// ____ XDataSeriesContainer ____ +void SAL_CALL ChartType::addDataSeries( const Reference< chart2::XDataSeries >& xDataSeries ) +{ + rtl::Reference xTmp = dynamic_cast(xDataSeries.get()); + assert(xTmp); + addDataSeries(xTmp); +} + +void ChartType::addDataSeries( const rtl::Reference< DataSeries >& xDataSeries ) +{ + SolarMutexGuard g; + + impl_addDataSeriesWithoutNotification( xDataSeries ); + fireModifyEvent(); +} + +void SAL_CALL ChartType::removeDataSeries( const Reference< chart2::XDataSeries >& xDataSeries ) +{ + rtl::Reference xTmp = dynamic_cast(xDataSeries.get()); + assert(xTmp); + removeDataSeries(xTmp); +} + +void ChartType::removeDataSeries( const rtl::Reference< DataSeries >& xDataSeries ) +{ + if( !xDataSeries.is()) + throw container::NoSuchElementException(); + + SolarMutexGuard g; + + auto aIt = std::find( m_aDataSeries.begin(), m_aDataSeries.end(), xDataSeries ); + + if( aIt == m_aDataSeries.end()) + throw container::NoSuchElementException( + "The given series is no element of this charttype", + static_cast< uno::XWeak * >( this )); + + ModifyListenerHelper::removeListener( xDataSeries, m_xModifyEventForwarder ); + m_aDataSeries.erase( aIt ); + fireModifyEvent(); +} + +Sequence< Reference< chart2::XDataSeries > > SAL_CALL ChartType::getDataSeries() +{ + SolarMutexGuard g; + + return comphelper::containerToSequence< Reference< chart2::XDataSeries > >( m_aDataSeries ); +} + +void SAL_CALL ChartType::setDataSeries( const Sequence< Reference< chart2::XDataSeries > >& aDataSeries ) +{ + std::vector< rtl::Reference > aTmp; + for (auto const & i : aDataSeries) + { + auto p = dynamic_cast(i.get()); + assert(p); + aTmp.push_back(p); + } + setDataSeries(aTmp); +} + +void ChartType::setDataSeries( const std::vector< rtl::Reference< DataSeries > >& aDataSeries ) +{ + SolarMutexGuard g; + + m_bNotifyChanges = false; + try + { + for( auto const & i : m_aDataSeries ) + ModifyListenerHelper::removeListener( i, m_xModifyEventForwarder ); + m_aDataSeries.clear(); + + for( auto const & i : aDataSeries ) + impl_addDataSeriesWithoutNotification( i ); + } + catch( ... ) + { + m_bNotifyChanges = true; + throw; + } + m_bNotifyChanges = true; + fireModifyEvent(); +} + +// ____ OPropertySet ____ +void ChartType::GetDefaultValue( sal_Int32 /* nHandle */, uno::Any& rAny ) const +{ + rAny.clear(); +} + +namespace +{ + +struct StaticChartTypeInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( Sequence< beans::Property >{} ); + return &aPropHelper; + } +}; + +struct StaticChartTypeInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticChartTypeInfoHelper_Initializer > +{ +}; + +struct StaticChartTypeInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticChartTypeInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticChartTypeInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticChartTypeInfo_Initializer > +{ +}; + +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL ChartType::getInfoHelper() +{ + return *StaticChartTypeInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ChartType::getPropertySetInfo() +{ + return *StaticChartTypeInfo::get(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL ChartType::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + try + { + m_xModifyEventForwarder->addModifyListener( aListener ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void SAL_CALL ChartType::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + try + { + m_xModifyEventForwarder->removeModifyListener( aListener ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XModifyListener ____ +void SAL_CALL ChartType::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL ChartType::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void ChartType::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void ChartType::fireModifyEvent() +{ + bool bNotifyChanges; + + { + SolarMutexGuard g; + bNotifyChanges = m_bNotifyChanges; + } + + if (bNotifyChanges) + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +using impl::ChartType_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( ChartType, ChartType_Base, ::property::OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( ChartType, ChartType_Base, ::property::OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ChartTypeManager.cxx b/chart2/source/model/template/ChartTypeManager.cxx new file mode 100644 index 000000000..b1abde352 --- /dev/null +++ b/chart2/source/model/template/ChartTypeManager.cxx @@ -0,0 +1,588 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "LineChartTypeTemplate.hxx" +#include "BarChartTypeTemplate.hxx" +#include "ColumnLineChartTypeTemplate.hxx" +#include "AreaChartTypeTemplate.hxx" +#include "PieChartTypeTemplate.hxx" +#include "ScatterChartTypeTemplate.hxx" +#include "StockChartTypeTemplate.hxx" +#include "NetChartTypeTemplate.hxx" +#include "BubbleChartTypeTemplate.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; + +namespace +{ + +enum TemplateId +{ + TEMPLATE_SYMBOL, + TEMPLATE_STACKEDSYMBOL, + TEMPLATE_PERCENTSTACKEDSYMBOL, + TEMPLATE_LINE, + TEMPLATE_STACKEDLINE, + TEMPLATE_PERCENTSTACKEDLINE, + TEMPLATE_LINESYMBOL, + TEMPLATE_STACKEDLINESYMBOL, + TEMPLATE_PERCENTSTACKEDLINESYMBOL, + TEMPLATE_THREEDLINE, + TEMPLATE_STACKEDTHREEDLINE, + TEMPLATE_PERCENTSTACKEDTHREEDLINE, + TEMPLATE_THREEDLINEDEEP, + TEMPLATE_COLUMN, + TEMPLATE_STACKEDCOLUMN, + TEMPLATE_PERCENTSTACKEDCOLUMN, + TEMPLATE_BAR, + TEMPLATE_STACKEDBAR, + TEMPLATE_PERCENTSTACKEDBAR, + TEMPLATE_THREEDCOLUMNDEEP, + TEMPLATE_THREEDCOLUMNFLAT, + TEMPLATE_STACKEDTHREEDCOLUMNFLAT, + TEMPLATE_PERCENTSTACKEDTHREEDCOLUMNFLAT, + TEMPLATE_THREEDBARDEEP, + TEMPLATE_THREEDBARFLAT, + TEMPLATE_STACKEDTHREEDBARFLAT, + TEMPLATE_PERCENTSTACKEDTHREEDBARFLAT, + TEMPLATE_COLUMNWITHLINE, + TEMPLATE_STACKEDCOLUMNWITHLINE, + TEMPLATE_AREA, + TEMPLATE_STACKEDAREA, + TEMPLATE_PERCENTSTACKEDAREA, + TEMPLATE_THREEDAREA, + TEMPLATE_STACKEDTHREEDAREA, + TEMPLATE_PERCENTSTACKEDTHREEDAREA, + TEMPLATE_PIE, + TEMPLATE_PIEALLEXPLODED, + TEMPLATE_DONUT, + TEMPLATE_DONUTALLEXPLODED, + TEMPLATE_THREEDPIE, + TEMPLATE_THREEDPIEALLEXPLODED, + TEMPLATE_THREEDDONUT, + TEMPLATE_THREEDDONUTALLEXPLODED, + TEMPLATE_SCATTERLINESYMBOL, + TEMPLATE_SCATTERLINE, + TEMPLATE_SCATTERSYMBOL, + TEMPLATE_THREEDSCATTER, + TEMPLATE_NET, + TEMPLATE_NETSYMBOL, + TEMPLATE_NETLINE, + TEMPLATE_STACKEDNET, + TEMPLATE_STACKEDNETSYMBOL, + TEMPLATE_STACKEDNETLINE, + TEMPLATE_PERCENTSTACKEDNET, + TEMPLATE_PERCENTSTACKEDNETSYMBOL, + TEMPLATE_PERCENTSTACKEDNETLINE, + TEMPLATE_FILLEDNET, + TEMPLATE_STACKEDFILLEDNET, + TEMPLATE_PERCENTSTACKEDFILLEDNET, + TEMPLATE_STOCKLOWHIGHCLOSE, + TEMPLATE_STOCKOPENLOWHIGHCLOSE, + TEMPLATE_STOCKVOLUMELOWHIGHCLOSE, + TEMPLATE_STOCKVOLUMEOPENLOWHIGHCLOSE, + TEMPLATE_BUBBLE, +// TEMPLATE_SURFACE, +// TEMPLATE_ADDIN, + TEMPLATE_NOT_FOUND = 0xffff +}; + +typedef std::map< OUString, TemplateId > tTemplateMapType; + +const tTemplateMapType & lcl_DefaultChartTypeMap() +{ + static const tTemplateMapType aMap{ + {"com.sun.star.chart2.template.Symbol", TEMPLATE_SYMBOL}, + {"com.sun.star.chart2.template.StackedSymbol", TEMPLATE_STACKEDSYMBOL}, + {"com.sun.star.chart2.template.PercentStackedSymbol", TEMPLATE_PERCENTSTACKEDSYMBOL}, + {"com.sun.star.chart2.template.Line", TEMPLATE_LINE}, + {"com.sun.star.chart2.template.StackedLine", TEMPLATE_STACKEDLINE}, + {"com.sun.star.chart2.template.PercentStackedLine", TEMPLATE_PERCENTSTACKEDLINE}, + {"com.sun.star.chart2.template.LineSymbol", TEMPLATE_LINESYMBOL}, + {"com.sun.star.chart2.template.StackedLineSymbol", TEMPLATE_STACKEDLINESYMBOL}, + {"com.sun.star.chart2.template.PercentStackedLineSymbol", TEMPLATE_PERCENTSTACKEDLINESYMBOL}, + {"com.sun.star.chart2.template.ThreeDLine", TEMPLATE_THREEDLINE}, + {"com.sun.star.chart2.template.StackedThreeDLine", TEMPLATE_STACKEDTHREEDLINE}, + {"com.sun.star.chart2.template.PercentStackedThreeDLine", TEMPLATE_PERCENTSTACKEDTHREEDLINE}, + {"com.sun.star.chart2.template.ThreeDLineDeep", TEMPLATE_THREEDLINEDEEP}, + {"com.sun.star.chart2.template.Column", TEMPLATE_COLUMN}, + {"com.sun.star.chart2.template.StackedColumn", TEMPLATE_STACKEDCOLUMN}, + {"com.sun.star.chart2.template.PercentStackedColumn", TEMPLATE_PERCENTSTACKEDCOLUMN}, + {"com.sun.star.chart2.template.Bar", TEMPLATE_BAR}, + {"com.sun.star.chart2.template.StackedBar", TEMPLATE_STACKEDBAR}, + {"com.sun.star.chart2.template.PercentStackedBar", TEMPLATE_PERCENTSTACKEDBAR}, + {"com.sun.star.chart2.template.ThreeDColumnDeep", TEMPLATE_THREEDCOLUMNDEEP}, + {"com.sun.star.chart2.template.ThreeDColumnFlat", TEMPLATE_THREEDCOLUMNFLAT}, + {"com.sun.star.chart2.template.StackedThreeDColumnFlat", TEMPLATE_STACKEDTHREEDCOLUMNFLAT}, + {"com.sun.star.chart2.template.PercentStackedThreeDColumnFlat", TEMPLATE_PERCENTSTACKEDTHREEDCOLUMNFLAT}, + {"com.sun.star.chart2.template.ThreeDBarDeep", TEMPLATE_THREEDBARDEEP}, + {"com.sun.star.chart2.template.ThreeDBarFlat", TEMPLATE_THREEDBARFLAT}, + {"com.sun.star.chart2.template.StackedThreeDBarFlat", TEMPLATE_STACKEDTHREEDBARFLAT}, + {"com.sun.star.chart2.template.PercentStackedThreeDBarFlat", TEMPLATE_PERCENTSTACKEDTHREEDBARFLAT}, + {"com.sun.star.chart2.template.ColumnWithLine", TEMPLATE_COLUMNWITHLINE}, + {"com.sun.star.chart2.template.StackedColumnWithLine", TEMPLATE_STACKEDCOLUMNWITHLINE}, + {"com.sun.star.chart2.template.Area", TEMPLATE_AREA}, + {"com.sun.star.chart2.template.StackedArea", TEMPLATE_STACKEDAREA}, + {"com.sun.star.chart2.template.PercentStackedArea", TEMPLATE_PERCENTSTACKEDAREA}, + {"com.sun.star.chart2.template.ThreeDArea", TEMPLATE_THREEDAREA}, + {"com.sun.star.chart2.template.StackedThreeDArea", TEMPLATE_STACKEDTHREEDAREA}, + {"com.sun.star.chart2.template.PercentStackedThreeDArea", TEMPLATE_PERCENTSTACKEDTHREEDAREA}, + {"com.sun.star.chart2.template.Pie", TEMPLATE_PIE}, + {"com.sun.star.chart2.template.PieAllExploded", TEMPLATE_PIEALLEXPLODED}, + {"com.sun.star.chart2.template.Donut", TEMPLATE_DONUT}, + {"com.sun.star.chart2.template.DonutAllExploded", TEMPLATE_DONUTALLEXPLODED}, + {"com.sun.star.chart2.template.ThreeDPie", TEMPLATE_THREEDPIE}, + {"com.sun.star.chart2.template.ThreeDPieAllExploded", TEMPLATE_THREEDPIEALLEXPLODED}, + {"com.sun.star.chart2.template.ThreeDDonut", TEMPLATE_THREEDDONUT}, + {"com.sun.star.chart2.template.ThreeDDonutAllExploded", TEMPLATE_THREEDDONUTALLEXPLODED}, + {"com.sun.star.chart2.template.ScatterLineSymbol", TEMPLATE_SCATTERLINESYMBOL}, + {"com.sun.star.chart2.template.ScatterLine", TEMPLATE_SCATTERLINE}, + {"com.sun.star.chart2.template.ScatterSymbol", TEMPLATE_SCATTERSYMBOL}, + {"com.sun.star.chart2.template.ThreeDScatter", TEMPLATE_THREEDSCATTER}, + {"com.sun.star.chart2.template.Net", TEMPLATE_NET}, + {"com.sun.star.chart2.template.NetSymbol", TEMPLATE_NETSYMBOL}, + {"com.sun.star.chart2.template.NetLine", TEMPLATE_NETLINE}, + {"com.sun.star.chart2.template.StackedNet", TEMPLATE_STACKEDNET}, + {"com.sun.star.chart2.template.StackedNetSymbol", TEMPLATE_STACKEDNETSYMBOL}, + {"com.sun.star.chart2.template.StackedNetLine", TEMPLATE_STACKEDNETLINE}, + {"com.sun.star.chart2.template.PercentStackedNet", TEMPLATE_PERCENTSTACKEDNET}, + {"com.sun.star.chart2.template.PercentStackedNetSymbol", TEMPLATE_PERCENTSTACKEDNETSYMBOL}, + {"com.sun.star.chart2.template.PercentStackedNetLine", TEMPLATE_PERCENTSTACKEDNETLINE}, + {"com.sun.star.chart2.template.FilledNet", TEMPLATE_FILLEDNET}, + {"com.sun.star.chart2.template.StackedFilledNet", TEMPLATE_STACKEDFILLEDNET}, + {"com.sun.star.chart2.template.PercentStackedFilledNet", TEMPLATE_PERCENTSTACKEDFILLEDNET}, + {"com.sun.star.chart2.template.StockLowHighClose", TEMPLATE_STOCKLOWHIGHCLOSE}, + {"com.sun.star.chart2.template.StockOpenLowHighClose", TEMPLATE_STOCKOPENLOWHIGHCLOSE}, + {"com.sun.star.chart2.template.StockVolumeLowHighClose", TEMPLATE_STOCKVOLUMELOWHIGHCLOSE}, + {"com.sun.star.chart2.template.StockVolumeOpenLowHighClose", TEMPLATE_STOCKVOLUMEOPENLOWHIGHCLOSE}, + {"com.sun.star.chart2.template.Bubble", TEMPLATE_BUBBLE}, +// {"com.sun.star.chart2.template.Surface", TEMPLATE_SURFACE}, +// {"com.sun.star.chart2.template.Addin", TEMPLATE_ADDIN}, + }; + return aMap; +} + +TemplateId lcl_GetTemplateIdForService( const OUString & rServiceName ) +{ + TemplateId eResult = TEMPLATE_NOT_FOUND; + const tTemplateMapType & rMap = lcl_DefaultChartTypeMap(); + tTemplateMapType::const_iterator aIt( rMap.find( rServiceName )); + + if( aIt != rMap.end()) + eResult = (*aIt).second; + + return eResult; +} + +} // anonymous namespace + +namespace chart +{ + +ChartTypeManager::ChartTypeManager( + uno::Reference< + uno::XComponentContext > const & xContext ) : + m_xContext( xContext ) +{} + +ChartTypeManager::~ChartTypeManager() +{} + +// ____ XMultiServiceFactory ____ +uno::Reference< uno::XInterface > SAL_CALL ChartTypeManager::createInstance( + const OUString& aServiceSpecifier ) +{ + return static_cast(createTemplate(aServiceSpecifier).get()); +} + +rtl::Reference< ::chart::ChartTypeTemplate > ChartTypeManager::createTemplate( + const OUString& aServiceSpecifier ) +{ + TemplateId nId = lcl_GetTemplateIdForService( aServiceSpecifier ); + + rtl::Reference< ::chart::ChartTypeTemplate > xTemplate; + switch( nId ) + { + // Point (category x axis) + case TEMPLATE_SYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, true, false )); + break; + case TEMPLATE_STACKEDSYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, true, false )); + break; + case TEMPLATE_PERCENTSTACKEDSYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, true, false )); + break; + // Line (category x axis) + case TEMPLATE_LINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, false )); + break; + case TEMPLATE_STACKEDLINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, false )); + break; + case TEMPLATE_PERCENTSTACKEDLINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, false )); + break; + case TEMPLATE_LINESYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, true )); + break; + case TEMPLATE_STACKEDLINESYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, true )); + break; + case TEMPLATE_PERCENTSTACKEDLINESYMBOL: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, true )); + break; + case TEMPLATE_THREEDLINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, false, true, 3 )); + break; + case TEMPLATE_STACKEDTHREEDLINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, false, true, 3 )); + break; + case TEMPLATE_PERCENTSTACKEDTHREEDLINE: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, false, true, 3 )); + break; + case TEMPLATE_THREEDLINEDEEP: + xTemplate.set( new LineChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::ZStacked, false, true, 3 )); + break; + + // Bar/Column + case TEMPLATE_COLUMN: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, BarChartTypeTemplate::VERTICAL )); + break; + case TEMPLATE_STACKEDCOLUMN: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, BarChartTypeTemplate::VERTICAL )); + break; + case TEMPLATE_PERCENTSTACKEDCOLUMN: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, BarChartTypeTemplate::VERTICAL )); + break; + case TEMPLATE_BAR: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, BarChartTypeTemplate::HORIZONTAL )); + break; + case TEMPLATE_STACKEDBAR: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, BarChartTypeTemplate::HORIZONTAL )); + break; + case TEMPLATE_PERCENTSTACKEDBAR: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, BarChartTypeTemplate::HORIZONTAL )); + break; + case TEMPLATE_THREEDCOLUMNDEEP: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::ZStacked, BarChartTypeTemplate::VERTICAL, 3 )); + break; + case TEMPLATE_THREEDCOLUMNFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, BarChartTypeTemplate::VERTICAL, 3 )); + break; + case TEMPLATE_STACKEDTHREEDCOLUMNFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, BarChartTypeTemplate::VERTICAL, 3 )); + break; + case TEMPLATE_PERCENTSTACKEDTHREEDCOLUMNFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, BarChartTypeTemplate::VERTICAL, 3 )); + break; + case TEMPLATE_THREEDBARDEEP: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::ZStacked, BarChartTypeTemplate::HORIZONTAL, 3 )); + break; + case TEMPLATE_THREEDBARFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, BarChartTypeTemplate::HORIZONTAL, 3 )); + break; + case TEMPLATE_STACKEDTHREEDBARFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, BarChartTypeTemplate::HORIZONTAL, 3 )); + break; + case TEMPLATE_PERCENTSTACKEDTHREEDBARFLAT: + xTemplate.set( new BarChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, BarChartTypeTemplate::HORIZONTAL, 3 )); + break; + + // Combi-Chart Line/Column + case TEMPLATE_COLUMNWITHLINE: + case TEMPLATE_STACKEDCOLUMNWITHLINE: + { + StackMode eMode = ( nId == TEMPLATE_COLUMNWITHLINE ) + ? StackMode::NONE + : StackMode::YStacked; + + xTemplate.set( new ColumnLineChartTypeTemplate( m_xContext, aServiceSpecifier, eMode, 1 )); + } + break; + + // Area + case TEMPLATE_AREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::NONE )); + break; + case TEMPLATE_STACKEDAREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::YStacked )); + break; + case TEMPLATE_PERCENTSTACKEDAREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::YStackedPercent )); + break; + case TEMPLATE_THREEDAREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::ZStacked, 3 )); + break; + case TEMPLATE_STACKEDTHREEDAREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::YStacked, 3 )); + break; + case TEMPLATE_PERCENTSTACKEDTHREEDAREA: + xTemplate.set( new AreaChartTypeTemplate( m_xContext, aServiceSpecifier, StackMode::YStackedPercent, 3 )); + break; + + case TEMPLATE_PIE: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_NONE, false )); + break; + case TEMPLATE_PIEALLEXPLODED: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_ALL_EXPLODED, false )); + break; + case TEMPLATE_DONUT: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_NONE, true )); + break; + case TEMPLATE_DONUTALLEXPLODED: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_ALL_EXPLODED, true )); + break; + case TEMPLATE_THREEDPIE: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_NONE, false, 3 )); + break; + case TEMPLATE_THREEDPIEALLEXPLODED: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_ALL_EXPLODED, false, 3 )); + break; + case TEMPLATE_THREEDDONUT: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_NONE, true, 3 )); + break; + case TEMPLATE_THREEDDONUTALLEXPLODED: + xTemplate.set( new PieChartTypeTemplate( m_xContext, aServiceSpecifier, + chart2::PieChartOffsetMode_ALL_EXPLODED, true, 3 )); + break; + + case TEMPLATE_SCATTERLINESYMBOL: + xTemplate.set( new ScatterChartTypeTemplate( m_xContext, aServiceSpecifier, /* bSymbols */ true )); + break; + case TEMPLATE_SCATTERLINE: + xTemplate.set( new ScatterChartTypeTemplate( m_xContext, aServiceSpecifier, /* bSymbols */ false )); + break; + case TEMPLATE_SCATTERSYMBOL: + xTemplate.set( new ScatterChartTypeTemplate( m_xContext, aServiceSpecifier, /* bSymbols */ true, /* bHasLines */ false )); + break; + case TEMPLATE_THREEDSCATTER: + xTemplate.set( new ScatterChartTypeTemplate( m_xContext, aServiceSpecifier, /* bSymbols */ false, /* bHasLines */ true, 3 )); + break; + + // NetChart + case TEMPLATE_NET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, true )); + break; + case TEMPLATE_NETSYMBOL: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, true, false )); + break; + case TEMPLATE_NETLINE: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, false )); + break; + + case TEMPLATE_STACKEDNET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, true )); + break; + case TEMPLATE_STACKEDNETSYMBOL: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, true, false )); + break; + case TEMPLATE_STACKEDNETLINE: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, false, true )); + break; + + case TEMPLATE_PERCENTSTACKEDNET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, true )); + break; + case TEMPLATE_PERCENTSTACKEDNETSYMBOL: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, true, false )); + break; + case TEMPLATE_PERCENTSTACKEDNETLINE: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, false, true )); + break; + + case TEMPLATE_FILLEDNET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::NONE, false, false, true )); + break; + case TEMPLATE_STACKEDFILLEDNET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStacked, false, false, true )); + break; + case TEMPLATE_PERCENTSTACKEDFILLEDNET: + xTemplate.set( new NetChartTypeTemplate( m_xContext, aServiceSpecifier, + StackMode::YStackedPercent, false, false, true )); + break; + + case TEMPLATE_STOCKLOWHIGHCLOSE: + xTemplate.set( new StockChartTypeTemplate( m_xContext, aServiceSpecifier, + StockChartTypeTemplate::StockVariant::NONE, false )); + break; + case TEMPLATE_STOCKOPENLOWHIGHCLOSE: + xTemplate.set( new StockChartTypeTemplate( m_xContext, aServiceSpecifier, + StockChartTypeTemplate::StockVariant::Open, true )); + break; + case TEMPLATE_STOCKVOLUMELOWHIGHCLOSE: + xTemplate.set( new StockChartTypeTemplate( m_xContext, aServiceSpecifier, + StockChartTypeTemplate::StockVariant::Volume, false )); + break; + case TEMPLATE_STOCKVOLUMEOPENLOWHIGHCLOSE: + xTemplate.set( new StockChartTypeTemplate( m_xContext, aServiceSpecifier, + StockChartTypeTemplate::StockVariant::VolumeOpen, true )); + break; + + //BubbleChart + case TEMPLATE_BUBBLE: + xTemplate.set( new BubbleChartTypeTemplate( m_xContext, aServiceSpecifier )); + break; + + case TEMPLATE_NOT_FOUND: + SAL_WARN("chart2", "Couldn't instantiate service: "<< aServiceSpecifier ); + assert(false); + break; + + default: break; +// case TEMPLATE_SURFACE: +// case TEMPLATE_ADDIN: +// break; + } + + return xTemplate; +} + +uno::Reference< uno::XInterface > SAL_CALL ChartTypeManager::createInstanceWithArguments( + const OUString& ServiceSpecifier, + const uno::Sequence< uno::Any >& /* Arguments */ ) +{ + OSL_FAIL( "createInstanceWithArguments: No arguments supported" ); + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > SAL_CALL ChartTypeManager::getAvailableServiceNames() +{ + std::vector< OUString > aServices; + const tTemplateMapType & rMap = lcl_DefaultChartTypeMap(); + aServices.reserve( rMap.size()); + + // get own default templates + std::transform( rMap.begin(), rMap.end(), std::back_inserter( aServices ), + ::o3tl::select1st< tTemplateMapType::value_type >() ); + + // add components that were registered in the context's factory + uno::Reference< container::XContentEnumerationAccess > xEnumAcc( + m_xContext->getServiceManager(), uno::UNO_QUERY ); + if( xEnumAcc.is()) + { + uno::Reference< container::XEnumeration > xEnum( + xEnumAcc->createContentEnumeration( "com.sun.star.chart2.ChartTypeTemplate" )); + if( xEnum.is()) + { + uno::Reference< uno::XInterface > xFactIntf; + + while( xEnum->hasMoreElements()) + { + if( xEnum->nextElement() >>= xFactIntf ) + { + uno::Reference< lang::XServiceName > xServiceName( xFactIntf, uno::UNO_QUERY ); + if( xServiceName.is()) + aServices.push_back( xServiceName->getServiceName()); + } + } + } + } + + return comphelper::containerToSequence( aServices ); +} + +// ____ XServiceInfo ____ +OUString SAL_CALL ChartTypeManager::getImplementationName() +{ + return "com.sun.star.comp.chart.ChartTypeManager"; +} + +sal_Bool SAL_CALL ChartTypeManager::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartTypeManager::getSupportedServiceNames() +{ + return { + "com.sun.star.chart2.ChartTypeManager", + "com.sun.star.lang.MultiServiceFactory" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ChartTypeManager_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ChartTypeManager(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ChartTypeTemplate.cxx b/chart2/source/model/template/ChartTypeTemplate.cxx new file mode 100644 index 000000000..a785635f9 --- /dev/null +++ b/chart2/source/model/template/ChartTypeTemplate.cxx @@ -0,0 +1,861 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +void lcl_applyDefaultStyle( + const rtl::Reference< ::chart::DataSeries > & xSeries, + sal_Int32 nIndex, + const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + // @deprecated: correct default color should be found by view without + // setting color as hard attribute + if( xSeries.is() && xDiagram.is()) + { + Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme()); + if( xColorScheme.is() ) + xSeries->setPropertyValue( + "Color", + uno::Any( xColorScheme->getColorByIndex( nIndex ))); + } +} + +void lcl_ensureCorrectLabelPlacement( const Reference< beans::XPropertySet >& xProp, const uno::Sequence < sal_Int32 >& rAvailablePlacements ) +{ + sal_Int32 nLabelPlacement=0; + if( !(xProp.is() && (xProp->getPropertyValue( "LabelPlacement" ) >>= nLabelPlacement)) ) + return; + + bool bValid = false; + for( sal_Int32 i : rAvailablePlacements ) + { + if( i == nLabelPlacement ) + { + bValid = true; + break; + } + } + if( !bValid ) + { + uno::Any aNewValue; + //otherwise use the first supported one + if( rAvailablePlacements.hasElements() ) + aNewValue <<=rAvailablePlacements[0]; + xProp->setPropertyValue( "LabelPlacement", aNewValue ); + } +} + +void lcl_resetLabelPlacementIfDefault( const Reference< beans::XPropertySet >& xProp, sal_Int32 nDefaultPlacement ) +{ + + sal_Int32 nLabelPlacement=0; + if( xProp.is() && (xProp->getPropertyValue( "LabelPlacement" ) >>= nLabelPlacement) ) + { + if( nDefaultPlacement == nLabelPlacement ) + xProp->setPropertyValue( "LabelPlacement", uno::Any() ); + } +} + +void lcl_ensureCorrectMissingValueTreatment( const rtl::Reference< ::chart::Diagram >& xDiagram, const rtl::Reference< ::chart::ChartType >& xChartType ) +{ + if( xDiagram.is() ) + { + uno::Sequence < sal_Int32 > aAvailableMissingValueTreatment( + ::chart::ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); + + if( aAvailableMissingValueTreatment.hasElements() ) + xDiagram->setPropertyValue( "MissingValueTreatment", uno::Any( aAvailableMissingValueTreatment[0] ) ); + else + xDiagram->setPropertyValue( "MissingValueTreatment", uno::Any() ); + } +} + +} // anonymous namespace + +namespace chart +{ + +ChartTypeTemplate::ChartTypeTemplate( + Reference< uno::XComponentContext > const & xContext, + const OUString & rServiceName ) : + m_xContext( xContext ), + m_aServiceName( rServiceName ) +{ +} + +ChartTypeTemplate::~ChartTypeTemplate() +{} + +// ____ ChartTypeTemplate ____ +rtl::Reference< Diagram > ChartTypeTemplate::createDiagramByDataSource2( + const uno::Reference< data::XDataSource >& xDataSource, + const uno::Sequence< beans::PropertyValue >& aArguments ) +{ + rtl::Reference< Diagram > xDia; + + try + { + // create diagram + xDia = new Diagram(GetComponentContext()); + + // modify diagram + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData( + xInterpreter->interpretDataSource( + xDataSource, aArguments, {} )); + + sal_Int32 nCount = 0; + for( auto const & i : aData.Series ) + for( auto const & j : i ) + lcl_applyDefaultStyle( j, nCount++, xDia ); + + std::vector< rtl::Reference< ChartType > > aOldChartTypesSeq; + FillDiagram( xDia, aData.Series, aData.Categories, aOldChartTypesSeq ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xDia; +} + +sal_Bool SAL_CALL ChartTypeTemplate::supportsCategories() +{ + return true; +} + +void ChartTypeTemplate::changeDiagram( const rtl::Reference< Diagram >& xDiagram ) +{ + if( ! xDiagram.is()) + return; + + try + { + std::vector< std::vector< rtl::Reference< DataSeries > > > aSeriesSeq = + DiagramHelper::getDataSeriesGroups( xDiagram ); + std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.size(); + + // chart-type specific interpretation of existing data series + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData; + aData.Series = aSeriesSeq; + aData.Categories = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + + if( xInterpreter->isDataCompatible( aData ) ) + { + aData = xInterpreter->reinterpretDataSeries( aData ); + } + else + { + rtl::Reference< DataSource > xSource = DataInterpreter::mergeInterpretedData( aData ); + // todo: get a "range-union" from the data provider by calling + // OUString aRange = getRangeRepresentationByData( xSource ); + // xSource.set( getDataByRangeRepresentation( aRange, aParam )); + // where aParam == ?? + Sequence< beans::PropertyValue > aParam; + if( aData.Categories.is()) + { + aParam = { beans::PropertyValue( "HasCategories", -1, uno::Any( true ), + beans::PropertyState_DIRECT_VALUE ) }; + } + aData = xInterpreter->interpretDataSource( xSource, aParam, aFlatSeriesSeq ); + } + aSeriesSeq = aData.Series; + + sal_Int32 nIndex = 0; + for( auto const & i : std::as_const(aSeriesSeq) ) + for( auto const & j : i ) + { + if( nIndex >= nFormerSeriesCount ) + lcl_applyDefaultStyle( j, nIndex++, xDiagram ); + } + + // remove charttype groups from all coordinate systems + std::vector< rtl::Reference< ChartType > > aOldChartTypesSeq = + DiagramHelper::getChartTypesFromDiagram(xDiagram); + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + coords->setChartTypes( Sequence< Reference< XChartType > >() ); + } + + FillDiagram( xDiagram, aSeriesSeq, aData.Categories, aOldChartTypesSeq ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::changeDiagramData( + const rtl::Reference< Diagram >& xDiagram, + const Reference< chart2::data::XDataSource >& xDataSource, + const Sequence< beans::PropertyValue >& aArguments ) +{ + if( ! (xDiagram.is() && + xDataSource.is()) ) + return; + + try + { + // interpret new data and re-use existing series + std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.size(); + rtl::Reference< DataInterpreter > xInterpreter( getDataInterpreter2()); + InterpretedData aData = + xInterpreter->interpretDataSource( xDataSource, aArguments, aFlatSeriesSeq ); + + // data series + sal_Int32 nIndex = 0; + for( std::size_t i=0; i= nFormerSeriesCount ) + { + lcl_applyDefaultStyle( aData.Series[i][j], nIndex, xDiagram ); + applyStyle2( aData.Series[i][j], i, j, aData.Series[i].size() ); + } + } + + // categories + DiagramHelper::setCategoriesToDiagram( aData.Categories, xDiagram, true, supportsCategories() ); + + std::vector< rtl::Reference< ChartType > > aChartTypes = + DiagramHelper::getChartTypesFromDiagram( xDiagram ); + sal_Int32 nMax = std::min( aChartTypes.size(), aData.Series.size()); + for( sal_Int32 i=0; isetDataSeries( aData.Series[i] ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool ChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool /* bAdaptProperties */ ) +{ + bool bResult = false; + + if( ! xDiagram.is()) + return bResult; + + try + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq( + xDiagram->getBaseCoordinateSystems()); + + // need to have at least one coordinate system + bResult = !aCooSysSeq.empty(); + if( bResult ) + { + std::vector< rtl::Reference< ChartType > > aFormerlyUsedChartTypes; + rtl::Reference xOldCT = getChartTypeForNewSeries2(aFormerlyUsedChartTypes); + if (!xOldCT.is()) + return false; + + const OUString aChartTypeToMatch = xOldCT->getChartType(); + const sal_Int32 nDimensionToMatch = getDimension(); + for( std::size_t nCooSysIdx=0; bResult && (nCooSysIdx < aCooSysSeq.size()); ++nCooSysIdx ) + { + // match dimension + bResult = bResult && (aCooSysSeq[nCooSysIdx]->getDimension() == nDimensionToMatch); + + const std::vector< rtl::Reference< ChartType > > & aChartTypeSeq( aCooSysSeq[nCooSysIdx]->getChartTypes2()); + for( std::size_t nCTIdx=0; bResult && (nCTIdx < aChartTypeSeq.size()); ++nCTIdx ) + { + // match chart type + bResult = bResult && aChartTypeSeq[nCTIdx]->getChartType() == aChartTypeToMatch; + bool bFound=false; + bool bAmbiguous=false; + // match stacking mode + bResult = bResult && + ( DiagramHelper::getStackModeFromChartType( + aChartTypeSeq[nCTIdx], bFound, bAmbiguous, + aCooSysSeq[nCooSysIdx] ) + == getStackMode( nCTIdx ) ); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return bResult; +} + +rtl::Reference< DataInterpreter > ChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new DataInterpreter ); + + return m_xDataInterpreter; +} + +void ChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 /* nSeriesIndex */, + ::sal_Int32 /* nSeriesCount */ ) +{ + // sset stacking mode + if( !xSeries.is()) + return; + + try + { + StackMode eStackMode = getStackMode( nChartTypeIndex ); + const uno::Any aPropValue( + ( (eStackMode == StackMode::YStacked) || + (eStackMode == StackMode::YStackedPercent) ) + ? chart2::StackingDirection_Y_STACKING + : (eStackMode == StackMode::ZStacked ) + ? chart2::StackingDirection_Z_STACKING + : chart2::StackingDirection_NO_STACKING ); + xSeries->setPropertyValue( "StackingDirection", aPropValue ); + + //ensure valid label placement + { + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + getChartTypeForIndex( nChartTypeIndex ), isSwapXAndY(), xSeries ) ); + lcl_ensureCorrectLabelPlacement( xSeries, aAvailablePlacements ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_ensureCorrectLabelPlacement( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), aAvailablePlacements ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::applyStyles( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + // apply chart-type specific styles, like "symbols on" for example + std::vector< std::vector< rtl::Reference< DataSeries > > > aNewSeriesSeq( + DiagramHelper::getDataSeriesGroups( xDiagram )); + for( std::size_t i=0; i& xDiagram ) +{ + // reset number format if we had percent stacking on + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + if( bPercent ) + { + const std::vector< rtl::Reference< Axis > > aAxisSeq( AxisHelper::getAllAxesOfDiagram( xDiagram ) ); + for( rtl::Reference< Axis > const & axis : aAxisSeq ) + { + if( AxisHelper::getDimensionIndexOfAxis( axis, xDiagram )== 1 ) + { + // set number format to source format + axis->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(true)); + axis->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any()); + } + } + } + + //reset label placement if default + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + for( rtl::Reference< ChartType > const & xChartType : xCooSys->getChartTypes2() ) + { + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & xSeries : xChartType->getDataSeries2() ) + { + uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, isSwapXAndY(), xSeries ) ); + if(!aAvailablePlacements.hasElements()) + continue; + + sal_Int32 nDefaultPlacement = aAvailablePlacements[0]; + + lcl_resetLabelPlacementIfDefault( xSeries, nDefaultPlacement ); + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + lcl_resetLabelPlacementIfDefault( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), nDefaultPlacement ); + } + } + } + +} + +// ____ XServiceName ____ + OUString SAL_CALL ChartTypeTemplate::getServiceName() +{ + return m_aServiceName; +} + +sal_Int32 ChartTypeTemplate::getDimension() const +{ + return 2; +} + +StackMode ChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return StackMode::NONE; +} + +bool ChartTypeTemplate::isSwapXAndY() const +{ + return false; +} + +void ChartTypeTemplate::createCoordinateSystems( + const rtl::Reference< ::chart::Diagram > & xDiagram ) +{ + if( ! xDiagram.is()) + return; + std::vector< rtl::Reference< ChartType > > aFormerlyUsedChartTypes; + rtl::Reference< ChartType > xChartType( getChartTypeForNewSeries2(aFormerlyUsedChartTypes)); + if( ! xChartType.is()) + return; + rtl::Reference< BaseCoordinateSystem > xCooSys = xChartType->createCoordinateSystem2( getDimension()); + if( ! xCooSys.is()) + { + // chart type wants no coordinate systems + xDiagram->setCoordinateSystems( Sequence< Reference< XCoordinateSystem > >()); + return; + } + // #i69680# make grid of first y-axis visible (was in the CooSys CTOR before) + if( xCooSys->getDimension() >= 2 ) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1, 0 ); + if( xAxis.is()) + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + } + + std::vector< rtl::Reference< BaseCoordinateSystem > > aCoordinateSystems( + xDiagram->getBaseCoordinateSystems()); + + if( !aCoordinateSystems.empty() ) + { + bool bOk = true; + for( std::size_t i=0; bOk && igetCoordinateSystemType() == aCoordinateSystems[i]->getCoordinateSystemType() && + (xCooSys->getDimension() == aCoordinateSystems[i]->getDimension()) ); + // coordinate systems are ok + if( bOk ) + return; + // there are coordinate systems but they do not fit. So overwrite them. + } + + //copy as much info from former coordinate system as possible: + if( !aCoordinateSystems.empty() ) + { + rtl::Reference< BaseCoordinateSystem > xOldCooSys( aCoordinateSystems[0] ); + sal_Int32 nMaxDimensionCount = std::min( xCooSys->getDimension(), xOldCooSys->getDimension() ); + + for(sal_Int32 nDimensionIndex=0; nDimensionIndexgetMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + rtl::Reference< Axis > xAxis = xOldCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + if( xAxis.is()) + { + xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); + } + } + } + } + + // set new coordinate systems + aCoordinateSystems = { xCooSys }; + + xDiagram->setCoordinateSystems( aCoordinateSystems ); +} + +void ChartTypeTemplate::adaptScales( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq, + const Reference< data::XLabeledDataSequence > & xCategories //@todo: in future there may be more than one sequence of categories (e.g. charttype with categories at x and y axis ) + ) +{ + bool bSupportsCategories( supportsCategories() ); + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : aCooSysSeq ) + { + try + { + // attach categories to first axis + sal_Int32 nDim( xCooSys->getDimension()); + if( nDim > 0 ) + { + const sal_Int32 nDimensionX = 0; + const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionX); + for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(nDimensionX,nI); + if( xAxis.is()) + { + ScaleData aData( xAxis->getScaleData() ); + aData.Categories = xCategories; + if(bSupportsCategories) + { + rtl::Reference< ChartType > xChartType = getChartTypeForNewSeries2({}); + if( aData.AxisType == AxisType::CATEGORY ) + { + aData.ShiftedCategoryPosition = m_aServiceName.indexOf("Column") != -1 || m_aServiceName.indexOf("Bar") != -1 || m_aServiceName.endsWith("Close"); + } + bool bSupportsDates = ::chart::ChartTypeHelper::isSupportingDateAxis( xChartType, nDimensionX ); + if( aData.AxisType != AxisType::CATEGORY && ( aData.AxisType != AxisType::DATE || !bSupportsDates) ) + { + aData.AxisType = AxisType::CATEGORY; + aData.AutoDateAxis = true; + AxisHelper::removeExplicitScaling( aData ); + } + } + else + aData.AxisType = AxisType::REALNUMBER; + + xAxis->setScaleData( aData ); + } + } + } + // set percent stacking mode at second axis + if( nDim > 1 ) + { + const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(1); + for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1,nI ); + if( xAxis.is()) + { + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + chart2::ScaleData aScaleData = xAxis->getScaleData(); + + if( bPercent != (aScaleData.AxisType==AxisType::PERCENT) ) + { + if( bPercent ) + aScaleData.AxisType = AxisType::PERCENT; + else + aScaleData.AxisType = AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +void ChartTypeTemplate::adaptDiagram( const rtl::Reference< ::chart::Diagram > & /* xDiagram */ ) +{ +} + +void ChartTypeTemplate::createAxes( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys ) +{ + //create missing axes + if( rCoordSys.empty() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys( rCoordSys[0] ); + if(!xCooSys.is()) + return; + + //create main axis in first coordinate system + sal_Int32 nDimCount = xCooSys->getDimension(); + sal_Int32 nDim=0; + for( nDim=0; nDim xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ); + if( !xAxis.is()) + { + // create and add axis + xAxis.set( AxisHelper::createAxis( + nDim, nAxisIndex, xCooSys, GetComponentContext() )); + } + } + } +} + +void ChartTypeTemplate::adaptAxes( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys ) +{ + //adapt properties of existing axes and remove superfluous axes + + if( rCoordSys.empty() ) + return; + + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : rCoordSys ) + { + if( !xCooSys.is() ) + continue; + sal_Int32 nDimCount = xCooSys->getDimension(); + for( sal_Int32 nDim=0; nDimgetMaximumAxisIndexByDimension( nDim ); + for( sal_Int32 nAxisIndex=0; nAxisIndex<=nMaxAxisIndex; nAxisIndex++ ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ); + if( !xAxis.is() ) + continue; + + if( nAxisIndex == MAIN_AXIS_INDEX || nAxisIndex == SECONDARY_AXIS_INDEX ) + { + // adapt scales + bool bPercent = (getStackMode(0) == StackMode::YStackedPercent); + if( bPercent && nDim == 1 ) + { + // set number format to source format + xAxis->setPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT, uno::Any(true)); + xAxis->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any()); + } + } + } + } + } +} + +sal_Int32 ChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension ) +{ + return (nDimension < getDimension()) ? 1 : 0; +} + +void ChartTypeTemplate::FillDiagram( + const rtl::Reference< ::chart::Diagram >& xDiagram, + const std::vector< std::vector< rtl::Reference< DataSeries > > >& aSeriesSeq, + const uno::Reference< chart2::data::XLabeledDataSequence >& xCategories, + const std::vector< rtl::Reference< ChartType > >& aOldChartTypesSeq ) +{ + adaptDiagram( xDiagram ); + + try + { + // create coordinate systems and scales + createCoordinateSystems( xDiagram ); + std::vector< rtl::Reference< BaseCoordinateSystem > > aCoordinateSystems( xDiagram->getBaseCoordinateSystems()); + createAxes( aCoordinateSystems ); + adaptAxes( aCoordinateSystems ); + adaptScales( aCoordinateSystems, xCategories ); + + // chart types + createChartTypes( aSeriesSeq, aCoordinateSystems, aOldChartTypesSeq ); + applyStyles( xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::createChartTypes( + const std::vector< std::vector< rtl::Reference< DataSeries > > > & aSeriesSeq, + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > >& aOldChartTypesSeq ) +{ + if( rCoordSys.empty() ) + return; + + try + { + std::size_t nCooSysIdx=0; + rtl::Reference< ChartType > xCT; + if( aSeriesSeq.empty() ) + { + // we need a new chart type + xCT = getChartTypeForNewSeries2( aOldChartTypesSeq ); + rCoordSys[nCooSysIdx]->setChartTypes(std::vector{ xCT }); + } + else + { + for( std::size_t nSeriesIdx=0; nSeriesIdx > aCTSeq( rCoordSys[nCooSysIdx]->getChartTypes2()); + if( !aCTSeq.empty()) + { + aCTSeq[0] = xCT; + rCoordSys[nCooSysIdx]->setChartTypes( aCTSeq ); + } + else + rCoordSys[nCooSysIdx]->addChartType( xCT ); + + xCT->setDataSeries( aSeriesSeq[nSeriesIdx] ); + } + else + { + // reuse existing chart type + OSL_ASSERT( xCT.is()); + std::vector< rtl::Reference< DataSeries > > aNewSeriesSeq = xCT->getDataSeries2(); + sal_Int32 nNewStartIndex = aNewSeriesSeq.size(); + aNewSeriesSeq.resize( nNewStartIndex + aSeriesSeq[nSeriesIdx].size() ); + std::copy( aSeriesSeq[nSeriesIdx].begin(), + aSeriesSeq[nSeriesIdx].end(), + aNewSeriesSeq.begin() + nNewStartIndex ); + xCT->setDataSeries( aNewSeriesSeq ); + } + + // spread the series over the available coordinate systems + if( rCoordSys.size() > (nCooSysIdx + 1) ) + ++nCooSysIdx; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( + const std::vector< rtl::Reference< ChartType > > & rOldChartTypesSeq, + const rtl::Reference< ChartType > & xNewChartType ) +{ + if( !xNewChartType.is() ) + return; + + OUString aNewChartType( xNewChartType->getChartType() ); + + Reference< beans::XPropertySet > xSource; + for( rtl::Reference< ChartType > const & xOldType : rOldChartTypesSeq ) + { + if( xOldType.is() && xOldType->getChartType() == aNewChartType ) + { + xSource = xOldType; + if( xSource.is() ) + break; + } + } + if( xSource.is() ) + comphelper::copyProperties( xSource, xNewChartType ); +} + +css::uno::Reference< css::uno::XInterface > ChartTypeTemplate::getDataInterpreter() +{ + return static_cast(getDataInterpreter2().get()); +} +css::uno::Reference< css::chart2::XDiagram > ChartTypeTemplate::createDiagramByDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) +{ + return createDiagramByDataSource2(xDataSource, aArguments); +} +void ChartTypeTemplate::changeDiagram( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) +{ + changeDiagram(rtl::Reference(dynamic_cast(xDiagram.get()))); +} +void ChartTypeTemplate::changeDiagramData( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram, + const css::uno::Reference< css::chart2::data::XDataSource >& xDataSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments ) +{ + changeDiagramData(rtl::Reference(dynamic_cast(xDiagram.get())), xDataSource, aArguments); +} +sal_Bool ChartTypeTemplate::matchesTemplate( + const css::uno::Reference& xDiagram, + sal_Bool bAdaptProperties ) +{ + return matchesTemplate2(dynamic_cast(xDiagram.get()), static_cast(bAdaptProperties)); +} +css::uno::Reference< ::css::chart2::XChartType > ChartTypeTemplate::getChartTypeForNewSeries( + const css::uno::Sequence< css::uno::Reference< css::chart2::XChartType > >& aFormerlyUsedChartTypes ) +{ + std::vector< rtl::Reference< ::chart::ChartType > > aTmp; + aTmp.reserve(aFormerlyUsedChartTypes.getLength()); + for (auto const & rxChartType : aFormerlyUsedChartTypes) + aTmp.push_back(dynamic_cast(rxChartType.get())); + return getChartTypeForNewSeries2(aTmp); +} +void ChartTypeTemplate::applyStyle( + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + applyStyle2(dynamic_cast(xSeries.get()), nChartTypeIndex, nSeriesIndex, nSeriesCount); +} +void ChartTypeTemplate::resetStyles( + const css::uno::Reference< css::chart2::XDiagram >& xDiagram ) +{ + resetStyles2(dynamic_cast(xDiagram.get())); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnChartType.cxx b/chart2/source/model/template/ColumnChartType.cxx new file mode 100644 index 000000000..50fdca0e1 --- /dev/null +++ b/chart2/source/model/template/ColumnChartType.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ColumnChartType.hxx" +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_BARCHARTTYPE_OVERLAP_SEQUENCE, + PROP_BARCHARTTYPE_GAPWIDTH_SEQUENCE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "OverlapSequence", + PROP_BARCHARTTYPE_OVERLAP_SEQUENCE, + cppu::UnoType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "GapwidthSequence", + PROP_BARCHARTTYPE_GAPWIDTH_SEQUENCE, + cppu::UnoType>::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +struct StaticColumnChartTypeDefaults_Initializer +{ + ::chart::tPropertyValueMap* operator()() + { + static ::chart::tPropertyValueMap aStaticDefaults; + lcl_AddDefaultsToMap( aStaticDefaults ); + return &aStaticDefaults; + } +private: + static void lcl_AddDefaultsToMap( ::chart::tPropertyValueMap & rOutMap ) + { + Sequence< sal_Int32 > aSeq{ 0, 0 }; + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_BARCHARTTYPE_OVERLAP_SEQUENCE, aSeq ); + + aSeq = { 100, 100 }; + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_BARCHARTTYPE_GAPWIDTH_SEQUENCE, aSeq ); + } +}; + +struct StaticColumnChartTypeDefaults : public rtl::StaticAggregate< ::chart::tPropertyValueMap, StaticColumnChartTypeDefaults_Initializer > +{ +}; + +struct StaticColumnChartTypeInfoHelper_Initializer +{ + ::cppu::OPropertyArrayHelper* operator()() + { + static ::cppu::OPropertyArrayHelper aPropHelper( lcl_GetPropertySequence() ); + return &aPropHelper; + } + +private: + static Sequence< Property > lcl_GetPropertySequence() + { + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + } + +}; + +struct StaticColumnChartTypeInfoHelper : public rtl::StaticAggregate< ::cppu::OPropertyArrayHelper, StaticColumnChartTypeInfoHelper_Initializer > +{ +}; + +struct StaticColumnChartTypeInfo_Initializer +{ + uno::Reference< beans::XPropertySetInfo >* operator()() + { + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(*StaticColumnChartTypeInfoHelper::get() ) ); + return &xPropertySetInfo; + } +}; + +struct StaticColumnChartTypeInfo : public rtl::StaticAggregate< uno::Reference< beans::XPropertySetInfo >, StaticColumnChartTypeInfo_Initializer > +{ +}; + +} // anonymous namespace + +namespace chart +{ + +ColumnChartType::ColumnChartType() +{} + +ColumnChartType::ColumnChartType( const ColumnChartType & rOther ) : + ChartType( rOther ) +{ +} + +ColumnChartType::~ColumnChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL ColumnChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new ColumnChartType( *this )); +} + +rtl::Reference< ChartType > ColumnChartType::cloneChartType() const +{ + return new ColumnChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL ColumnChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_COLUMN; +} + +uno::Sequence< OUString > ColumnChartType::getSupportedPropertyRoles() +{ + return { "FillColor", "BorderColor" }; +} + +// ____ OPropertySet ____ +void ColumnChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = *StaticColumnChartTypeDefaults::get(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL ColumnChartType::getInfoHelper() +{ + return *StaticColumnChartTypeInfoHelper::get(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ColumnChartType::getPropertySetInfo() +{ + return *StaticColumnChartTypeInfo::get(); +} + +OUString SAL_CALL ColumnChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.ColumnChartType"; +} + +sal_Bool SAL_CALL ColumnChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ColumnChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_COLUMN, + "com.sun.star.chart2.ChartType" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ColumnChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ColumnChartType()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnChartType.hxx b/chart2/source/model/template/ColumnChartType.hxx new file mode 100644 index 000000000..2c6b3d762 --- /dev/null +++ b/chart2/source/model/template/ColumnChartType.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class ColumnChartType final : public ChartType +{ +public: + explicit ColumnChartType(); + virtual ~ColumnChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit ColumnChartType( const ColumnChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedPropertyRoles() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnLineChartTypeTemplate.cxx b/chart2/source/model/template/ColumnLineChartTypeTemplate.cxx new file mode 100644 index 000000000..f0a18708a --- /dev/null +++ b/chart2/source/model/template/ColumnLineChartTypeTemplate.cxx @@ -0,0 +1,356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ColumnLineChartTypeTemplate.hxx" +#include "ColumnChartType.hxx" +#include "LineChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "ColumnLineDataInterpreter.hxx" +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star::chart2; +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_COL_LINE_NUMBER_OF_LINES +}; + +::chart::tPropertyValueMap& StaticColumnLineChartTypeTemplateDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_COL_LINE_NUMBER_OF_LINES, 1 ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticColumnLineChartTypeTemplateInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { "NumberOfLines", + PROP_COL_LINE_NUMBER_OF_LINES, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }()); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticColumnLineChartTypeTemplateInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticColumnLineChartTypeTemplateInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +ColumnLineChartTypeTemplate::ColumnLineChartTypeTemplate( + Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + sal_Int32 nNumberOfLines ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_eStackMode( eStackMode ) +{ + setFastPropertyValue_NoBroadcast( PROP_COL_LINE_NUMBER_OF_LINES, uno::Any( nNumberOfLines )); +} + +ColumnLineChartTypeTemplate::~ColumnLineChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void ColumnLineChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticColumnLineChartTypeTemplateDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL ColumnLineChartTypeTemplate::getInfoHelper() +{ + return StaticColumnLineChartTypeTemplateInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ColumnLineChartTypeTemplate::getPropertySetInfo() +{ + return StaticColumnLineChartTypeTemplateInfo(); +} + +void ColumnLineChartTypeTemplate::createChartTypes( + const std::vector< std::vector< rtl::Reference< DataSeries > > > & aSeriesSeq, + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > >& aOldChartTypesSeq ) +{ + if( rCoordSys.empty() ) + return; + + try + { + const std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq )); + sal_Int32 nNumberOfSeries = aFlatSeriesSeq.size(); + sal_Int32 nNumberOfLines = 0; + sal_Int32 nNumberOfColumns = 0; + + getFastPropertyValue( PROP_COL_LINE_NUMBER_OF_LINES ) >>= nNumberOfLines; + OSL_ENSURE( nNumberOfLines>=0, "number of lines should be not negative" ); + if( nNumberOfLines < 0 ) + nNumberOfLines = 0; + + if( nNumberOfLines >= nNumberOfSeries ) + { + if( nNumberOfSeries > 0 ) + { + nNumberOfLines = nNumberOfSeries - 1; + nNumberOfColumns = 1; + } + else + nNumberOfLines = 0; + } + else + nNumberOfColumns = nNumberOfSeries - nNumberOfLines; + + // Columns + + rtl::Reference< ChartType > xCT = new ColumnChartType(); + + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aOldChartTypesSeq, xCT ); + + rCoordSys[ 0 ]->setChartTypes( std::vector{xCT} ); + + if( nNumberOfColumns > 0 ) + { + std::vector< rtl::Reference< DataSeries > > aColumnSeq( nNumberOfColumns ); + std::copy( aFlatSeriesSeq.begin(), + aFlatSeriesSeq.begin() + nNumberOfColumns, + aColumnSeq.begin()); + xCT->setDataSeries( aColumnSeq ); + } + + // Lines + + xCT = new LineChartType(); + rCoordSys[ 0 ]->addChartType( xCT ); + + if( nNumberOfLines > 0 ) + { + std::vector< rtl::Reference< DataSeries > > aLineSeq( nNumberOfLines ); + std::copy( aFlatSeriesSeq.begin() + nNumberOfColumns, + aFlatSeriesSeq.end(), + aLineSeq.begin()); + xCT->setDataSeries( aLineSeq ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ColumnLineChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + + if( nChartTypeIndex==0 ) // columns + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); + } + else if( nChartTypeIndex==1 ) // lines + { + DataSeriesHelper::switchLinesOnOrOff( xSeries, true ); + DataSeriesHelper::switchSymbolsOnOrOff( xSeries, false, nSeriesIndex ); + DataSeriesHelper::makeLinesThickOrThin( xSeries, true ); + } +} + +StackMode ColumnLineChartTypeTemplate::getStackMode( sal_Int32 nChartTypeIndex ) const +{ + if( nChartTypeIndex == 0 ) + return m_eStackMode; + return StackMode::NONE; +} + +// ____ XChartTypeTemplate ____ +bool ColumnLineChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = false; + + if( ! xDiagram.is()) + return bResult; + + try + { + rtl::Reference< ChartType > xColumnChartType; + rtl::Reference< BaseCoordinateSystem > xColumnChartCooSys; + rtl::Reference< ChartType > xLineChartType; + sal_Int32 nNumberOfChartTypes = 0; + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + const std::vector< rtl::Reference< ChartType > > aChartTypeSeq( coords->getChartTypes2()); + for( rtl::Reference< ChartType > const & chartType : aChartTypeSeq ) + { + ++nNumberOfChartTypes; + if( nNumberOfChartTypes > 2 ) + break; + OUString aCTService = chartType->getChartType(); + if( aCTService == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) + { + xColumnChartType = chartType; + xColumnChartCooSys = coords; + } + else if( aCTService == CHART2_SERVICE_NAME_CHARTTYPE_LINE ) + xLineChartType = chartType; + } + if( nNumberOfChartTypes > 2 ) + break; + } + + if( nNumberOfChartTypes == 2 && + xColumnChartType.is() && + xLineChartType.is()) + { + OSL_ASSERT( xColumnChartCooSys.is()); + + // check stackmode of bars + bResult = (xColumnChartCooSys->getDimension() == getDimension()); + if( bResult ) + { + bool bFound=false; + bool bAmbiguous=false; + bResult = ( DiagramHelper::getStackModeFromChartType( + xColumnChartType, bFound, bAmbiguous, + xColumnChartCooSys ) + == getStackMode( 0 ) ); + + if( bResult && bAdaptProperties ) + { + if( xLineChartType.is() ) + { + sal_Int32 nNumberOfLines = xLineChartType->getDataSeries().getLength(); + setFastPropertyValue_NoBroadcast( PROP_COL_LINE_NUMBER_OF_LINES, uno::Any( nNumberOfLines )); + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return bResult; +} + +rtl::Reference< ChartType > ColumnLineChartTypeTemplate::getChartTypeForIndex( sal_Int32 nChartTypeIndex ) +{ + if( nChartTypeIndex == 0 ) + return new ColumnChartType(); + else + return new LineChartType(); +} + +rtl::Reference< ChartType > ColumnLineChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new LineChartType(); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< DataInterpreter > ColumnLineChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + { + sal_Int32 nNumberOfLines = 1; + getFastPropertyValue( PROP_COL_LINE_NUMBER_OF_LINES ) >>= nNumberOfLines; + m_xDataInterpreter = new ColumnLineDataInterpreter( nNumberOfLines ); + } + else + { + //todo... + OSL_FAIL( "number of lines may not be valid anymore in the datainterpreter" ); + + } + + return m_xDataInterpreter; +} + +IMPLEMENT_FORWARD_XINTERFACE2( ColumnLineChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( ColumnLineChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnLineChartTypeTemplate.hxx b/chart2/source/model/template/ColumnLineChartTypeTemplate.hxx new file mode 100644 index 000000000..f76f329a1 --- /dev/null +++ b/chart2/source/model/template/ColumnLineChartTypeTemplate.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include +#include +#include + +namespace chart +{ + +class ColumnLineChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + explicit ColumnLineChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + sal_Int32 nNumberOfLines ); + virtual ~ColumnLineChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual rtl::Reference< ::chart::DataInterpreter > getDataInterpreter2() override; + + // ____ ChartTypeTemplate ____ + virtual void createChartTypes( + const std::vector< + std::vector< + rtl::Reference< + ::chart::DataSeries > > > & aSeriesSeq, + const std::vector< + rtl::Reference< + ::chart::BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > > & aOldChartTypesSeq + ) override; + + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + +private: + StackMode m_eStackMode; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnLineDataInterpreter.cxx b/chart2/source/model/template/ColumnLineDataInterpreter.cxx new file mode 100644 index 000000000..15ce4adce --- /dev/null +++ b/chart2/source/model/template/ColumnLineDataInterpreter.cxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ColumnLineDataInterpreter.hxx" +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +// explicit +ColumnLineDataInterpreter::ColumnLineDataInterpreter( + sal_Int32 nNumberOfLines ) : + m_nNumberOfLines( nNumberOfLines ) +{} + +ColumnLineDataInterpreter::~ColumnLineDataInterpreter() +{} + +// ____ DataInterpreter ____ +InterpretedData ColumnLineDataInterpreter::interpretDataSource( + const Reference< data::XDataSource >& xSource, + const Sequence< beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse ) +{ + InterpretedData aResult( DataInterpreter::interpretDataSource( xSource, aArguments, aSeriesToReUse )); + + // the base class should return one group + OSL_ASSERT( aResult.Series.size() == 1 ); + if( aResult.Series.size() == 1 ) + { + sal_Int32 nNumberOfSeries = aResult.Series[0].size(); + + // if we have more than one series put the last nNumOfLines ones into a new group + if( nNumberOfSeries > 1 && m_nNumberOfLines > 0 ) + { + sal_Int32 nNumOfLines = std::min( m_nNumberOfLines, nNumberOfSeries - 1 ); + aResult.Series.resize(2); + + std::vector< rtl::Reference< DataSeries > > & rColumnDataSeries = aResult.Series[0]; + std::vector< rtl::Reference< DataSeries > > & rLineDataSeries = aResult.Series[1]; + rLineDataSeries.resize( nNumOfLines ); + std::copy( std::cbegin(rColumnDataSeries) + nNumberOfSeries - nNumOfLines, + std::cbegin(rColumnDataSeries) + nNumberOfSeries, + rLineDataSeries.begin() ); + rColumnDataSeries.resize( nNumberOfSeries - nNumOfLines ); + } + } + + return aResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ColumnLineDataInterpreter.hxx b/chart2/source/model/template/ColumnLineDataInterpreter.hxx new file mode 100644 index 000000000..c2ec75826 --- /dev/null +++ b/chart2/source/model/template/ColumnLineDataInterpreter.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +class ColumnLineDataInterpreter : public DataInterpreter +{ +public: + explicit ColumnLineDataInterpreter(sal_Int32 nNumberOfLines); + virtual ~ColumnLineDataInterpreter() override; + +protected: + // ____ DataInterpreter ____ + virtual InterpretedData interpretDataSource( + const css::uno::Reference& xSource, + const css::uno::Sequence& aArguments, + const std::vector>& aSeriesToReUse) override; + +private: + sal_Int32 m_nNumberOfLines; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/DataInterpreter.cxx b/chart2/source/model/template/DataInterpreter.cxx new file mode 100644 index 000000000..5b8899dcc --- /dev/null +++ b/chart2/source/model/template/DataInterpreter.cxx @@ -0,0 +1,445 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +#ifdef DEBUG_CHART2_TEMPLATE +namespace +{ +void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource ); +} +#endif + +namespace chart +{ + +DataInterpreter::DataInterpreter() +{} + +DataInterpreter::~DataInterpreter() +{} + +// ____ XDataInterpreter ____ +InterpretedData DataInterpreter::interpretDataSource( + const Reference< data::XDataSource >& xSource, + const Sequence< beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse ) +{ + if( ! xSource.is()) + return InterpretedData(); + +#ifdef DEBUG_CHART2_TEMPLATE + lcl_ShowDataSource( xSource ); +#endif + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = getDataSequences(xSource); + + uno::Reference< chart2::data::XLabeledDataSequence > xCategories; + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequencesVec; + + // check if we should use categories + + bool bHasCategories( HasCategories( aArguments, aData )); + + // parse data + bool bCategoriesUsed = false; + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aData ) + { + try + { + if( bHasCategories && ! bCategoriesUsed ) + { + xCategories = labeledData; + if( xCategories.is()) + SetRole( xCategories->getValues(), "categories"); + bCategoriesUsed = true; + } + else + { + aSequencesVec.push_back( labeledData ); + if( labeledData.is()) + SetRole( labeledData->getValues(), "values-y"); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + // create DataSeries + std::size_t nSeriesIndex = 0; + vector< rtl::Reference< DataSeries > > aSeriesVec; + aSeriesVec.reserve( aSequencesVec.size()); + + for (auto const& elem : aSequencesVec) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewData { elem }; + rtl::Reference< DataSeries > xSeries; + if( nSeriesIndex < aSeriesToReUse.size()) + xSeries = aSeriesToReUse[nSeriesIndex]; + else + xSeries = new DataSeries; + assert( xSeries.is() ); + xSeries->setData( aNewData ); + + aSeriesVec.push_back( xSeries ); + ++nSeriesIndex; + } + + return { { aSeriesVec }, xCategories }; +} + +InterpretedData DataInterpreter::reinterpretDataSeries( + const InterpretedData& aInterpretedData ) +{ + InterpretedData aResult( aInterpretedData ); + + sal_Int32 i=0; + std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); + const sal_Int32 nCount = aSeries.size(); + for( ; i > aNewSequences; + + // values-y + uno::Reference< data::XLabeledDataSequence > xValuesY = + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-y" ); + // re-use values-... as values-y + if( ! xValuesY.is()) + { + xValuesY = + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values", true ); + if( xValuesY.is()) + SetRole( xValuesY->getValues(), "values-y"); + } + if( xValuesY.is()) + { + aNewSequences = { xValuesY }; + } + + const std::vector< uno::Reference< data::XLabeledDataSequence > > & aSeqs = aSeries[i]->getDataSequences2(); + if( aSeqs.size() != aNewSequences.size() ) + { +#ifdef DEBUG_CHART2_TEMPLATE + sal_Int32 j=0; + for( ; jsetData( aNewSequences ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +// criterion: all series must have exactly one data::XLabeledDataSequence +bool DataInterpreter::isDataCompatible( + const InterpretedData& aInterpretedData ) +{ + const std::vector< rtl::Reference< DataSeries > > aSeries( FlattenSequence( aInterpretedData.Series )); + for( rtl::Reference< DataSeries > const & i : aSeries ) + { + try + { + if( i->getDataSequences2().size() != 1 ) + return false; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return true; +} + +namespace +{ + +struct lcl_LabeledSequenceEquals +{ + explicit lcl_LabeledSequenceEquals( const Reference< data::XLabeledDataSequence > & xLSeqToCmp ) : + m_bHasLabels ( false ), + m_bHasValues ( false ) + { + if( !xLSeqToCmp.is()) + return; + + Reference< data::XDataSequence > xSeq( xLSeqToCmp->getValues()); + if( xSeq.is()) + { + m_bHasValues = true; + m_aValuesRangeRep = xSeq->getSourceRangeRepresentation(); + } + + xSeq.set( xLSeqToCmp->getLabel()); + if( xSeq.is()) + { + m_bHasLabels = true; + m_aLabelRangeRep = xSeq->getSourceRangeRepresentation(); + } + } + + bool operator() ( const Reference< data::XLabeledDataSequence > & xSeq ) + { + if( ! xSeq.is()) + return false; + + Reference< data::XDataSequence > xSeqValues( xSeq->getValues() ); + Reference< data::XDataSequence > xSeqLabels( xSeq->getLabel() ); + bool bHasValues = xSeqValues.is(); + bool bHasLabels = xSeqLabels.is(); + + return ( ( (m_bHasValues == bHasValues) && + (!bHasValues || m_aValuesRangeRep == xSeqValues->getSourceRangeRepresentation()) ) && + ( (m_bHasLabels == bHasLabels) && + (!bHasLabels || m_aLabelRangeRep == xSeqLabels->getSourceRangeRepresentation()) ) + ); + } + +private: + bool m_bHasLabels; + bool m_bHasValues; + OUString m_aValuesRangeRep; + OUString m_aLabelRangeRep; +}; + +} // anonymous namespace + +rtl::Reference< DataSource > DataInterpreter::mergeInterpretedData( + const InterpretedData& aInterpretedData ) +{ + vector< Reference< data::XLabeledDataSequence > > aResultVec; + aResultVec.reserve( aInterpretedData.Series.size() + + 1 // categories + ); + + if( aInterpretedData.Categories.is()) + aResultVec.push_back( aInterpretedData.Categories ); + + const std::vector< rtl::Reference< DataSeries > > aSeries = FlattenSequence( aInterpretedData.Series ); + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + try + { + // add all sequences of data series + for( uno::Reference< data::XLabeledDataSequence > const & xAdd : dataSeries->getDataSequences2() ) + { + // only add if sequence is not yet in the result + if( none_of( aResultVec.begin(), aResultVec.end(), + lcl_LabeledSequenceEquals( xAdd )) ) + { + aResultVec.push_back( xAdd ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return new DataSource(aResultVec); +} + +uno::Any DataInterpreter::getChartTypeSpecificData( + const OUString & ) +{ + return uno::Any(); +} + +// convenience methods + +OUString DataInterpreter::GetRole( const Reference< data::XDataSequence > & xSeq ) +{ + OUString aResult; + if( ! xSeq.is()) + return aResult; + + try + { + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + xProp->getPropertyValue( "Role") >>= aResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aResult; +} + +void DataInterpreter::SetRole( const Reference< data::XDataSequence > & xSeq, const OUString & rRole ) +{ + if( ! xSeq.is()) + return; + try + { + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + xProp->setPropertyValue( "Role", uno::Any( rRole )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +uno::Any DataInterpreter::GetProperty( + const Sequence< beans::PropertyValue > & aArguments, + std::u16string_view rName ) +{ + for( sal_Int32 i=aArguments.getLength(); i--; ) + { + if( aArguments[i].Name == rName ) + return aArguments[i].Value; + } + return uno::Any(); +} + +bool DataInterpreter::HasCategories( + const Sequence< beans::PropertyValue > & rArguments, + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & rData ) +{ + bool bHasCategories = false; + + if( rArguments.hasElements() ) + GetProperty( rArguments, u"HasCategories" ) >>= bHasCategories; + + for( std::size_t nLSeqIdx=0; ! bHasCategories && nLSeqIdxgetValues() ) == "categories"); + + return bHasCategories; +} + +bool DataInterpreter::UseCategoriesAsX( const Sequence< beans::PropertyValue > & rArguments ) +{ + bool bUseCategoriesAsX = true; + if( rArguments.hasElements() ) + GetProperty( rArguments, u"UseCategoriesAsX" ) >>= bUseCategoriesAsX; + return bUseCategoriesAsX; +} + +OUString SAL_CALL DataInterpreter::getImplementationName() +{ + return "com.sun.star.comp.chart2.DataInterpreter"; +} + +sal_Bool SAL_CALL DataInterpreter::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataInterpreter::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.DataInterpreter" }; +} + +std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > DataInterpreter::getDataSequences( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource) +{ + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData; + for (const Reference< data::XLabeledDataSequence > & rLDS : xSource->getDataSequences() ) + { + aData.push_back(rLDS); + } + return aData; +} + +} // namespace chart + +#ifdef DEBUG_CHART2_TEMPLATE +namespace +{ + +void lcl_ShowDataSource( const Reference< data::XDataSource > & xSource ) +{ + if( ! xSource.is()) + return; + + SAL_INFO("chart2", "DataSource in DataInterpreter:" ); + Sequence< Reference< data::XLabeledDataSequence > > aSequences( xSource->getDataSequences()); + Reference< beans::XPropertySet > xProp; + OUString aId; + const sal_Int32 nMax = aSequences.getLength(); + for( sal_Int32 k = 0; k < nMax; ++k ) + { + if( aSequences[k].is()) + { + OUString aSourceRepr(""); + if( aSequences[k]->getValues().is()) + aSourceRepr = aSequences[k]->getValues()->getSourceRangeRepresentation(); + xProp.set( aSequences[k]->getValues(), uno::UNO_QUERY ); + if( xProp.is() && + ( xProp->getPropertyValue( "Role") >>= aId )) + { + SAL_INFO("chart2", " Role: " << aId << ", Source: "<< aSourceRepr); + } + else + { + SAL_INFO("chart2", " unknown Role, Source: " << aSourceRepr ); + } + + aSourceRepr = ""; + if( aSequences[k]->getLabel().is()) + aSourceRepr = aSequences[k]->getLabel()->getSourceRangeRepresentation(); + xProp.set( aSequences[k]->getLabel(), uno::UNO_QUERY ); + if( xProp.is() && + ( xProp->getPropertyValue( "Role") >>= aId )) + { + SAL_INFO("chart2", " Role: " << aId + << ", Source: " << aSourceRepr ); + } + else + { + SAL_INFO("chart2", " unknown Role, Source: " << aSourceRepr ); + } + } + } +} + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/FilledNetChartType.cxx b/chart2/source/model/template/FilledNetChartType.cxx new file mode 100644 index 000000000..6ec39d983 --- /dev/null +++ b/chart2/source/model/template/FilledNetChartType.cxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "FilledNetChartType.hxx" +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +FilledNetChartType::FilledNetChartType() +{} + +FilledNetChartType::FilledNetChartType( const FilledNetChartType & rOther ) : + NetChartType_Base( rOther ) +{ +} + +FilledNetChartType::~FilledNetChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL FilledNetChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new FilledNetChartType( *this )); +} + +rtl::Reference< ChartType > FilledNetChartType::cloneChartType() const +{ + return new FilledNetChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL FilledNetChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET; +} + +OUString SAL_CALL FilledNetChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.FilledNetChartType"; +} + +sal_Bool SAL_CALL FilledNetChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL FilledNetChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_FilledNetChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::FilledNetChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/FilledNetChartType.hxx b/chart2/source/model/template/FilledNetChartType.hxx new file mode 100644 index 000000000..b2d239aec --- /dev/null +++ b/chart2/source/model/template/FilledNetChartType.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "NetChartType.hxx" + +namespace chart +{ +class FilledNetChartType final : public NetChartType_Base +{ +public: + explicit FilledNetChartType(); + virtual ~FilledNetChartType() override; + + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit FilledNetChartType(const FilledNetChartType& rOther); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + + // ____ XCloneable ____ + virtual css::uno::Reference SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/LineChartType.cxx b/chart2/source/model/template/LineChartType.cxx new file mode 100644 index 000000000..e9d7cf808 --- /dev/null +++ b/chart2/source/model/template/LineChartType.cxx @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "LineChartType.hxx" +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +enum +{ + PROP_LINECHARTTYPE_CURVE_STYLE, + PROP_LINECHARTTYPE_CURVE_RESOLUTION, + PROP_LINECHARTTYPE_SPLINE_ORDER +}; + +::chart::tPropertyValueMap& StaticLineChartTypeDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_LINECHARTTYPE_CURVE_STYLE, ::chart2::CurveStyle_LINES ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_LINECHARTTYPE_CURVE_RESOLUTION, 20 ); + + // todo: check whether order 3 means polygons of order 3 or 2. (see + // http://www.people.nnov.ru/fractal/Splines/Basis.htm ) + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_LINECHARTTYPE_SPLINE_ORDER, 3 ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticLineChartTypeInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { CHART_UNONAME_CURVE_STYLE, + PROP_LINECHARTTYPE_CURVE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_CURVE_RESOLUTION, + PROP_LINECHARTTYPE_CURVE_RESOLUTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_SPLINE_ORDER, + PROP_LINECHARTTYPE_SPLINE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }()); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticLineChartTypeInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticLineChartTypeInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +LineChartType::LineChartType() +{ +} + +LineChartType::LineChartType( const LineChartType & rOther ) : + ChartType( rOther ) +{ +} + +LineChartType::~LineChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL LineChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new LineChartType( *this )); +} + +rtl::Reference< ChartType > LineChartType::cloneChartType() const +{ + return new LineChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL LineChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_LINE; +} + +// ____ OPropertySet ____ +void LineChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticLineChartTypeDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL LineChartType::getInfoHelper() +{ + return StaticLineChartTypeInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL LineChartType::getPropertySetInfo() +{ + return StaticLineChartTypeInfo(); +} + +OUString SAL_CALL LineChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.LineChartType"; +} + +sal_Bool SAL_CALL LineChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LineChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_LINE, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_LineChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::LineChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/LineChartType.hxx b/chart2/source/model/template/LineChartType.hxx new file mode 100644 index 000000000..4c44cca9c --- /dev/null +++ b/chart2/source/model/template/LineChartType.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class LineChartType final : public ChartType +{ +public: + explicit LineChartType(); + virtual ~LineChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit LineChartType( const LineChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/LineChartTypeTemplate.cxx b/chart2/source/model/template/LineChartTypeTemplate.cxx new file mode 100644 index 000000000..65ce8def4 --- /dev/null +++ b/chart2/source/model/template/LineChartTypeTemplate.cxx @@ -0,0 +1,329 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "LineChartTypeTemplate.hxx" +#include "LineChartType.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE, + PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION, + PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER + +}; + +::chart::tPropertyValueMap& StaticLineChartTypeTemplateDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE, chart2::CurveStyle_LINES ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION, 20 ); + + // todo: check whether order 3 means polygons of order 3 or 2. (see + // http://www.people.nnov.ru/fractal/Splines/Basis.htm ) + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER, 3 ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticLineChartTypeTemplateInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { CHART_UNONAME_CURVE_STYLE, + PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_CURVE_RESOLUTION, + PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_SPLINE_ORDER, + PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }()); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticLineChartTypeTemplateInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticLineChartTypeTemplateInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +LineChartTypeTemplate::LineChartTypeTemplate( + uno::Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + bool bSymbols, + bool bHasLines /* = true */, + sal_Int32 nDim /* = 2 */ ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_eStackMode( eStackMode ), + m_bHasSymbols( bSymbols ), + m_bHasLines( bHasLines ), + m_nDim( nDim ) +{ + if( nDim == 3 ) + m_bHasSymbols = false; +} + +LineChartTypeTemplate::~LineChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void LineChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticLineChartTypeTemplateDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL LineChartTypeTemplate::getInfoHelper() +{ + return StaticLineChartTypeTemplateInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL LineChartTypeTemplate::getPropertySetInfo() +{ + return StaticLineChartTypeTemplateInfo(); +} + +sal_Int32 LineChartTypeTemplate::getDimension() const +{ + return m_nDim; +} + +StackMode LineChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return m_eStackMode; +} + +// ____ ChartTypeTemplate ____ +bool LineChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = ChartTypeTemplate::matchesTemplate2( xDiagram, bAdaptProperties ); + + // check symbol-style and line-style + // for a template with symbols (or with lines) it is ok, if there is at least one series + // with symbols (or with lines) + if( bResult ) + { + bool bSymbolFound = false; + bool bLineFound = false; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& series : aSeriesVec) + { + try + { + chart2::Symbol aSymbProp; + drawing::LineStyle eLineStyle; + + bool bCurrentHasSymbol = (series->getPropertyValue( "Symbol") >>= aSymbProp) && + (aSymbProp.Style != chart2::SymbolStyle_NONE); + + if( bCurrentHasSymbol ) + bSymbolFound = true; + + if( bCurrentHasSymbol && (!m_bHasSymbols) ) + { + bResult = false; + break; + } + + bool bCurrentHasLine = (series->getPropertyValue( "LineStyle") >>= eLineStyle) && + ( eLineStyle != drawing::LineStyle_NONE ); + + if( bCurrentHasLine ) + bLineFound = true; + + if( bCurrentHasLine && (!m_bHasLines) ) + { + bResult = false; + break; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if(bResult) + { + if( !bLineFound && m_bHasLines && bSymbolFound ) + bResult = false; + else if( !bSymbolFound && m_bHasSymbols && bLineFound ) + bResult = false; + else if( !bLineFound && !bSymbolFound ) + return m_bHasLines && m_bHasSymbols; + } + } + + // adapt curve style, spline order and resolution + if( bResult && bAdaptProperties ) + { + try + { + rtl::Reference< ChartType > xChartType = + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + setFastPropertyValue_NoBroadcast( PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE, xChartType->getPropertyValue(CHART_UNONAME_CURVE_STYLE) ); + setFastPropertyValue_NoBroadcast( PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION, xChartType->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) ); + setFastPropertyValue_NoBroadcast( PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER, xChartType->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +rtl::Reference< ChartType > LineChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new LineChartType(); + + xResult->setPropertyValue( + CHART_UNONAME_CURVE_STYLE, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE )); + xResult->setPropertyValue( + CHART_UNONAME_CURVE_RESOLUTION, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION )); + xResult->setPropertyValue( + CHART_UNONAME_SPLINE_ORDER, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< ChartType > LineChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new LineChartType(); + + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + + xResult->setPropertyValue( + CHART_UNONAME_CURVE_STYLE, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_CURVE_STYLE )); + xResult->setPropertyValue( + CHART_UNONAME_CURVE_RESOLUTION, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_CURVE_RESOLUTION )); + xResult->setPropertyValue( + CHART_UNONAME_SPLINE_ORDER, getFastPropertyValue( PROP_LINECHARTTYPE_TEMPLATE_SPLINE_ORDER )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +void LineChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + + try + { + DataSeriesHelper::switchSymbolsOnOrOff( xSeries, m_bHasSymbols, nSeriesIndex ); + DataSeriesHelper::switchLinesOnOrOff( xSeries, m_bHasLines ); + DataSeriesHelper::makeLinesThickOrThin( xSeries, m_nDim==2 ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +IMPLEMENT_FORWARD_XINTERFACE2( LineChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( LineChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/LineChartTypeTemplate.hxx b/chart2/source/model/template/LineChartTypeTemplate.hxx new file mode 100644 index 000000000..88ad1a7da --- /dev/null +++ b/chart2/source/model/template/LineChartTypeTemplate.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace chart +{ + +class LineChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + explicit LineChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + bool bSymbols, + bool bHasLines = true, + sal_Int32 nDim = 2 ); + virtual ~LineChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual sal_Int32 getDimension() const override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + +private: + StackMode m_eStackMode; + bool m_bHasSymbols; + bool m_bHasLines; + sal_Int32 m_nDim; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/NetChartType.cxx b/chart2/source/model/template/NetChartType.cxx new file mode 100644 index 000000000..cb4512c74 --- /dev/null +++ b/chart2/source/model/template/NetChartType.cxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "NetChartType.hxx" +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +NetChartType_Base::NetChartType_Base() +{} + +NetChartType_Base::NetChartType_Base( const NetChartType_Base & rOther ) : + ChartType( rOther ) +{ +} + +NetChartType_Base::~NetChartType_Base() +{} + +rtl::Reference< ::chart::BaseCoordinateSystem > + NetChartType_Base::createCoordinateSystem2( sal_Int32 DimensionCount ) +{ + if( DimensionCount != 2 ) + throw lang::IllegalArgumentException( + "NetChart must be two-dimensional", + static_cast< ::cppu::OWeakObject* >( this ), 0 ); + + rtl::Reference< PolarCoordinateSystem > xResult = + new PolarCoordinateSystem( DimensionCount ); + + rtl::Reference< Axis > xAxis = xResult->getAxisByDimension2( 0, MAIN_AXIS_INDEX ); + if( xAxis.is() ) + { + ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Scaling = AxisHelper::createLinearScaling(); + aScaleData.AxisType = AxisType::CATEGORY; + aScaleData.Orientation = AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + + xAxis = xResult->getAxisByDimension2( 1, MAIN_AXIS_INDEX ); + if( xAxis.is() ) + { + ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = AxisOrientation_MATHEMATICAL; + aScaleData.AxisType = AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + + return xResult; +} + +// ____ OPropertySet ____ +void NetChartType_Base::GetDefaultValue( sal_Int32 /*nHandle*/, uno::Any& rAny ) const +{ + rAny.clear(); +} + +namespace +{ + +::cppu::OPropertyArrayHelper& StaticNetChartTypeInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper(Sequence< beans::Property >{}); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticNetChartTypeInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticNetChartTypeInfoHelper() ) ); + return xPropertySetInfo; +} + +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL NetChartType_Base::getInfoHelper() +{ + return StaticNetChartTypeInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL NetChartType_Base::getPropertySetInfo() +{ + return StaticNetChartTypeInfo(); +} + +NetChartType::NetChartType() +{} + +NetChartType::NetChartType( const NetChartType & rOther ) : + NetChartType_Base( rOther ) +{ +} + +NetChartType::~NetChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL NetChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new NetChartType( *this )); +} + +rtl::Reference< ChartType > NetChartType::cloneChartType() const +{ + return new NetChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL NetChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_NET; +} + +OUString SAL_CALL NetChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.NetChartType"; +} + +sal_Bool SAL_CALL NetChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL NetChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_NET, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_NetChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::NetChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/NetChartType.hxx b/chart2/source/model/template/NetChartType.hxx new file mode 100644 index 000000000..ae414a27c --- /dev/null +++ b/chart2/source/model/template/NetChartType.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class NetChartType_Base : public ChartType +{ +public: + explicit NetChartType_Base(); + virtual ~NetChartType_Base() override; + +protected: + explicit NetChartType_Base( const NetChartType_Base & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + virtual rtl::Reference< ::chart::BaseCoordinateSystem > + createCoordinateSystem2( sal_Int32 DimensionCount ) override; +}; + +class NetChartType final : public NetChartType_Base +{ +public: + explicit NetChartType(); + virtual ~NetChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit NetChartType( const NetChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/NetChartTypeTemplate.cxx b/chart2/source/model/template/NetChartTypeTemplate.cxx new file mode 100644 index 000000000..158bffe0b --- /dev/null +++ b/chart2/source/model/template/NetChartTypeTemplate.cxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "NetChartTypeTemplate.hxx" +#include "FilledNetChartType.hxx" +#include "NetChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +NetChartTypeTemplate::NetChartTypeTemplate( + Reference< uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + bool bSymbols, + bool bHasLines , + bool bHasFilledArea ) : + ChartTypeTemplate( xContext, rServiceName ), + m_eStackMode( eStackMode ), + m_bHasSymbols( bSymbols ), + m_bHasLines( bHasLines ), + m_bHasFilledArea( bHasFilledArea ) +{} + +NetChartTypeTemplate::~NetChartTypeTemplate() +{} + +StackMode NetChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + return m_eStackMode; +} + +void NetChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + + try + { + DataSeriesHelper::switchSymbolsOnOrOff( xSeries, m_bHasSymbols, nSeriesIndex ); + DataSeriesHelper::switchLinesOnOrOff( xSeries, m_bHasLines ); + DataSeriesHelper::makeLinesThickOrThin( xSeries, true ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ ChartTypeTemplate ____ +bool NetChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = ChartTypeTemplate::matchesTemplate2( xDiagram, bAdaptProperties ); + + if( bResult ) + { + //filled net chart?: + if( m_bHasFilledArea ) + return true; + + // check symbol-style + // for a template with symbols it is ok, if there is at least one series + // with symbols, otherwise an unknown template is too easy to achieve + bool bSymbolFound = false; + bool bLineFound = false; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& series : aSeriesVec) + { + try + { + chart2::Symbol aSymbProp; + drawing::LineStyle eLineStyle; + + bool bCurrentHasSymbol = (series->getPropertyValue( "Symbol") >>= aSymbProp) && + (aSymbProp.Style != chart2::SymbolStyle_NONE); + + if( bCurrentHasSymbol ) + bSymbolFound = true; + + if( bCurrentHasSymbol && (!m_bHasSymbols) ) + { + bResult = false; + break; + } + + bool bCurrentHasLine = (series->getPropertyValue( "LineStyle") >>= eLineStyle) && + ( eLineStyle != drawing::LineStyle_NONE ); + + if( bCurrentHasLine ) + bLineFound = true; + + if( bCurrentHasLine && (!m_bHasLines) ) + { + bResult = false; + break; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if(bResult) + { + if( !bLineFound && m_bHasLines && bSymbolFound ) + bResult = false; + else if( !bSymbolFound && m_bHasSymbols && bLineFound ) + bResult = false; + else if( !bLineFound && !bSymbolFound ) + return m_bHasLines && m_bHasSymbols; + } + } + + return bResult; +} + +rtl::Reference< ChartType > NetChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + if( m_bHasFilledArea ) + return new FilledNetChartType(); + else + return new NetChartType(); +} + +rtl::Reference< ChartType > NetChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult( getChartTypeForIndex( 0 ) ); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + return xResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/NetChartTypeTemplate.hxx b/chart2/source/model/template/NetChartTypeTemplate.hxx new file mode 100644 index 000000000..b1f5ac9db --- /dev/null +++ b/chart2/source/model/template/NetChartTypeTemplate.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart +{ + +class NetChartTypeTemplate : public ChartTypeTemplate +{ +public: + explicit NetChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StackMode eStackMode, + bool bSymbols, + bool bHasLines = true, + bool bHasFilledArea = false + ); + virtual ~NetChartTypeTemplate() override; + +protected: + // ____ ChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + + // ____ ChartTypeTemplate ____ + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + +private: + StackMode m_eStackMode; + bool m_bHasSymbols; + bool m_bHasLines; + bool m_bHasFilledArea; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/PieChartType.cxx b/chart2/source/model/template/PieChartType.cxx new file mode 100644 index 000000000..fdbfc7ced --- /dev/null +++ b/chart2/source/model/template/PieChartType.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PieChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +enum +{ + PROP_PIECHARTTYPE_USE_RINGS, + PROP_PIECHARTTYPE_3DRELATIVEHEIGHT +}; + + +::chart::tPropertyValueMap& StaticPieChartTypeDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_PIECHARTTYPE_USE_RINGS, false ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_PIECHARTTYPE_3DRELATIVEHEIGHT, 100 ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticPieChartTypeInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { "UseRings", + PROP_PIECHARTTYPE_USE_RINGS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { "3DRelativeHeight", + PROP_PIECHARTTYPE_3DRELATIVEHEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID } + }; + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }()); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticPieChartTypeInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo( StaticPieChartTypeInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +PieChartType::PieChartType() +{ +} + +PieChartType::PieChartType( const PieChartType & rOther ) : + ChartType( rOther ) +{ +} + +PieChartType::~PieChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL PieChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new PieChartType( *this )); +} + +rtl::Reference< ChartType > PieChartType::cloneChartType() const +{ + return new PieChartType( *this ); +} + +// ____ XChartType ____ +OUString SAL_CALL PieChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_PIE; +} + +rtl::Reference< ::chart::BaseCoordinateSystem > + PieChartType::createCoordinateSystem2( sal_Int32 DimensionCount ) +{ + rtl::Reference< PolarCoordinateSystem > xResult = + new PolarCoordinateSystem( DimensionCount ); + + for( sal_Int32 i=0; i xAxis = xResult->getAxisByDimension2( i, MAIN_AXIS_INDEX ); + if( !xAxis.is() ) + { + OSL_FAIL("a created coordinate system should have an axis for each dimension"); + continue; + } + + //hhhh todo make axis invisible + + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Scaling = AxisHelper::createLinearScaling(); + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + + if( i == 0 ) + aScaleData.Orientation = chart2::AxisOrientation_REVERSE; + else + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + + //remove explicit scalings from all axes + AxisHelper::removeExplicitScaling( aScaleData ); + + xAxis->setScaleData( aScaleData ); + } + + return xResult; +} + +uno::Sequence< OUString > PieChartType::getSupportedPropertyRoles() +{ + return { "FillColor", "BorderColor" }; +} + +// ____ OPropertySet ____ +void PieChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticPieChartTypeDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL PieChartType::getInfoHelper() +{ + return StaticPieChartTypeInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL PieChartType::getPropertySetInfo() +{ + return StaticPieChartTypeInfo(); +} + +OUString SAL_CALL PieChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.PieChartType"; +} + +sal_Bool SAL_CALL PieChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PieChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_PIE, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_PieChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PieChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/PieChartType.hxx b/chart2/source/model/template/PieChartType.hxx new file mode 100644 index 000000000..5a1e46f43 --- /dev/null +++ b/chart2/source/model/template/PieChartType.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class PieChartType final: public ChartType +{ +public: + explicit PieChartType(); + virtual ~PieChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit PieChartType( const PieChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedPropertyRoles() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + virtual rtl::Reference< ::chart::BaseCoordinateSystem > + createCoordinateSystem2( sal_Int32 DimensionCount ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/PieChartTypeTemplate.cxx b/chart2/source/model/template/PieChartTypeTemplate.cxx new file mode 100644 index 000000000..c8d82b761 --- /dev/null +++ b/chart2/source/model/template/PieChartTypeTemplate.cxx @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PieChartTypeTemplate.hxx" +#include "PieChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +enum +{ + PROP_PIE_TEMPLATE_DEFAULT_OFFSET, + PROP_PIE_TEMPLATE_OFFSET_MODE, + PROP_PIE_TEMPLATE_DIMENSION, + PROP_PIE_TEMPLATE_USE_RINGS +}; + +::chart::tPropertyValueMap& StaticPieChartTypeTemplateDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []{ + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_PIE_TEMPLATE_OFFSET_MODE, chart2::PieChartOffsetMode_NONE ); + ::chart::PropertyHelper::setPropertyValueDefault< double >( aOutMap, PROP_PIE_TEMPLATE_DEFAULT_OFFSET, 0.5 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_PIE_TEMPLATE_DIMENSION, 2 ); + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_PIE_TEMPLATE_USE_RINGS, false ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticPieChartTypeTemplateInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { "OffsetMode", + PROP_PIE_TEMPLATE_OFFSET_MODE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { "DefaultOffset", + PROP_PIE_TEMPLATE_DEFAULT_OFFSET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { "Dimension", + PROP_PIE_TEMPLATE_DIMENSION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { "UseRings", + PROP_PIE_TEMPLATE_USE_RINGS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }() ); + return aPropHelper; +} + +uno::Reference< beans::XPropertySetInfo >& StaticPieChartTypeTemplateInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticPieChartTypeTemplateInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +PieChartTypeTemplate::PieChartTypeTemplate( + uno::Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + chart2::PieChartOffsetMode eMode, + bool bRings /* = false */, + sal_Int32 nDim /* = 2 */ ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ) +{ + setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_OFFSET_MODE, uno::Any( eMode )); + setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_DIMENSION, uno::Any( nDim )); + setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_USE_RINGS, uno::Any( bRings )); +} + +PieChartTypeTemplate::~PieChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void PieChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticPieChartTypeTemplateDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL PieChartTypeTemplate::getInfoHelper() +{ + return StaticPieChartTypeTemplateInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL PieChartTypeTemplate::getPropertySetInfo() +{ + return StaticPieChartTypeTemplateInfo(); +} + +// ____ ChartTypeTemplate ____ +sal_Int32 PieChartTypeTemplate::getDimension() const +{ + sal_Int32 nDim = 2; + try + { + // note: UNO-methods are never const + const_cast< PieChartTypeTemplate * >( this )-> + getFastPropertyValue( PROP_PIE_TEMPLATE_DIMENSION ) >>= nDim; + } + catch( const beans::UnknownPropertyException & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nDim; +} + +sal_Int32 PieChartTypeTemplate::getAxisCountByDimension( sal_Int32 /*nDimension*/ ) +{ + return 0; +} + +void PieChartTypeTemplate::adaptAxes( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & /*rCoordSys*/ ) +{ + // hide existing axes + //hhhh todo +} + +void PieChartTypeTemplate::adaptScales( + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysSeq, + const Reference< chart2::data::XLabeledDataSequence > & xCategories //@todo: in future there may be more than one sequence of categories (e.g. charttype with categories at x and y axis ) + ) +{ + ChartTypeTemplate::adaptScales( aCooSysSeq, xCategories ); + + //remove explicit scalings from radius axis + //and ensure correct orientation of scales for donuts + + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + try + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1 /*nDimensionIndex*/,0 /*nAxisIndex*/ + , coords ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + AxisHelper::removeExplicitScaling( aScaleData ); + // tdf#108059 Create new pie/donut charts with clockwise orientation + if (!officecfg::Office::Compatibility::View::ClockwisePieChartDirection::get()) + { + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + } + else + { + aScaleData.Orientation = chart2::AxisOrientation_REVERSE; + } + xAxis->setScaleData( aScaleData ); + } + + xAxis = AxisHelper::getAxis( 0 /*nDimensionIndex*/,0 /*nAxisIndex*/ + , coords ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + + //tdf#123218 Don't reverse the orientation in OOXML-heavy environments + if( officecfg::Office::Compatibility::View::ReverseXAxisOrientationDoughnutChart::get() ) + aScaleData.Orientation = chart2::AxisOrientation_REVERSE; + else + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +void PieChartTypeTemplate::createChartTypes( + const std::vector< std::vector< rtl::Reference< DataSeries > > > & aSeriesSeq, + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > >& /* aOldChartTypesSeq */ ) +{ + if( rCoordSys.empty() ) + return; + + try + { + rtl::Reference< ChartType > xCT = new PieChartType(); + xCT->setPropertyValue( + "UseRings", getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); + rCoordSys[0]->setChartTypes( std::vector{xCT} ); + + if( !aSeriesSeq.empty() ) + { + std::vector< rtl::Reference< DataSeries > > aFlatSeriesSeq = FlattenSequence( aSeriesSeq ); + xCT->setDataSeries( aFlatSeriesSeq ); + + DataSeriesHelper::setStackModeAtSeries( + aFlatSeriesSeq, rCoordSys[0], getStackMode( 0 )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XChartTypeTemplate ____ +bool PieChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = ChartTypeTemplate::matchesTemplate2( xDiagram, bAdaptProperties ); + + bool bTemplateUsesRings = false; + getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS ) >>= bTemplateUsesRings; + chart2::PieChartOffsetMode ePieOffsetMode; + getFastPropertyValue( PROP_PIE_TEMPLATE_OFFSET_MODE ) >>= ePieOffsetMode; + + //check offset-mode + if( bResult ) + { + try + { + double fOffset=0.0; + bool bAllOffsetsEqual = true; + sal_Int32 nOuterSeriesIndex = 0; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + //tdf#108067 The outer series is the last series in OOXML-heavy environments + if( !officecfg::Office::Compatibility::View::ReverseXAxisOrientationDoughnutChart::get() ) + nOuterSeriesIndex = aSeriesVec.size() - 1; + + //check offset of outer series + if( !aSeriesVec.empty() ) + { + //@todo in future this will depend on Orientation of the radius axis scale + rtl::Reference< DataSeries > xSeries( aSeriesVec[nOuterSeriesIndex] ); + xSeries->getPropertyValue( "Offset") >>= fOffset; + + //get AttributedDataPoints + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + uno::Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if(xPointProp.is()) + { + double fPointOffset=0.0; + if( xSeries->getPropertyValue( "Offset") >>= fPointOffset ) + { + if( ! ::rtl::math::approxEqual( fPointOffset, fOffset ) ) + { + bAllOffsetsEqual = false; + break; + } + } + } + } + } + } + + chart2::PieChartOffsetMode eOffsetMode = chart2::PieChartOffsetMode_NONE; + if( bAllOffsetsEqual && fOffset > 0.0 ) + { + eOffsetMode = chart2::PieChartOffsetMode_ALL_EXPLODED; + if( bAdaptProperties ) + setFastPropertyValue_NoBroadcast( PROP_PIE_TEMPLATE_DEFAULT_OFFSET, uno::Any( fOffset )); + } + + bResult = ( eOffsetMode == ePieOffsetMode ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + bResult = false; + } + } + + //check UseRings + if( bResult ) + { + rtl::Reference< ChartType > xCTProp = + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + bool bUseRings = false; + if( xCTProp->getPropertyValue( "UseRings") >>= bUseRings ) + { + bResult = ( bTemplateUsesRings == bUseRings ); + } + } + + return bResult; +} + +rtl::Reference< ChartType > PieChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new PieChartType(); + xResult->setPropertyValue( + "UseRings", getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< ChartType > PieChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new PieChartType(); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + xResult->setPropertyValue( + "UseRings", getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +void PieChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + + try + { + bool bTemplateUsesRings = false; + sal_Int32 nOuterSeriesIndex = 0; + getFastPropertyValue( PROP_PIE_TEMPLATE_USE_RINGS ) >>= bTemplateUsesRings; + + //tdf#108067 The outer series is the last series in OOXML-heavy environments + if( !officecfg::Office::Compatibility::View::ReverseXAxisOrientationDoughnutChart::get() ) + nOuterSeriesIndex = nSeriesCount - 1; + + if( nSeriesIndex == nOuterSeriesIndex ) //@todo in future this will depend on Orientation of the radius axis scale + { + static const OUStringLiteral aOffsetPropName( u"Offset" ); + // get offset mode + chart2::PieChartOffsetMode ePieOffsetMode; + getFastPropertyValue( PROP_PIE_TEMPLATE_OFFSET_MODE ) >>= ePieOffsetMode; + + // get default offset + double fDefaultOffset = 0.5; + getFastPropertyValue( PROP_PIE_TEMPLATE_DEFAULT_OFFSET ) >>= fDefaultOffset; + double fOffsetToSet = fDefaultOffset; + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList; + + // determine whether to set the new offset + bool bSetOffset = ( ePieOffsetMode == chart2::PieChartOffsetMode_ALL_EXPLODED ); + if( !bSetOffset && + (ePieOffsetMode == chart2::PieChartOffsetMode_NONE) ) + { + // set offset to 0 if the offset was exactly "all exploded" + // before (individual offsets are kept) + double fOffset = 0.0; + if( (xSeries->getPropertyValue( aOffsetPropName ) >>= fOffset) && + ::rtl::math::approxEqual( fOffset, fDefaultOffset )) + { + fOffsetToSet = 0.0; + bSetOffset = true; + for( auto const & pointIndex : std::as_const(aAttributedDataPointIndexList) ) + { + uno::Reference< beans::XPropertySet > xPointProp( + xSeries->getDataPointByIndex( pointIndex )); + uno::Reference< beans::XPropertyState > xPointState( xPointProp, uno::UNO_QUERY ); + double fPointOffset = 0.0; + if( xPointState.is() && + (xPointState->getPropertyState( aOffsetPropName ) == beans::PropertyState_DIRECT_VALUE) && + xPointProp.is() && + (xPointProp->getPropertyValue( aOffsetPropName ) >>= fPointOffset ) && + ! ::rtl::math::approxEqual( fPointOffset, fDefaultOffset ) ) + { + bSetOffset = false; + break; + } + } + } + } + + if( bSetOffset ) + { + // set the offset to the series and to the attributed data points + xSeries->setPropertyValue( aOffsetPropName, uno::Any( fOffsetToSet )); + + // remove hard attributes from data points + for( auto const & pointIndex : std::as_const(aAttributedDataPointIndexList) ) + { + uno::Reference< beans::XPropertyState > xPointState( + xSeries->getDataPointByIndex( pointIndex ), uno::UNO_QUERY ); + if( xPointState.is()) + xPointState->setPropertyToDefault( aOffsetPropName ); + } + } + } + + // line style + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); + + // vary colors by point + xSeries->setPropertyValue( "VaryColorsByPoint", uno::Any( true )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void PieChartTypeTemplate::resetStyles2( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + // reset axes and grids + if( xDiagram.is()) + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysSeq( xDiagram->getBaseCoordinateSystems()); + ChartTypeTemplate::createAxes( aCooSysSeq ); + + //reset scale orientation + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysSeq ) + { + try + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 0 /*nDimensionIndex*/,0 /*nAxisIndex*/ + , coords ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + + xAxis = AxisHelper::getAxis( 1, 0, coords ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData() ); + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + + ChartTypeTemplate::resetStyles2( xDiagram ); + + // vary colors by point, + // line style + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + uno::Any aLineStyleAny( drawing::LineStyle_NONE ); + for (auto const& series : aSeriesVec) + { + series->setPropertyToDefault( "VaryColorsByPoint"); + if( series->getPropertyValue( "BorderStyle") == aLineStyleAny ) + { + series->setPropertyToDefault( "BorderStyle"); + } + } + + //reset scene properties + ThreeDHelper::setDefaultRotation( xDiagram, false ); +} + +// ____ XChartTypeTemplate ____ +void PieChartTypeTemplate::adaptDiagram( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + //different default for scene geometry: + ThreeDHelper::setDefaultRotation( xDiagram, true ); +} + +IMPLEMENT_FORWARD_XINTERFACE2( PieChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( PieChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/PieChartTypeTemplate.hxx b/chart2/source/model/template/PieChartTypeTemplate.hxx new file mode 100644 index 000000000..06e80bbb3 --- /dev/null +++ b/chart2/source/model/template/PieChartTypeTemplate.hxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace chart +{ + +class PieChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + PieChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + css::chart2::PieChartOffsetMode eMode, + bool bRings, + sal_Int32 nDim = 2 ); + virtual ~PieChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual void resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) override; + + // ____ ChartTypeTemplate ____ + virtual sal_Int32 getDimension() const override; + + virtual void adaptDiagram( + const rtl::Reference< ::chart::Diagram > & xDiagram ) override; + + virtual sal_Int32 getAxisCountByDimension( sal_Int32 nDimension ) override; + + virtual void adaptAxes( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > & rCoordSys ) override; + + virtual void adaptScales( + const std::vector< rtl::Reference< ::chart::BaseCoordinateSystem > > & aCooSysSeq, + const css::uno::Reference< css::chart2::data::XLabeledDataSequence > & xCategories ) override; + + virtual void createChartTypes( + const std::vector< + std::vector< + rtl::Reference< + ::chart::DataSeries > > >& aSeriesSeq, + const std::vector< + rtl::Reference< + ::chart::BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > > & aOldChartTypesSeq + ) override; + + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ScatterChartType.cxx b/chart2/source/model/template/ScatterChartType.cxx new file mode 100644 index 000000000..cee026913 --- /dev/null +++ b/chart2/source/model/template/ScatterChartType.cxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ScatterChartType.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +enum +{ + PROP_SCATTERCHARTTYPE_CURVE_STYLE, + PROP_SCATTERCHARTTYPE_CURVE_RESOLUTION, + PROP_SCATTERCHARTTYPE_SPLINE_ORDER +}; + +::chart::tPropertyValueMap& StaticScatterChartTypeDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_SCATTERCHARTTYPE_CURVE_STYLE, chart2::CurveStyle_LINES ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_SCATTERCHARTTYPE_CURVE_RESOLUTION, 20 ); + + // todo: check whether order 3 means polygons of order 3 or 2. (see + // http://www.people.nnov.ru/fractal/Splines/Basis.htm ) + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_SCATTERCHARTTYPE_SPLINE_ORDER, 3 ); + return aOutMap; + }(); + return aStaticDefaults; +} + +::cppu::OPropertyArrayHelper& StaticScatterChartTypeInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { CHART_UNONAME_CURVE_STYLE, + PROP_SCATTERCHARTTYPE_CURVE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_CURVE_RESOLUTION, + PROP_SCATTERCHARTTYPE_CURVE_RESOLUTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_SPLINE_ORDER, + PROP_SCATTERCHARTTYPE_SPLINE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + return comphelper::containerToSequence( aProperties ); + }() ); + return aPropHelper; +} + +const uno::Reference< beans::XPropertySetInfo >& StaticScatterChartTypeInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticScatterChartTypeInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +ScatterChartType::ScatterChartType() +{ +} + +ScatterChartType::ScatterChartType( const ScatterChartType & rOther ) : + ChartType( rOther ) +{ +} + +ScatterChartType::~ScatterChartType() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL ScatterChartType::createClone() +{ + return uno::Reference< util::XCloneable >( new ScatterChartType( *this )); +} + +rtl::Reference< ChartType > ScatterChartType::cloneChartType() const +{ + return new ScatterChartType( *this ); +} + +// ____ XChartType ____ +rtl::Reference< ::chart::BaseCoordinateSystem > + ScatterChartType::createCoordinateSystem2( sal_Int32 DimensionCount ) +{ + rtl::Reference< CartesianCoordinateSystem > xResult = + new CartesianCoordinateSystem( DimensionCount ); + + for( sal_Int32 i=0; i xAxis = xResult->getAxisByDimension2( i, MAIN_AXIS_INDEX ); + if( !xAxis.is() ) + { + OSL_FAIL("a created coordinate system should have an axis for each dimension"); + continue; + } + + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + aScaleData.Scaling = AxisHelper::createLinearScaling(); + + if( i == 2 ) + aScaleData.AxisType = chart2::AxisType::SERIES; + else + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + + xAxis->setScaleData( aScaleData ); + } + + return xResult; +} + +OUString SAL_CALL ScatterChartType::getChartType() +{ + return CHART2_SERVICE_NAME_CHARTTYPE_SCATTER; +} + +uno::Sequence< OUString > SAL_CALL ScatterChartType::getSupportedMandatoryRoles() +{ + return { "label", "values-x", "values-y" }; +} + +// ____ OPropertySet ____ +void ScatterChartType::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticScatterChartTypeDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +// ____ OPropertySet ____ +::cppu::IPropertyArrayHelper & SAL_CALL ScatterChartType::getInfoHelper() +{ + return StaticScatterChartTypeInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ScatterChartType::getPropertySetInfo() +{ + return StaticScatterChartTypeInfo(); +} + +OUString SAL_CALL ScatterChartType::getImplementationName() +{ + return "com.sun.star.comp.chart.ScatterChartType"; +} + +sal_Bool SAL_CALL ScatterChartType::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ScatterChartType::getSupportedServiceNames() +{ + return { + CHART2_SERVICE_NAME_CHARTTYPE_SCATTER, + "com.sun.star.chart2.ChartType", + "com.sun.star.beans.PropertySet" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ScatterChartType_get_implementation(css::uno::XComponentContext * /*context*/, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ScatterChartType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ScatterChartType.hxx b/chart2/source/model/template/ScatterChartType.hxx new file mode 100644 index 000000000..f490c108c --- /dev/null +++ b/chart2/source/model/template/ScatterChartType.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class ScatterChartType final : public ChartType +{ +public: + ScatterChartType(); + virtual ~ScatterChartType() override; + + virtual OUString SAL_CALL + getImplementationName() override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual rtl::Reference cloneChartType() const override; + +private: + explicit ScatterChartType( const ScatterChartType & rOther ); + + // ____ XChartType ____ + virtual OUString SAL_CALL getChartType() override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedMandatoryRoles() override; + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + // ____ OPropertySet ____ + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + virtual rtl::Reference< ::chart::BaseCoordinateSystem > + createCoordinateSystem2( sal_Int32 DimensionCount ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ScatterChartTypeTemplate.cxx b/chart2/source/model/template/ScatterChartTypeTemplate.cxx new file mode 100644 index 000000000..91fe7bba5 --- /dev/null +++ b/chart2/source/model/template/ScatterChartTypeTemplate.cxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ScatterChartTypeTemplate.hxx" +#include "ScatterChartType.hxx" +#include "XYDataInterpreter.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::Property; + +namespace +{ + +enum +{ + PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE, + PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION, + PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER + +}; + +const ::chart::tPropertyValueMap& StaticScatterChartTypeTemplateDefaults() +{ + static const ::chart::tPropertyValueMap aStaticDefaults = + []() + { + ::chart::tPropertyValueMap aOutMap; + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE, chart2::CurveStyle_LINES ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION, 20 ); + + // todo: check whether order 3 means polygons of order 3 or 2. (see + // http://www.people.nnov.ru/fractal/Splines/Basis.htm ) + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aOutMap, PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER, 3 ); + return aOutMap; + }(); + return aStaticDefaults; +} + + +::cppu::OPropertyArrayHelper& StaticScatterChartTypeTemplateInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper( + []() + { + std::vector< css::beans::Property > aProperties { + { CHART_UNONAME_CURVE_STYLE, + PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_CURVE_RESOLUTION, + PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT }, + { CHART_UNONAME_SPLINE_ORDER, + PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT } }; + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + return comphelper::containerToSequence( aProperties ); + }() ); + return aPropHelper; +} + +const uno::Reference< beans::XPropertySetInfo >& StaticScatterChartTypeTemplateInfo() +{ + static const uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(StaticScatterChartTypeTemplateInfoHelper() ) ); + return xPropertySetInfo; +} + +} // anonymous namespace + +namespace chart +{ + +ScatterChartTypeTemplate::ScatterChartTypeTemplate( + Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + bool bSymbols, + bool bHasLines /* = true */, + sal_Int32 nDim /* = 2 */ ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_bHasSymbols( bSymbols ), + m_bHasLines( bHasLines ), + m_nDim( nDim ) +{ + if( nDim == 3 ) + m_bHasSymbols = false; +} + +ScatterChartTypeTemplate::~ScatterChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void ScatterChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = StaticScatterChartTypeTemplateDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL ScatterChartTypeTemplate::getInfoHelper() +{ + return StaticScatterChartTypeTemplateInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ScatterChartTypeTemplate::getPropertySetInfo() +{ + return StaticScatterChartTypeTemplateInfo(); +} + +sal_Int32 ScatterChartTypeTemplate::getDimension() const +{ + return m_nDim; +} + +StackMode ScatterChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const +{ + if( m_nDim == 3 ) + return StackMode::ZStacked; + return StackMode::NONE; +} + +void ScatterChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + + try + { + DataSeriesHelper::switchSymbolsOnOrOff( xSeries, m_bHasSymbols, nSeriesIndex ); + DataSeriesHelper::switchLinesOnOrOff( xSeries, m_bHasLines ); + DataSeriesHelper::makeLinesThickOrThin( xSeries, m_nDim==2 ); + if( m_nDim==3 ) + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XChartTypeTemplate ____ +sal_Bool SAL_CALL ScatterChartTypeTemplate::supportsCategories() +{ + return false; +} + +bool ScatterChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) +{ + bool bResult = ChartTypeTemplate::matchesTemplate2( xDiagram, bAdaptProperties ); + + // check symbol-style and line-style + // for a template with symbols (or with lines) it is ok, if there is at least one series + // with symbols (or with lines) + if( bResult ) + { + bool bSymbolFound = false; + bool bLineFound = false; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& series : aSeriesVec) + { + try + { + chart2::Symbol aSymbProp; + drawing::LineStyle eLineStyle; + + bool bCurrentHasSymbol = (series->getPropertyValue( "Symbol") >>= aSymbProp) && + (aSymbProp.Style != chart2::SymbolStyle_NONE); + + if( bCurrentHasSymbol ) + bSymbolFound = true; + + if( bCurrentHasSymbol && (!m_bHasSymbols) ) + { + bResult = false; + break; + } + + bool bCurrentHasLine = (series->getPropertyValue( "LineStyle") >>= eLineStyle) && + ( eLineStyle != drawing::LineStyle_NONE ); + + if( bCurrentHasLine ) + bLineFound = true; + + if( bCurrentHasLine && (!m_bHasLines) ) + { + bResult = false; + break; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if(bResult) + { + if( !bLineFound && m_bHasLines && bSymbolFound ) + bResult = false; + else if( !bSymbolFound && m_bHasSymbols && bLineFound ) + bResult = false; + else if( !bLineFound && !bSymbolFound ) + return m_bHasLines && m_bHasSymbols; + } + } + + // adapt curve style, spline order and resolution + if( bResult && bAdaptProperties ) + { + try + { + rtl::Reference< ChartType > xChartTypeProp = + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + setFastPropertyValue_NoBroadcast( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE, xChartTypeProp->getPropertyValue(CHART_UNONAME_CURVE_STYLE) ); + setFastPropertyValue_NoBroadcast( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION, xChartTypeProp->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) ); + setFastPropertyValue_NoBroadcast( PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER, xChartTypeProp->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return bResult; +} + +rtl::Reference< ChartType > ScatterChartTypeTemplate::getChartTypeForIndex( sal_Int32 /*nChartTypeIndex*/ ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new ScatterChartType(); + + xResult->setPropertyValue( + CHART_UNONAME_CURVE_STYLE, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE )); + xResult->setPropertyValue( + CHART_UNONAME_CURVE_RESOLUTION, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION )); + xResult->setPropertyValue( + CHART_UNONAME_SPLINE_ORDER, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< ChartType > ScatterChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new ScatterChartType(); + + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + + xResult->setPropertyValue( + CHART_UNONAME_CURVE_STYLE, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_STYLE )); + xResult->setPropertyValue( + CHART_UNONAME_CURVE_RESOLUTION, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_CURVE_RESOLUTION )); + xResult->setPropertyValue( + CHART_UNONAME_SPLINE_ORDER, getFastPropertyValue( PROP_SCATTERCHARTTYPE_TEMPLATE_SPLINE_ORDER )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< DataInterpreter > ScatterChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new XYDataInterpreter ); + + return m_xDataInterpreter; +} + +IMPLEMENT_FORWARD_XINTERFACE2( ScatterChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScatterChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/ScatterChartTypeTemplate.hxx b/chart2/source/model/template/ScatterChartTypeTemplate.hxx new file mode 100644 index 000000000..88441b844 --- /dev/null +++ b/chart2/source/model/template/ScatterChartTypeTemplate.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +class ScatterChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + explicit ScatterChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + bool bSymbols, + bool bHasLines = true, + sal_Int32 nDim = 2 ); + virtual ~ScatterChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ ChartTypeTemplate ____ + virtual sal_Bool SAL_CALL supportsCategories() override; + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual rtl::Reference< ::chart::DataInterpreter > getDataInterpreter2() override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeGroupIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + + // ____ ChartTypeTemplate ____ + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + virtual sal_Int32 getDimension() const override; + virtual StackMode getStackMode( sal_Int32 nChartTypeIndex ) const override; + +private: + bool m_bHasSymbols; + bool m_bHasLines; + sal_Int32 m_nDim; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/StockChartTypeTemplate.cxx b/chart2/source/model/template/StockChartTypeTemplate.cxx new file mode 100644 index 000000000..bd14ac3c4 --- /dev/null +++ b/chart2/source/model/template/StockChartTypeTemplate.cxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "StockChartTypeTemplate.hxx" +#include "ColumnChartType.hxx" +#include "CandleStickChartType.hxx" +#include "LineChartType.hxx" +#include +#include +#include "StockDataInterpreter.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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::beans::Property; + +namespace +{ + +enum +{ + PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME, + PROP_STOCKCHARTTYPE_TEMPLATE_OPEN, + PROP_STOCKCHARTTYPE_TEMPLATE_LOW_HIGH, + PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "Volume", + PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Open", + PROP_STOCKCHARTTYPE_TEMPLATE_OPEN, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "LowHigh", + PROP_STOCKCHARTTYPE_TEMPLATE_LOW_HIGH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "Japanese", + PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +::chart::tPropertyValueMap& GetStaticStockChartTypeTemplateDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + [](){ + ::chart::tPropertyValueMap aTmp; + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_STOCKCHARTTYPE_TEMPLATE_OPEN, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_STOCKCHARTTYPE_TEMPLATE_LOW_HIGH, true ); + ::chart::PropertyHelper::setPropertyValueDefault( aTmp, PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE, false ); + return aTmp; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& GetStaticStockChartTypeTemplateInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = + [](){ + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + + +uno::Reference< beans::XPropertySetInfo >& GetStaticStockChartTypeTemplateInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(GetStaticStockChartTypeTemplateInfoHelper() ) ); + return xPropertySetInfo; +}; + +} // anonymous namespace + +namespace chart +{ + +StockChartTypeTemplate::StockChartTypeTemplate( + uno::Reference< + uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StockVariant eVariant, + bool bJapaneseStyle ) : + ChartTypeTemplate( xContext, rServiceName ), + ::property::OPropertySet( m_aMutex ), + m_eStockVariant( eVariant ) +{ + setFastPropertyValue_NoBroadcast( + PROP_STOCKCHARTTYPE_TEMPLATE_OPEN, + uno::Any( ( eVariant == StockVariant::Open || + eVariant == StockVariant::VolumeOpen ))); + setFastPropertyValue_NoBroadcast( + PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME, + uno::Any( ( eVariant == StockVariant::Volume || + eVariant == StockVariant::VolumeOpen ))); + setFastPropertyValue_NoBroadcast( + PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE, + uno::Any( bJapaneseStyle )); +} + +StockChartTypeTemplate::~StockChartTypeTemplate() +{} + +// ____ OPropertySet ____ +void StockChartTypeTemplate::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = GetStaticStockChartTypeTemplateDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL StockChartTypeTemplate::getInfoHelper() +{ + return GetStaticStockChartTypeTemplateInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL StockChartTypeTemplate::getPropertySetInfo() +{ + return GetStaticStockChartTypeTemplateInfo(); +} + +sal_Int32 StockChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension ) +{ + // one x-axis + if( nDimension <= 0 ) + return 1; + // no further axes + if( nDimension >= 2 ) + return 0; + + // one or two y-axes depending on volume + OSL_ASSERT( nDimension == 1 ); + bool bHasVolume = false; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME ) >>= bHasVolume; + return bHasVolume ? 2 : 1; +} + +void StockChartTypeTemplate::applyStyle2( + const rtl::Reference< DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) +{ + ChartTypeTemplate::applyStyle2( xSeries, nChartTypeIndex, nSeriesIndex, nSeriesCount ); + try + { + sal_Int32 nNewAxisIndex = 0; + + bool bHasVolume = false; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME ) >>= bHasVolume; + if( bHasVolume && nChartTypeIndex != 0 ) + nNewAxisIndex = 1; + + xSeries->setPropertyValue( "AttachedAxisIndex", uno::Any( nNewAxisIndex ) ); + + if( bHasVolume && nChartTypeIndex==0 ) + { + //switch lines off for volume bars + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", uno::Any( drawing::LineStyle_NONE ) ); + } + else + { + //ensure that lines are on + drawing::LineStyle eStyle = drawing::LineStyle_NONE; + xSeries->getPropertyValue( "LineStyle" ) >>= eStyle; + if( eStyle == drawing::LineStyle_NONE ) + xSeries->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID )); + } + + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void StockChartTypeTemplate::resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + ChartTypeTemplate::resetStyles2( xDiagram ); + if( getDimension() == 3 ) + { + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + for (auto const& series : aSeriesVec) + { + series->setPropertyValue( "AttachedAxisIndex", uno::Any( sal_Int32(0) ) ); + } + } + + DiagramHelper::setVertical( xDiagram, false ); +} + +rtl::Reference< ChartType > StockChartTypeTemplate::getChartTypeForIndex( sal_Int32 nChartTypeIndex ) +{ + rtl::Reference< ChartType > xCT; + bool bHasVolume = false; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME ) >>= bHasVolume; + if( bHasVolume ) + { + if( nChartTypeIndex == 0 ) + xCT = new ColumnChartType(); + else if( nChartTypeIndex == 1 ) + xCT = new CandleStickChartType(); + else + xCT = new LineChartType(); + } + else + { + if( nChartTypeIndex == 0 ) + xCT = new CandleStickChartType(); + else + xCT = new LineChartType(); + } + return xCT; +} + +void StockChartTypeTemplate::createChartTypes( + const std::vector< std::vector< rtl::Reference< DataSeries > > > & aSeriesSeq, + const std::vector< rtl::Reference< BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > >& /* aOldChartTypesSeq */ ) +{ + if( rCoordSys.empty() ) + return; + + try + { + bool bHasVolume = false; + bool bShowFirst = false; + bool bJapaneseStyle = false; + bool bShowHighLow = true; + + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME ) >>= bHasVolume; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_OPEN ) >>= bShowFirst; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE ) >>= bJapaneseStyle; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_LOW_HIGH ) >>= bShowHighLow; + + std::size_t nSeriesIndex = 0; + + std::vector< rtl::Reference< ChartType > > aChartTypeVec; + // Bars (Volume) + if( bHasVolume ) + { + // chart type + rtl::Reference< ChartType > xCT = new ColumnChartType(); + aChartTypeVec.push_back( xCT ); + + if( aSeriesSeq.size() > nSeriesIndex && + !aSeriesSeq[nSeriesIndex].empty() ) + { + xCT->setDataSeries( aSeriesSeq[ nSeriesIndex ] ); + } + ++nSeriesIndex; + } + + rtl::Reference< ChartType > xCT = new CandleStickChartType(); + aChartTypeVec.push_back( xCT ); + + xCT->setPropertyValue( "Japanese", uno::Any( bJapaneseStyle )); + xCT->setPropertyValue( "ShowFirst", uno::Any( bShowFirst )); + xCT->setPropertyValue( "ShowHighLow", uno::Any( bShowHighLow )); + + if( aSeriesSeq.size() > nSeriesIndex && + !aSeriesSeq[ nSeriesIndex ].empty() ) + { + xCT->setDataSeries( aSeriesSeq[ nSeriesIndex ] ); + } + ++nSeriesIndex; + + // Lines (remaining series) + if( aSeriesSeq.size() > nSeriesIndex && + !aSeriesSeq[ nSeriesIndex ].empty() ) + { + xCT = new LineChartType(); + aChartTypeVec.push_back( xCT ); + + xCT->setDataSeries( aSeriesSeq[ nSeriesIndex ] ); + } + + rCoordSys[ 0 ]->setChartTypes( aChartTypeVec ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ ChartTypeTemplate ____ +bool StockChartTypeTemplate::matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool /* bAdaptProperties */ ) +{ + bool bResult = false; + + if( ! xDiagram.is()) + return bResult; + + try + { + bool bHasVolume = false, bHasOpenValue = false, bHasJapaneseStyle = false; + + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_VOLUME ) >>= bHasVolume; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_OPEN ) >>= bHasOpenValue; + getFastPropertyValue( PROP_STOCKCHARTTYPE_TEMPLATE_JAPANESE ) >>= bHasJapaneseStyle; + + rtl::Reference< ChartType > xVolumeChartType; + rtl::Reference< ChartType > xCandleStickChartType; + rtl::Reference< ChartType > xLineChartType; + sal_Int32 nNumberOfChartTypes = 0; + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + for( rtl::Reference< ChartType > const & chartType : coords->getChartTypes2() ) + { + ++nNumberOfChartTypes; + if( nNumberOfChartTypes > 3 ) + break; + OUString aCTService = chartType->getChartType(); + if( aCTService == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) + xVolumeChartType = chartType; + else if( aCTService == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ) + xCandleStickChartType = chartType; + else if( aCTService == CHART2_SERVICE_NAME_CHARTTYPE_LINE ) + xLineChartType = chartType; + } + if( nNumberOfChartTypes > 3 ) + break; + } + + if (xCandleStickChartType.is() && bHasVolume == xVolumeChartType.is()) + { + bResult = true; + + // check for japanese style + bool bJapaneseProp = false; + xCandleStickChartType->getPropertyValue( "Japanese") >>= bJapaneseProp; + bResult = bResult && ( bHasJapaneseStyle == bJapaneseProp ); + + // in old chart japanese == showFirst + bool bShowFirstProp = false; + xCandleStickChartType->getPropertyValue( "ShowFirst") >>= bShowFirstProp; + bResult = bResult && ( bHasOpenValue == bShowFirstProp ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return bResult; +} + +rtl::Reference< ChartType > StockChartTypeTemplate::getChartTypeForNewSeries2( + const std::vector< rtl::Reference< ChartType > >& aFormerlyUsedChartTypes ) +{ + rtl::Reference< ChartType > xResult; + + try + { + xResult = new LineChartType(); + ChartTypeTemplate::copyPropertiesFromOldToNewCoordinateSystem( aFormerlyUsedChartTypes, xResult ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +rtl::Reference< DataInterpreter > StockChartTypeTemplate::getDataInterpreter2() +{ + if( ! m_xDataInterpreter.is()) + m_xDataInterpreter.set( new StockDataInterpreter( m_eStockVariant ) ); + + return m_xDataInterpreter; +} + +IMPLEMENT_FORWARD_XINTERFACE2( StockChartTypeTemplate, ChartTypeTemplate, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( StockChartTypeTemplate, ChartTypeTemplate, OPropertySet ) + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/StockChartTypeTemplate.hxx b/chart2/source/model/template/StockChartTypeTemplate.hxx new file mode 100644 index 000000000..78d6c02e1 --- /dev/null +++ b/chart2/source/model/template/StockChartTypeTemplate.hxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +class StockChartTypeTemplate : + public cppu::BaseMutex, + public ChartTypeTemplate, + public ::property::OPropertySet +{ +public: + enum class StockVariant + { + NONE, + Open, + Volume, + VolumeOpen + }; + + /** CTOR + + @param bJapaneseStyle + If true, the candlesticks are drawn as solid white or black boxes + depending on rising or falling stock-values. Otherwise the + open-value will be drawn as a small line at the left side of a + straight vertical line, and the close-value on the right hand side. + */ + explicit StockChartTypeTemplate( + css::uno::Reference< css::uno::XComponentContext > const & xContext, + const OUString & rServiceName, + StockVariant eVariant, + bool bJapaneseStyle ); + virtual ~StockChartTypeTemplate() override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + /// merge XTypeProvider implementations + DECLARE_XTYPEPROVIDER() + +protected: + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XChartTypeTemplate ____ + virtual bool matchesTemplate2( + const rtl::Reference< ::chart::Diagram >& xDiagram, + bool bAdaptProperties ) override; + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForNewSeries2( const std::vector< + rtl::Reference< ::chart::ChartType > >& aFormerlyUsedChartTypes ) override; + virtual rtl::Reference< ::chart::DataInterpreter > getDataInterpreter2() override; + virtual void applyStyle2( + const rtl::Reference< ::chart::DataSeries >& xSeries, + ::sal_Int32 nChartTypeIndex, + ::sal_Int32 nSeriesIndex, + ::sal_Int32 nSeriesCount ) override; + virtual void resetStyles2( + const rtl::Reference< ::chart::Diagram >& xDiagram ) override; + + // ChartTypeTemplate + virtual sal_Int32 getAxisCountByDimension( sal_Int32 nDimension ) override; + + // ____ ChartTypeTemplate ____ + virtual void createChartTypes( + const std::vector< + std::vector< + rtl::Reference< + ::chart::DataSeries > > >& aSeriesSeq, + const std::vector< + rtl::Reference< + ::chart::BaseCoordinateSystem > > & rCoordSys, + const std::vector< rtl::Reference< ChartType > > & aOldChartTypesSeq + ) override; + + virtual rtl::Reference< ::chart::ChartType > + getChartTypeForIndex( sal_Int32 nChartTypeIndex ) override; + +private: + // todo: deprecate this variable + StockVariant m_eStockVariant; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/StockDataInterpreter.cxx b/chart2/source/model/template/StockDataInterpreter.cxx new file mode 100644 index 000000000..24072f718 --- /dev/null +++ b/chart2/source/model/template/StockDataInterpreter.cxx @@ -0,0 +1,342 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "StockDataInterpreter.hxx" +#include "StockChartTypeTemplate.hxx" +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +// explicit +StockDataInterpreter::StockDataInterpreter( + StockChartTypeTemplate::StockVariant eVariant ) : + m_eStockVariant( eVariant ) +{} + +StockDataInterpreter::~StockDataInterpreter() +{} + +// ____ XDataInterpreter ____ +InterpretedData StockDataInterpreter::interpretDataSource( + const Reference< data::XDataSource >& xSource, + const Sequence< beans::PropertyValue >& rArguments, + const std::vector< rtl::Reference< ::chart::DataSeries > >& rSeriesToReUse ) +{ + if( ! xSource.is()) + return InterpretedData(); + + uno::Reference< chart2::data::XLabeledDataSequence > xCategories; + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = DataInterpreter::getDataSequences(xSource); + const sal_Int32 nDataCount( aData.size()); + + // sub-type properties + const StockChartTypeTemplate::StockVariant eVar( GetStockVariant()); + const bool bHasOpenValues (( eVar == StockChartTypeTemplate::StockVariant::Open ) || + ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen )); + const bool bHasVolume (( eVar == StockChartTypeTemplate::StockVariant::Volume ) || + ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen )); + const bool bHasCategories( HasCategories( rArguments, aData )); + + // necessary roles for "full series" + // low/high/close + sal_Int32 nNumberOfNecessarySequences( 3 ); + if( bHasOpenValues ) + ++nNumberOfNecessarySequences; + if( bHasVolume ) + ++nNumberOfNecessarySequences; + + // calculate number of full series (nNumOfFullSeries) and the number of remaining + // sequences used for additional "incomplete series" (nRemaining) + sal_Int32 nNumOfFullSeries( 0 ); + sal_Int32 nRemaining( 0 ); + { + sal_Int32 nAvailableSequences( nDataCount ); + if( bHasCategories ) + --nAvailableSequences; + nNumOfFullSeries = nAvailableSequences / nNumberOfNecessarySequences; + nRemaining = nAvailableSequences % nNumberOfNecessarySequences; + } + sal_Int32 nCandleStickSeries = nNumOfFullSeries; + sal_Int32 nVolumeSeries = nNumOfFullSeries; + + sal_Int32 nNumberOfGroups( bHasVolume ? 2 : 1 ); + // sequences of data::XLabeledDataSequence per series per group + std::vector< std::vector< std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > > > aSequences( nNumberOfGroups ); + const sal_Int32 nBarGroupIndex( 0 ); + const sal_Int32 nCandleStickGroupIndex( nNumberOfGroups - 1 ); + + // allocate space for labeled sequences + if( nRemaining > 0 ) + ++nCandleStickSeries; + aSequences[nCandleStickGroupIndex].resize( nCandleStickSeries ); + auto & pCandleStickGroup = aSequences[nCandleStickGroupIndex]; + if( bHasVolume ) + { + // if there are remaining sequences, the first one is taken for + // additional close values, the second one is taken as volume, if volume + // is used + if( nRemaining > 1 ) + ++nVolumeSeries; + aSequences[nBarGroupIndex].resize( nVolumeSeries ); + } + auto & pBarGroup = aSequences[nBarGroupIndex]; + + // create data + sal_Int32 nSourceIndex = 0; // index into aData sequence + + // 1. categories + if( bHasCategories ) + { + xCategories = aData[nSourceIndex]; + ++nSourceIndex; + } + + // 2. create "full" series + for( sal_Int32 nLabeledSeqIdx=0; nLabeledSeqIdxgetValues(), "values-y"); + ++nSourceIndex; + } + + sal_Int32 nSeqIdx = 0; + if( bHasOpenValues ) + { + pCandleStickGroup[nLabeledSeqIdx].resize( 4 ); + pCandleStickGroup[nLabeledSeqIdx][nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-first"); + ++nSourceIndex; + ++nSeqIdx; + } + else + pCandleStickGroup[nLabeledSeqIdx].resize( 3 ); + auto & pLabeledSeq = pCandleStickGroup[nLabeledSeqIdx]; + + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-min"); + ++nSourceIndex; + ++nSeqIdx; + + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-max"); + ++nSourceIndex; + ++nSeqIdx; + + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-last"); + ++nSourceIndex; + ++nSeqIdx; + } + + // 3. create series with remaining sequences + if( bHasVolume && nRemaining > 1 ) + { + OSL_ASSERT( nVolumeSeries > nNumOfFullSeries ); + pBarGroup[nVolumeSeries - 1].resize( 1 ); + OSL_ASSERT( nDataCount > nSourceIndex ); + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-y"); + pBarGroup[nVolumeSeries - 1][0] = aData[nSourceIndex]; + ++nSourceIndex; + --nRemaining; + OSL_ENSURE( nRemaining, "additional bar should only be used if there is at least one more sequence for a candle stick" ); + } + + // candle-stick + if( nRemaining > 0 ) + { + OSL_ASSERT( nCandleStickSeries > nNumOfFullSeries ); + const sal_Int32 nSeriesIndex = nCandleStickSeries - 1; + pCandleStickGroup[nSeriesIndex].resize( nRemaining ); + auto & pLabeledSeq = pCandleStickGroup[nSeriesIndex]; + OSL_ASSERT( nDataCount > nSourceIndex ); + + // 1. low + sal_Int32 nSeqIdx( 0 ); + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-min"); + ++nSourceIndex; + ++nSeqIdx; + + // 2. high + if( nSeqIdx < nRemaining ) + { + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-max"); + ++nSourceIndex; + ++nSeqIdx; + } + + // 3. close + OSL_ENSURE( bHasOpenValues || nSeqIdx >= nRemaining, "could have created full series" ); + if( nSeqIdx < nRemaining ) + { + pLabeledSeq[nSeqIdx] = aData[nSourceIndex]; + if( aData[nSourceIndex].is()) + SetRole( aData[nSourceIndex]->getValues(), "values-last"); + ++nSourceIndex; + ++nSeqIdx; + } + + // 4. open + OSL_ENSURE( nSeqIdx >= nRemaining, "could have created full series" ); + } + + // create DataSeries + std::vector< std::vector< rtl::Reference< DataSeries > > > aResultSeries( nNumberOfGroups ); + sal_Int32 nGroupIndex; + std::size_t nReUsedSeriesIdx = 0; + for( nGroupIndex=0; nGroupIndex xSeries; + if( nReUsedSeriesIdx < rSeriesToReUse.size()) + xSeries = rSeriesToReUse[nReUsedSeriesIdx]; + else + xSeries = new DataSeries; + assert( xSeries.is() ); + xSeries->setData( aSequences[nGroupIndex][nSeriesIdx] ); + pResultSerie[nSeriesIdx] = xSeries; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + + return { aResultSeries, xCategories }; +} + +// criterion: there must be two groups for stock-charts with volume and all +// series must have the correct number of data::XLabeledDataSequences + +// todo: skip first criterion? (to allow easy switch from stock-chart without +// volume to one with volume) +bool StockDataInterpreter::isDataCompatible( + const InterpretedData& aInterpretedData ) +{ + // high/low/close + std::size_t nNumberOfNecessarySequences = 3; + // open + StockChartTypeTemplate::StockVariant eVar( GetStockVariant()); + if( ( eVar == StockChartTypeTemplate::StockVariant::Open ) || + ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen )) + ++nNumberOfNecessarySequences; + // volume + bool bHasVolume = (( eVar == StockChartTypeTemplate::StockVariant::Volume ) || + ( eVar == StockChartTypeTemplate::StockVariant::VolumeOpen )); + + // 1. correct number of sub-types + if( aInterpretedData.Series.size() < (bHasVolume ? 2U : 1U )) + return false; + + // 2. a. volume -- use default check + if( bHasVolume ) + { + if( ! DataInterpreter::isDataCompatible( + { std::vector< std::vector< rtl::Reference< DataSeries > > >{ + aInterpretedData.Series[0] }, + aInterpretedData.Categories })) + return false; + } + + // 2. b. candlestick + { + OSL_ASSERT( aInterpretedData.Series.size() > (bHasVolume ? 1U : 0U)); + const std::vector< rtl::Reference< DataSeries > > & aSeries = aInterpretedData.Series[(bHasVolume ? 1 : 0)]; + if(aSeries.empty()) + return false; + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + try + { + if( dataSeries->getDataSequences2().size() != nNumberOfNecessarySequences ) + return false; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + + // 2. c. additional series + // ignore + + return true; +} + +InterpretedData StockDataInterpreter::reinterpretDataSeries( + const InterpretedData& aInterpretedData ) +{ + // prerequisite: StockDataInterpreter::isDataCompatible() returned true + return aInterpretedData; +} + +uno::Any StockDataInterpreter::getChartTypeSpecificData( + const OUString& sKey ) +{ + if( sKey == "stock variant" ) + { + StockChartTypeTemplate::StockVariant eStockVariant( GetStockVariant()); + std::map< StockChartTypeTemplate::StockVariant, sal_Int32 > aTranslation { + { StockChartTypeTemplate::StockVariant::NONE, 0 }, + { StockChartTypeTemplate::StockVariant::Open, 1 }, + { StockChartTypeTemplate::StockVariant::Volume, 2 }, + { StockChartTypeTemplate::StockVariant::VolumeOpen, 3 } + }; + return uno::Any( aTranslation[eStockVariant] ); + } + return uno::Any(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/StockDataInterpreter.hxx b/chart2/source/model/template/StockDataInterpreter.hxx new file mode 100644 index 000000000..4617da597 --- /dev/null +++ b/chart2/source/model/template/StockDataInterpreter.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include "StockChartTypeTemplate.hxx" + +namespace chart +{ + +class StockDataInterpreter : public DataInterpreter +{ +public: + explicit StockDataInterpreter( + StockChartTypeTemplate::StockVariant eVariant ); + virtual ~StockDataInterpreter() override; + +protected: + // ____ XDataInterpreter ____ + virtual InterpretedData interpretDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< ::chart::DataSeries > >& aSeriesToReUse ) override; + virtual bool isDataCompatible( + const InterpretedData& aInterpretedData ) override; + virtual InterpretedData reinterpretDataSeries( + const InterpretedData& aInterpretedData ) override; + virtual css::uno::Any getChartTypeSpecificData( + const OUString& sKey ) override; + +private: + StockChartTypeTemplate::StockVariant m_eStockVariant; + + StockChartTypeTemplate::StockVariant GetStockVariant() const { return m_eStockVariant;} +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/XYDataInterpreter.cxx b/chart2/source/model/template/XYDataInterpreter.cxx new file mode 100644 index 000000000..d77a3df39 --- /dev/null +++ b/chart2/source/model/template/XYDataInterpreter.cxx @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "XYDataInterpreter.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +XYDataInterpreter::XYDataInterpreter() +{ +} + +XYDataInterpreter::~XYDataInterpreter() +{ +} + +// ____ XDataInterpreter ____ +InterpretedData XYDataInterpreter::interpretDataSource( + const Reference< chart2::data::XDataSource >& xSource, + const Sequence< beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< DataSeries > >& aSeriesToReUse ) +{ + if( ! xSource.is()) + return InterpretedData(); + + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aData = DataInterpreter::getDataSequences(xSource); + + uno::Reference< chart2::data::XLabeledDataSequence > xValuesX; + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSequencesVec; + + uno::Reference< chart2::data::XLabeledDataSequence > xCategories; + bool bHasCategories = HasCategories( aArguments, aData ); + bool bUseCategoriesAsX = UseCategoriesAsX( aArguments ); + + // parse data + bool bCategoriesUsed = false; + bool bSetXValues = aData.size()>1; + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labelData : aData ) + { + try + { + if( bHasCategories && ! bCategoriesUsed ) + { + xCategories = labelData; + if( xCategories.is()) + { + SetRole( xCategories->getValues(), "categories"); + if( bUseCategoriesAsX ) + bSetXValues = false; + } + bCategoriesUsed = true; + } + else if( !xValuesX.is() && bSetXValues ) + { + xValuesX = labelData; + if( xValuesX.is()) + SetRole( xValuesX->getValues(), "values-x"); + } + else + { + aSequencesVec.push_back( labelData ); + if( labelData.is()) + SetRole( labelData->getValues(), "values-y"); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + // create DataSeries + vector< rtl::Reference< DataSeries > > aSeriesVec; + aSeriesVec.reserve( aSequencesVec.size()); + + Reference< data::XLabeledDataSequence > xClonedXValues = xValuesX; + Reference< util::XCloneable > xCloneable( xValuesX, uno::UNO_QUERY ); + + std::size_t nSeriesIndex = 0; + for (auto const& elem : aSequencesVec) + { + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewData; + + if( nSeriesIndex && xCloneable.is() ) + xClonedXValues.set( xCloneable->createClone(), uno::UNO_QUERY ); + if( xValuesX.is() ) + aNewData.push_back( xClonedXValues ); + + aNewData.push_back(elem); + + rtl::Reference< DataSeries > xSeries; + if( nSeriesIndex < aSeriesToReUse.size()) + xSeries = aSeriesToReUse[nSeriesIndex]; + else + xSeries = new DataSeries; + assert( xSeries.is() ); + xSeries->setData( aNewData ); + + aSeriesVec.push_back( xSeries ); + ++nSeriesIndex; + } + + return { { aSeriesVec }, xCategories }; +} + +InterpretedData XYDataInterpreter::reinterpretDataSeries( + const InterpretedData& aInterpretedData ) +{ + InterpretedData aResult( aInterpretedData ); + + sal_Int32 i=0; + std::vector< rtl::Reference< DataSeries > > aSeries = FlattenSequence( aInterpretedData.Series ); + const sal_Int32 nCount = aSeries.size(); + for( ; i > aNewSequences; + + // values-y + uno::Reference< chart2::data::XLabeledDataSequence > xValuesY( + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-y" )); + uno::Reference< chart2::data::XLabeledDataSequence > xValuesX( + DataSeriesHelper::getDataSequenceByRole( aSeries[i], "values-x" )); + // re-use values-... as values-x/values-y + if( ! xValuesX.is() || + ! xValuesY.is()) + { + vector< uno::Reference< chart2::data::XLabeledDataSequence > > aValueSeqVec( + DataSeriesHelper::getAllDataSequencesByRole( + aSeries[i]->getDataSequences2(), "values" )); + if( xValuesX.is()) + aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesX )); + if( xValuesY.is()) + aValueSeqVec.erase( find( aValueSeqVec.begin(), aValueSeqVec.end(), xValuesY )); + + size_t nIndex = 0; + if( ! xValuesY.is() && + aValueSeqVec.size() > nIndex ) + { + xValuesY = aValueSeqVec[nIndex++]; + if( xValuesY.is()) + SetRole( xValuesY->getValues(), "values-y"); + } + + if( ! xValuesX.is() && + aValueSeqVec.size() > nIndex ) + { + xValuesX = aValueSeqVec[nIndex++]; + if( xValuesX.is()) + SetRole( xValuesY->getValues(), "values-x"); + } + } + if( xValuesY.is()) + { + if( xValuesX.is()) + { + aNewSequences = { xValuesX, xValuesY }; + } + else + { + aNewSequences = { xValuesY }; + } + } + + const std::vector< uno::Reference< data::XLabeledDataSequence > > & aSeqs = aSeries[i]->getDataSequences2(); + if( aSeqs.size() != aNewSequences.size() ) + { +#ifdef DBG_UTIL + for( auto const & j : aSeqs ) + { + SAL_WARN_IF((j == xValuesY || j == xValuesX), "chart2.template", "All sequences should be used" ); + } +#endif + aSeries[i]->setData( aNewSequences ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +// criterion: all series must have exactly two data::XLabeledDataSequences +bool XYDataInterpreter::isDataCompatible( + const InterpretedData& aInterpretedData ) +{ + const std::vector< rtl::Reference< DataSeries > > aSeries = FlattenSequence( aInterpretedData.Series ); + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + try + { + if( dataSeries->getDataSequences2().size() != 2 ) + return false; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return true; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/model/template/XYDataInterpreter.hxx b/chart2/source/model/template/XYDataInterpreter.hxx new file mode 100644 index 000000000..56343013d --- /dev/null +++ b/chart2/source/model/template/XYDataInterpreter.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class XYDataInterpreter : public DataInterpreter +{ +public: + explicit XYDataInterpreter(); + virtual ~XYDataInterpreter() override; + +protected: + // ____ DataInterpreter ____ + virtual InterpretedData interpretDataSource( + const css::uno::Reference< css::chart2::data::XDataSource >& xSource, + const css::uno::Sequence< css::beans::PropertyValue >& aArguments, + const std::vector< rtl::Reference< ::chart::DataSeries > >& aSeriesToReUse ) override; + virtual InterpretedData reinterpretDataSeries( + const InterpretedData& aInterpretedData ) override; + virtual bool isDataCompatible( + const InterpretedData& aInterpretedData ) override; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/AxisHelper.cxx b/chart2/source/tools/AxisHelper.cxx new file mode 100644 index 000000000..a44fb567a --- /dev/null +++ b/chart2/source/tools/AxisHelper.cxx @@ -0,0 +1,1151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +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; + +Reference< chart2::XScaling > AxisHelper::createLinearScaling() +{ + return new LinearScaling( 1.0, 0.0 ); +} + +Reference< chart2::XScaling > AxisHelper::createLogarithmicScaling( double fBase ) +{ + return new LogarithmicScaling( fBase ); +} + +ScaleData AxisHelper::createDefaultScale() +{ + ScaleData aScaleData; + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + aScaleData.AutoDateAxis = true; + aScaleData.ShiftedCategoryPosition = false; + Sequence< SubIncrement > aSubIncrements{ SubIncrement() }; + aScaleData.IncrementData.SubIncrements = aSubIncrements; + return aScaleData; +} + +void AxisHelper::removeExplicitScaling( ScaleData& rScaleData ) +{ + uno::Any aEmpty; + rScaleData.Minimum = rScaleData.Maximum = rScaleData.Origin = aEmpty; + rScaleData.Scaling = nullptr; + ScaleData aDefaultScale( createDefaultScale() ); + rScaleData.IncrementData = aDefaultScale.IncrementData; + rScaleData.TimeIncrement = aDefaultScale.TimeIncrement; +} + +bool AxisHelper::isLogarithmic( const Reference< XScaling >& xScaling ) +{ + Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY ); + return xServiceName.is() + && xServiceName->getServiceName() == "com.sun.star.chart2.LogarithmicScaling"; +} + +chart2::ScaleData AxisHelper::getDateCheckedScale( const rtl::Reference< Axis >& xAxis, ChartModel& rModel ) +{ + ScaleData aScale = xAxis->getScaleData(); + rtl::Reference< BaseCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( &rModel ) ); + if( aScale.AutoDateAxis && aScale.AxisType == AxisType::CATEGORY ) + { + sal_Int32 nDimensionIndex=0; sal_Int32 nAxisIndex=0; + AxisHelper::getIndicesForAxis(xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + bool bChartTypeAllowsDateAxis = ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( xCooSys, 0 ), nDimensionIndex ); + if( bChartTypeAllowsDateAxis ) + aScale.AxisType = AxisType::DATE; + } + if( aScale.AxisType == AxisType::DATE ) + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel ); + if( !aExplicitCategoriesProvider.isDateAxis() ) + aScale.AxisType = AxisType::CATEGORY; + } + return aScale; +} + +void AxisHelper::checkDateAxis( chart2::ScaleData& rScale, ExplicitCategoriesProvider* pExplicitCategoriesProvider, bool bChartTypeAllowsDateAxis ) +{ + if( rScale.AutoDateAxis && rScale.AxisType == AxisType::CATEGORY && bChartTypeAllowsDateAxis ) + { + rScale.AxisType = AxisType::DATE; + removeExplicitScaling( rScale ); + } + if( rScale.AxisType == AxisType::DATE && (!pExplicitCategoriesProvider || !pExplicitCategoriesProvider->isDateAxis()) ) + { + rScale.AxisType = AxisType::CATEGORY; + removeExplicitScaling( rScale ); + } +} + +sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis( + const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem + , const rtl::Reference& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast(xAxis.get()); + assert(pAxis || !xAxis); + return getExplicitNumberFormatKeyForAxis(pAxis, xCorrespondingCoordinateSystem, xChartDoc, bSearchForParallelAxisIfNothingIsFound); +} + +sal_Int32 AxisHelper::getExplicitNumberFormatKeyForAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem + , const rtl::Reference& xChartDoc + , bool bSearchForParallelAxisIfNothingIsFound ) +{ + sal_Int32 nNumberFormatKey(0); + sal_Int32 nAxisIndex = 0; + sal_Int32 nDimensionIndex = 1; + AxisHelper::getIndicesForAxis( xAxis, xCorrespondingCoordinateSystem, nDimensionIndex, nAxisIndex ); + + if (!xAxis.is()) + return 0; + + bool bLinkToSource = true; + xAxis->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource; + xAxis->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey; + + if (bLinkToSource) + { + bool bFormatSet = false; + //check whether we have a percent scale -> use percent format + if (xChartDoc) + { + ScaleData aData = AxisHelper::getDateCheckedScale( xAxis, *xChartDoc ); + if( aData.AxisType==AxisType::PERCENT ) + { + sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( xChartDoc ); + if( nPercentFormat != -1 ) + { + nNumberFormatKey = nPercentFormat; + bFormatSet = true; + } + } + else if( aData.AxisType==AxisType::DATE ) + { + if( aData.Categories.is() ) + { + Reference< data::XDataSequence > xSeq( aData.Categories->getValues()); + if( xSeq.is() && !( xChartDoc.is() && xChartDoc->hasInternalDataProvider()) ) + nNumberFormatKey = xSeq->getNumberFormatKeyByIndex( -1 ); + else + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + bFormatSet = true; + } + } + else if( xChartDoc.is() && xChartDoc->hasInternalDataProvider() && nDimensionIndex == 0 ) //maybe date axis + { + rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram() ); + if( DiagramHelper::isSupportingDateAxis( xDiagram ) ) + { + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + } + else + { + rtl::Reference< DataSource > xSource = DataSourceHelper::getUsedData( *xChartDoc ); + if( xSource.is() ) + { + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aXValues( + DataSeriesHelper::getAllDataSequencesByRole( xSource->getDataSequences(), "values-x" ) ); + if( aXValues.empty() ) + { + uno::Reference< chart2::data::XLabeledDataSequence > xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram ) ); + if( xCategories.is() ) + { + Reference< data::XDataSequence > xSeq( xCategories->getValues()); + if( xSeq.is() ) + { + bool bHasValidDoubles = false; + double fTest=0.0; + Sequence< uno::Any > aCats( xSeq->getData() ); + sal_Int32 nCount = aCats.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + if( (aCats[i]>>=fTest) && !std::isnan(fTest) ) + { + bHasValidDoubles=true; + break; + } + } + if( bHasValidDoubles ) + nNumberFormatKey = DiagramHelper::getDateNumberFormat( xChartDoc ); + } + } + } + } + } + bFormatSet = true; + } + } + + if( !bFormatSet ) + { + std::map< sal_Int32, sal_Int32 > aKeyMap; + bool bNumberFormatKeyFoundViaAttachedData = false; + + try + { + OUString aRoleToMatch; + if( nDimensionIndex == 0 ) + aRoleToMatch = "values-x"; + const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCorrespondingCoordinateSystem->getChartTypes2()); + for( rtl::Reference< ChartType > const & chartType : aChartTypes ) + { + if( nDimensionIndex != 0 ) + aRoleToMatch = ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( chartType ); + for( rtl::Reference< DataSeries > const & xDataSeries : chartType->getDataSeries2() ) + { + if( nDimensionIndex == 1 ) + { + //only take those series into account that are attached to this axis + sal_Int32 nAttachedAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + if( nAttachedAxisIndex != nAxisIndex ) + continue; + } + + Reference< data::XLabeledDataSequence > xLabeledSeq( + DataSeriesHelper::getDataSequenceByRole( xDataSeries, aRoleToMatch ) ); + + if( !xLabeledSeq.is() && nDimensionIndex==0 ) + { + ScaleData aData = xAxis->getScaleData(); + xLabeledSeq = aData.Categories; + } + + if( xLabeledSeq.is() ) + { + Reference< data::XDataSequence > xSeq( xLabeledSeq->getValues()); + if( xSeq.is() ) + { + sal_Int32 nKey = xSeq->getNumberFormatKeyByIndex( -1 ); + // increase frequency + aKeyMap[ nKey ] ++; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( ! aKeyMap.empty()) + { + sal_Int32 nMaxFreq = 0; + // find most frequent key + for (auto const& elem : aKeyMap) + { + SAL_INFO( + "chart2.tools", + "NumberFormatKey " << elem.first << " appears " + << elem.second << " times"); + // all values must at least be 1 + if( elem.second > nMaxFreq ) + { + nNumberFormatKey = elem.first; + bNumberFormatKeyFoundViaAttachedData = true; + nMaxFreq = elem.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; + rtl::Reference< Axis > xParallelAxis = AxisHelper::getAxis( 1, nParallelAxisIndex, xCorrespondingCoordinateSystem ); + nNumberFormatKey = AxisHelper::getExplicitNumberFormatKeyForAxis(xParallelAxis, xCorrespondingCoordinateSystem, xChartDoc, false); + } + } + } + } + + return nNumberFormatKey; +} + +rtl::Reference< Axis > AxisHelper::createAxis( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex // 0==main or 1==secondary axis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , const Reference< uno::XComponentContext > & xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + if( !xContext.is() || !xCooSys.is() ) + return nullptr; + if( nDimensionIndex >= xCooSys->getDimension() ) + return nullptr; + + rtl::Reference< Axis > xAxis = new Axis(); + + xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex ); + + if( nAxisIndex>0 )//when inserting secondary axes copy some things from the main axis + { + css::chart::ChartAxisPosition eNewAxisPos( css::chart::ChartAxisPosition_END ); + + rtl::Reference< Axis > xMainAxis = xCooSys->getAxisByDimension2( nDimensionIndex, 0 ); + if( xMainAxis.is() ) + { + ScaleData aScale = xAxis->getScaleData(); + ScaleData aMainScale = xMainAxis->getScaleData(); + + aScale.AxisType = aMainScale.AxisType; + aScale.AutoDateAxis = aMainScale.AutoDateAxis; + aScale.Categories = aMainScale.Categories; + aScale.Orientation = aMainScale.Orientation; + aScale.ShiftedCategoryPosition = aMainScale.ShiftedCategoryPosition; + + xAxis->setScaleData( aScale ); + + //ensure that the second axis is not placed on the main axis + css::chart::ChartAxisPosition eMainAxisPos( css::chart::ChartAxisPosition_ZERO ); + xMainAxis->getPropertyValue("CrossoverPosition") >>= eMainAxisPos; + if( eMainAxisPos == css::chart::ChartAxisPosition_END ) + eNewAxisPos = css::chart::ChartAxisPosition_START; + } + + xAxis->setPropertyValue("CrossoverPosition", uno::Any(eNewAxisPos) ); + } + + try + { + // set correct initial AutoScale + if( pRefSizeProvider ) + pRefSizeProvider->setValuesAtPropertySet( xAxis ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xAxis; +} + +rtl::Reference< Axis > AxisHelper::createAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + OSL_ENSURE( xContext.is(), "need a context to create an axis" ); + if( !xContext.is() ) + return nullptr; + + sal_Int32 nAxisIndex = bMainAxis ? MAIN_AXIS_INDEX : SECONDARY_AXIS_INDEX; + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ); + + // create axis + return AxisHelper::createAxis( + nDimensionIndex, nAxisIndex, xCooSys, xContext, pRefSizeProvider ); +} + +void AxisHelper::showAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + if( !xDiagram.is() ) + return; + + bool bNewAxisCreated = false; + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ); + if( !xAxis.is() && xContext.is() ) + { + // create axis + bNewAxisCreated = true; + xAxis = AxisHelper::createAxis( nDimensionIndex, bMainAxis, xDiagram, xContext, pRefSizeProvider ); + } + + OSL_ASSERT( xAxis.is()); + if( !bNewAxisCreated ) //default is true already if created + AxisHelper::makeAxisVisible( xAxis ); +} + +void AxisHelper::showGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + { + //hhhh todo create axis without axis visibility + } + if(!xAxis.is()) + return; + + if( bMainGrid ) + AxisHelper::makeGridVisible( xAxis->getGridProperties() ); + else + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( auto const & i : aSubGrids ) + AxisHelper::makeGridVisible( i ); + } +} + +void AxisHelper::makeAxisVisible( const rtl::Reference< Axis >& xAxis ) +{ + if( xAxis.is() ) + { + xAxis->setPropertyValue( "Show", uno::Any( true ) ); + LinePropertiesHelper::SetLineVisible( xAxis ); + xAxis->setPropertyValue( "DisplayLabels", uno::Any( true ) ); + } +} + +void AxisHelper::makeGridVisible( const Reference< beans::XPropertySet >& xGridProperties ) +{ + if( xGridProperties.is() ) + { + xGridProperties->setPropertyValue( "Show", uno::Any( true ) ); + LinePropertiesHelper::SetLineVisible( xGridProperties ); + } +} + +void AxisHelper::hideAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + AxisHelper::makeAxisInvisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) ); +} + +void AxisHelper::makeAxisInvisible( const rtl::Reference< Axis >& xAxis ) +{ + if( xAxis.is() ) + { + xAxis->setPropertyValue( "Show", uno::Any( false ) ); + } +} + +void AxisHelper::hideAxisIfNoDataIsAttached( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram ) +{ + //axis is hidden if no data is attached anymore but data is available + bool bOtherSeriesAttachedToThisAxis = false; + std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + for (auto const& series : aSeriesVector) + { + rtl::Reference< Axis > xCurrentAxis = DiagramHelper::getAttachedAxis(series, xDiagram ); + if( xCurrentAxis==xAxis ) + { + bOtherSeriesAttachedToThisAxis = true; + break; + } + } + if(!bOtherSeriesAttachedToThisAxis && !aSeriesVector.empty() ) + AxisHelper::makeAxisInvisible( xAxis ); +} + +void AxisHelper::hideGrid( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + return; + + if( bMainGrid ) + AxisHelper::makeGridInvisible( xAxis->getGridProperties() ); + else + { + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( auto const & i : aSubGrids) + AxisHelper::makeGridInvisible( i ); + } +} + +void AxisHelper::makeGridInvisible( const Reference< beans::XPropertySet >& xGridProperties ) +{ + if( xGridProperties.is() ) + { + xGridProperties->setPropertyValue( "Show", uno::Any( false ) ); + } +} + +bool AxisHelper::isGridShown( sal_Int32 nDimensionIndex, sal_Int32 nCooSysIndex, bool bMainGrid + , const rtl::Reference< Diagram >& xDiagram ) +{ + bool bRet = false; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, nCooSysIndex ); + if(!xCooSys.is()) + return bRet; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, MAIN_AXIS_INDEX, xCooSys ); + if(!xAxis.is()) + return bRet; + + if( bMainGrid ) + bRet = AxisHelper::isGridVisible( xAxis->getGridProperties() ); + else + { + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + if( aSubGrids.hasElements() ) + bRet = AxisHelper::isGridVisible( aSubGrids[0] ); + } + + return bRet; +} + +rtl::Reference< ::chart::BaseCoordinateSystem > AxisHelper::getCoordinateSystemByIndex( + const rtl::Reference< Diagram >& xDiagram, sal_Int32 nIndex ) +{ + if(!xDiagram.is()) + return nullptr; + auto & rCooSysList = xDiagram->getBaseCoordinateSystems(); + if(0<=nIndex && o3tl::make_unsigned(nIndex) < rCooSysList.size()) + return rCooSysList[nIndex]; + return nullptr; +} + +rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + rtl::Reference< Axis > xRet; + try + { + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemByIndex( xDiagram, 0 ); + xRet = AxisHelper::getAxis( nDimensionIndex, bMainAxis ? 0 : 1, xCooSys ); + } + catch( const uno::Exception & ) + { + } + return xRet; +} + +rtl::Reference< Axis > AxisHelper::getAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + rtl::Reference< Axis > xRet; + if(!xCooSys.is()) + return xRet; + + if(nDimensionIndex >= xCooSys->getDimension()) + return xRet; + + if(nAxisIndex > xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex)) + return xRet; + + assert(nAxisIndex >= 0); + assert(nDimensionIndex >= 0); + xRet = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + return xRet; +} + +rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast(xAxis.get()); + assert(pAxis || !xAxis); + return getCrossingMainAxis(pAxis, xCooSys); +} + +rtl::Reference< Axis > AxisHelper::getCrossingMainAxis( const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + sal_Int32 nDimensionIndex = 0; + sal_Int32 nAxisIndex = 0; + AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + if( nDimensionIndex==2 ) + { + nDimensionIndex=1; + bool bSwapXY = false; + if( (xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXY) && bSwapXY ) + nDimensionIndex=0; + } + else if( nDimensionIndex==1 ) + nDimensionIndex=0; + else + nDimensionIndex=1; + return AxisHelper::getAxis( nDimensionIndex, 0, xCooSys ); +} + +rtl::Reference< Axis > AxisHelper::getParallelAxis( const Reference< XAxis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + try + { + sal_Int32 nCooSysIndex=-1; + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( getIndicesForAxis( xAxis, xDiagram, nCooSysIndex, nDimensionIndex, nAxisIndex ) ) + { + sal_Int32 nParallelAxisIndex = (nAxisIndex==1) ?0 :1; + return getAxis( nDimensionIndex, nParallelAxisIndex, getCoordinateSystemByIndex( xDiagram, nCooSysIndex ) ); + } + } + catch( const uno::RuntimeException& ) + { + } + return nullptr; +} + +bool AxisHelper::isAxisShown( sal_Int32 nDimensionIndex, bool bMainAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + return AxisHelper::isAxisVisible( AxisHelper::getAxis( nDimensionIndex, bMainAxis, xDiagram ) ); +} + +bool AxisHelper::isAxisVisible( const Reference< XAxis >& xAxis ) +{ + bool bRet = false; + + Reference< beans::XPropertySet > xProps( xAxis, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->getPropertyValue( "Show" ) >>= bRet; + bRet = bRet && ( LinePropertiesHelper::IsLineVisible( xProps ) + || areAxisLabelsVisible( xProps ) ); + } + + return bRet; +} + +bool AxisHelper::areAxisLabelsVisible( const Reference< beans::XPropertySet >& xAxisProperties ) +{ + bool bRet = false; + if( xAxisProperties.is() ) + { + xAxisProperties->getPropertyValue( "DisplayLabels" ) >>= bRet; + } + return bRet; +} + +bool AxisHelper::isGridVisible( const Reference< beans::XPropertySet >& xGridproperties ) +{ + bool bRet = false; + + if( xGridproperties.is() ) + { + xGridproperties->getPropertyValue( "Show" ) >>= bRet; + bRet = bRet && LinePropertiesHelper::IsLineVisible( xGridproperties ); + } + + return bRet; +} + +Reference< beans::XPropertySet > AxisHelper::getGridProperties( + const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex, sal_Int32 nSubGridIndex ) +{ + Reference< beans::XPropertySet > xRet; + + rtl::Reference< Axis > xAxis( AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ) ); + if( xAxis.is() ) + { + if( nSubGridIndex<0 ) + xRet.set( xAxis->getGridProperties() ); + else + { + Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + if (nSubGridIndex < aSubGrids.getLength()) + xRet.set( aSubGrids[nSubGridIndex] ); + } + } + + return xRet; +} + +sal_Int32 AxisHelper::getDimensionIndexOfAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + sal_Int32 nDimensionIndex = -1; + sal_Int32 nCooSysIndex = -1; + sal_Int32 nAxisIndex = -1; + AxisHelper::getIndicesForAxis( xAxis, xDiagram, nCooSysIndex , nDimensionIndex, nAxisIndex ); + return nDimensionIndex; +} + +bool AxisHelper::getIndicesForAxis( + const Reference< chart2::XAxis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast(xAxis.get()); + assert(pAxis || !xAxis); + return getIndicesForAxis(pAxis, xCooSys, rOutDimensionIndex, rOutAxisIndex); +} + +bool AxisHelper::getIndicesForAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys + , sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + //returns true if indices are found + + rOutDimensionIndex = -1; + rOutAxisIndex = -1; + + if( !xCooSys || !xAxis ) + return false; + + rtl::Reference< Axis > xCurrentAxis; + sal_Int32 nDimensionCount( xCooSys->getDimension() ); + for( sal_Int32 nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + xCurrentAxis = xCooSys->getAxisByDimension2(nDimensionIndex,nAxisIndex); + if( xCurrentAxis == xAxis ) + { + rOutDimensionIndex = nDimensionIndex; + rOutAxisIndex = nAxisIndex; + return true; + } + } + } + return false; +} + +bool AxisHelper::getIndicesForAxis( const Reference< chart2::XAxis >& xAxis, const rtl::Reference< Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast(xAxis.get()); + assert(pAxis || !xAxis); + return getIndicesForAxis(pAxis, xDiagram, rOutCooSysIndex, rOutDimensionIndex, rOutAxisIndex); +} + +bool AxisHelper::getIndicesForAxis( const rtl::Reference< Axis >& xAxis, const rtl::Reference< Diagram >& xDiagram + , sal_Int32& rOutCooSysIndex, sal_Int32& rOutDimensionIndex, sal_Int32& rOutAxisIndex ) +{ + //returns true if indices are found + + rOutCooSysIndex = -1; + rOutDimensionIndex = -1; + rOutAxisIndex = -1; + + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList = xDiagram->getBaseCoordinateSystems(); + for( std::size_t nC=0; nC < aCooSysList.size(); ++nC ) + { + if( AxisHelper::getIndicesForAxis( xAxis, aCooSysList[nC], rOutDimensionIndex, rOutAxisIndex ) ) + { + rOutCooSysIndex = nC; + return true; + } + } + + return false; +} + +std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfCoordinateSystem( + const rtl::Reference< BaseCoordinateSystem >& xCooSys + , bool bOnlyVisible /* = false */ ) +{ + std::vector< rtl::Reference< Axis > > aAxisVector; + + if(xCooSys.is()) + { + sal_Int32 nMaxDimensionIndex = xCooSys->getDimension() -1; + if( nMaxDimensionIndex>=0 ) + { + sal_Int32 nDimensionIndex = 0; + for(; nDimensionIndex<=nMaxDimensionIndex; ++nDimensionIndex) + { + const sal_Int32 nMaximumAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex) + { + try + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + if( xAxis.is() ) + { + bool bAddAxis = true; + if( bOnlyVisible ) + { + if( !(xAxis->getPropertyValue( "Show") >>= bAddAxis) ) + bAddAxis = false; + } + if( bAddAxis ) + aAxisVector.push_back( xAxis ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + } + + return aAxisVector; +} + +std::vector< rtl::Reference< Axis > > AxisHelper::getAllAxesOfDiagram( + const rtl::Reference< Diagram >& xDiagram + , bool bOnlyVisible ) +{ + std::vector< rtl::Reference< Axis > > aAxisVector; + + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + std::vector< rtl::Reference< Axis > > aAxesPerCooSys = AxisHelper::getAllAxesOfCoordinateSystem( coords, bOnlyVisible ); + aAxisVector.insert( aAxisVector.end(), aAxesPerCooSys.begin(), aAxesPerCooSys.end() ); + } + + return aAxisVector; +} + +Sequence< Reference< beans::XPropertySet > > AxisHelper::getAllGrids( const rtl::Reference< Diagram >& xDiagram ) +{ + const std::vector< rtl::Reference< Axis > > aAllAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + std::vector< Reference< beans::XPropertySet > > aGridVector; + + for( rtl::Reference< Axis > const & xAxis : aAllAxes ) + { + Reference< beans::XPropertySet > xGridProperties( xAxis->getGridProperties() ); + if( xGridProperties.is() ) + aGridVector.push_back( xGridProperties ); + + const Sequence< Reference< beans::XPropertySet > > aSubGrids( xAxis->getSubGridProperties() ); + for( Reference< beans::XPropertySet > const & xSubGrid : aSubGrids ) + { + if( xSubGrid.is() ) + aGridVector.push_back( xSubGrid ); + } + } + + return comphelper::containerToSequence( aGridVector ); +} + +void AxisHelper::getAxisOrGridPossibilities( Sequence< sal_Bool >& rPossibilityList + , const rtl::Reference< Diagram>& xDiagram, bool bAxis ) +{ + rPossibilityList.realloc(6); + sal_Bool* pPossibilityList = rPossibilityList.getArray(); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + + //set possibilities: + sal_Int32 nIndex=0; + rtl::Reference< ChartType > xChartType = DiagramHelper::getChartTypeByIndex( xDiagram, 0 ); + for(nIndex=0;nIndex<3;nIndex++) + pPossibilityList[nIndex]=ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nIndex); + for(nIndex=3;nIndex<6;nIndex++) + if( bAxis ) + pPossibilityList[nIndex]=ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount); + else + pPossibilityList[nIndex] = rPossibilityList[nIndex-3]; +} + +bool AxisHelper::isSecondaryYAxisNeeded( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + if( !xCooSys.is() ) + return false; + + const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & chartType : aChartTypes ) + { + const std::vector< rtl::Reference< DataSeries > > & aSeriesList = chartType->getDataSeries2(); + for( sal_Int32 nS = aSeriesList.size(); nS-- ; ) + { + sal_Int32 nAttachedAxisIndex = 0; + if( ( aSeriesList[nS]->getPropertyValue( "AttachedAxisIndex" ) >>= nAttachedAxisIndex ) && + nAttachedAxisIndex>0 ) + return true; + } + } + return false; +} + +bool AxisHelper::shouldAxisBeDisplayed( const rtl::Reference< Axis >& xAxis + , const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + bool bRet = false; + + if( xAxis.is() && xCooSys.is() ) + { + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) + { + sal_Int32 nDimensionCount = xCooSys->getDimension(); + rtl::Reference< ChartType > xChartType( AxisHelper::getChartTypeByIndex( xCooSys, 0 ) ); + + bool bMainAxis = (nAxisIndex==MAIN_AXIS_INDEX); + if( bMainAxis ) + bRet = ChartTypeHelper::isSupportingMainAxis(xChartType,nDimensionCount,nDimensionIndex); + else + bRet = ChartTypeHelper::isSupportingSecondaryAxis(xChartType,nDimensionCount); + } + } + + return bRet; +} + +void AxisHelper::getAxisOrGridExistence( Sequence< sal_Bool >& rExistenceList + , const rtl::Reference< Diagram>& xDiagram, bool bAxis ) +{ + rExistenceList.realloc(6); + sal_Bool* pExistenceList = rExistenceList.getArray(); + + if(bAxis) + { + sal_Int32 nN; + for(nN=0;nN<3;nN++) + pExistenceList[nN] = AxisHelper::isAxisShown( nN, true, xDiagram ); + for(nN=3;nN<6;nN++) + pExistenceList[nN] = AxisHelper::isAxisShown( nN%3, false, xDiagram ); + } + else + { + sal_Int32 nN; + + for(nN=0;nN<3;nN++) + pExistenceList[nN] = AxisHelper::isGridShown( nN, 0, true, xDiagram ); + for(nN=3;nN<6;nN++) + pExistenceList[nN] = AxisHelper::isGridShown( nN%3, 0, false, xDiagram ); + } +} + +bool AxisHelper::changeVisibilityOfAxes( const rtl::Reference< Diagram >& xDiagram + , const Sequence< sal_Bool >& rOldExistenceList + , const Sequence< sal_Bool >& rNewExistenceList + , const Reference< uno::XComponentContext >& xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + bool bChanged = false; + for(sal_Int32 nN=0;nN<6;nN++) + { + if(rOldExistenceList[nN]!=rNewExistenceList[nN]) + { + bChanged = true; + if(rNewExistenceList[nN]) + { + AxisHelper::showAxis( nN%3, nN<3, xDiagram, xContext, pRefSizeProvider ); + } + else + AxisHelper::hideAxis( nN%3, nN<3, xDiagram ); + } + } + return bChanged; +} + +bool AxisHelper::changeVisibilityOfGrids( const rtl::Reference< Diagram >& xDiagram + , const Sequence< sal_Bool >& rOldExistenceList + , const Sequence< sal_Bool >& rNewExistenceList ) +{ + bool bChanged = false; + for(sal_Int32 nN=0;nN<6;nN++) + { + if(rOldExistenceList[nN]!=rNewExistenceList[nN]) + { + bChanged = true; + if(rNewExistenceList[nN]) + AxisHelper::showGrid( nN%3, 0, nN<3, xDiagram ); + else + AxisHelper::hideGrid( nN%3, 0, nN<3, xDiagram ); + } + } + return bChanged; +} + +rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis( + const Reference< XAxis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + rtl::Reference< Axis > pAxis = dynamic_cast(xAxis.get()); + assert(pAxis || !xAxis); + return getCoordinateSystemOfAxis(pAxis, xDiagram); +} + +rtl::Reference< BaseCoordinateSystem > AxisHelper::getCoordinateSystemOfAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference< Diagram >& xDiagram ) +{ + if (!xDiagram) + return nullptr; + + rtl::Reference< BaseCoordinateSystem > xRet; + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + std::vector< rtl::Reference< Axis > > aAllAxis = AxisHelper::getAllAxesOfCoordinateSystem( xCooSys ); + + auto aFound = std::find( aAllAxis.begin(), aAllAxis.end(), xAxis ); + if( aFound != aAllAxis.end()) + { + xRet = xCooSys; + break; + } + } + return xRet; +} + +rtl::Reference< ChartType > AxisHelper::getChartTypeByIndex( const rtl::Reference< BaseCoordinateSystem >& xCooSys, sal_Int32 nIndex ) +{ + rtl::Reference< ChartType > xChartType; + + if( xCooSys.is() ) + { + const std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aChartTypeList.size() ) + xChartType = aChartTypeList[nIndex]; + } + + return xChartType; +} + +void AxisHelper::setRTLAxisLayout( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + if( !xCooSys.is() ) + return; + + bool bCartesian = xCooSys->getViewServiceName() == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME; + if( !bCartesian ) + return; + + bool bVertical = false; + xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bVertical; + + sal_Int32 nHorizontalAxisDimension = bVertical ? 1 : 0; + sal_Int32 nVerticalAxisDimension = bVertical ? 0 : 1; + + try + { + //reverse direction for horizontal main axis + rtl::Reference< Axis > xHorizontalMainAxis = AxisHelper::getAxis( nHorizontalAxisDimension, MAIN_AXIS_INDEX, xCooSys ); + if( xHorizontalMainAxis.is() ) + { + chart2::ScaleData aScale = xHorizontalMainAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_REVERSE; + xHorizontalMainAxis->setScaleData(aScale); + } + + //mathematical direction for vertical main axis + rtl::Reference< Axis > xVerticalMainAxis = AxisHelper::getAxis( nVerticalAxisDimension, MAIN_AXIS_INDEX, xCooSys ); + if( xVerticalMainAxis.is() ) + { + chart2::ScaleData aScale = xVerticalMainAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xVerticalMainAxis->setScaleData(aScale); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + try + { + //reverse direction for horizontal secondary axis + rtl::Reference< Axis > xHorizontalSecondaryAxis = AxisHelper::getAxis( nHorizontalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys ); + if( xHorizontalSecondaryAxis.is() ) + { + chart2::ScaleData aScale = xHorizontalSecondaryAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_REVERSE; + xHorizontalSecondaryAxis->setScaleData(aScale); + } + + //mathematical direction for vertical secondary axis + rtl::Reference< Axis > xVerticalSecondaryAxis = AxisHelper::getAxis( nVerticalAxisDimension, SECONDARY_AXIS_INDEX, xCooSys ); + if( xVerticalSecondaryAxis.is() ) + { + chart2::ScaleData aScale = xVerticalSecondaryAxis->getScaleData(); + aScale.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xVerticalSecondaryAxis->setScaleData(aScale); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +rtl::Reference< ChartType > AxisHelper::getFirstChartTypeWithSeriesAttachedToAxisIndex( const rtl::Reference< Diagram >& xDiagram, const sal_Int32 nAttachedAxisIndex ) +{ + rtl::Reference< ChartType > xChartType; + std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + for (auto const& series : aSeriesVector) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); + if( nAttachedAxisIndex == nCurrentIndex ) + { + xChartType = DiagramHelper::getChartTypeOfSeries(xDiagram, series); + if(xChartType.is()) + break; + } + } + return xChartType; +} + +bool AxisHelper::isAxisPositioningEnabled() +{ + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(GetODFSaneDefaultVersion()); + return nCurrentVersion >= SvtSaveOptions::ODFSVER_012; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/BaseGFXHelper.cxx b/chart2/source/tools/BaseGFXHelper.cxx new file mode 100644 index 000000000..17bd4f5e1 --- /dev/null +++ b/chart2/source/tools/BaseGFXHelper.cxx @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::drawing; +using namespace ::basegfx; + +namespace chart::BaseGFXHelper +{ + +::basegfx::B3DRange getBoundVolume( const drawing::PolyPolygonShape3D& rPolyPoly ) +{ + ::basegfx::B3DRange aRet; + + bool bInited = false; + sal_Int32 nPolyCount = rPolyPoly.SequenceX.getLength(); + for(sal_Int32 nPoly = 0; nPoly < nPolyCount; nPoly++) + { + sal_Int32 nPointCount = rPolyPoly.SequenceX[nPoly].getLength(); + for( sal_Int32 nPoint = 0; nPoint < nPointCount; nPoint++) + { + if(!bInited) + { + aRet = ::basegfx::B3DRange(::basegfx::B3DTuple( + rPolyPoly.SequenceX[nPoly][nPoint] + , rPolyPoly.SequenceY[nPoly][nPoint] + , rPolyPoly.SequenceZ[nPoly][nPoint])); + bInited = true; + } + else + { + aRet.expand( ::basegfx::B3DTuple( + rPolyPoly.SequenceX[nPoly][nPoint] + , rPolyPoly.SequenceY[nPoly][nPoint] + , rPolyPoly.SequenceZ[nPoly][nPoint])); + } + } + } + + return aRet; +} + +::basegfx::B3DRange getBoundVolume( const std::vector>& rPolyPoly ) +{ + ::basegfx::B3DRange aRet; + + bool bInited = false; + sal_Int32 nPolyCount = rPolyPoly.size(); + for(sal_Int32 nPoly = 0; nPoly < nPolyCount; nPoly++) + { + sal_Int32 nPointCount = rPolyPoly[nPoly].size(); + for( sal_Int32 nPoint = 0; nPoint < nPointCount; nPoint++) + { + if(!bInited) + { + aRet = ::basegfx::B3DRange(::basegfx::B3DTuple( + rPolyPoly[nPoly][nPoint].PositionX + , rPolyPoly[nPoly][nPoint].PositionY + , rPolyPoly[nPoly][nPoint].PositionZ)); + bInited = true; + } + else + { + aRet.expand( ::basegfx::B3DTuple( + rPolyPoly[nPoly][nPoint].PositionX + , rPolyPoly[nPoly][nPoint].PositionY + , rPolyPoly[nPoly][nPoint].PositionZ)); + } + } + } + + return aRet; +} + +B2IRectangle makeRectangle( const awt::Point& rPos, const awt::Size& rSize ) +{ + return B2IRectangle(rPos.X,rPos.Y,rPos.X+rSize.Width,rPos.Y+rSize.Height); +} + +B2IRectangle makeRectangle( const awt::Rectangle& rRect ) +{ + return B2IRectangle(rRect.X, rRect.Y, rRect.X+rRect.Width, rRect.Y+rRect.Height); +} + +awt::Point B2IRectangleToAWTPoint( const ::basegfx::B2IRectangle& rB2IRectangle ) +{ + return awt::Point( rB2IRectangle.getMinX(), rB2IRectangle.getMinY() ); +} + +awt::Size B2IRectangleToAWTSize( const ::basegfx::B2IRectangle& rB2IRectangle ) +{ + return awt::Size( static_cast< sal_Int32 >( rB2IRectangle.getWidth()), + static_cast< sal_Int32 >( rB2IRectangle.getHeight())); +} + +awt::Rectangle toAwtRectangle(const basegfx::B2IRectangle& rRectangle) +{ + return awt::Rectangle(rRectangle.getMinX(), rRectangle.getMinY(), + rRectangle.getWidth(), rRectangle.getHeight()); +} + +B3DVector Direction3DToB3DVector( const Direction3D& rDirection ) +{ + return B3DVector( + rDirection.DirectionX + , rDirection.DirectionY + , rDirection.DirectionZ + ); +} + +Direction3D B3DVectorToDirection3D( const B3DVector& rB3DVector ) +{ + return Direction3D( + rB3DVector.getX() + , rB3DVector.getY() + , rB3DVector.getZ() + ); +} + +B3DVector Position3DToB3DVector( const Position3D& rPosition ) +{ + return B3DVector( + rPosition.PositionX + , rPosition.PositionY + , rPosition.PositionZ + ); +} + +Position3D B3DVectorToPosition3D( const B3DVector& rB3DVector ) +{ + return Position3D( + rB3DVector.getX() + , rB3DVector.getY() + , rB3DVector.getZ() + ); +} + +B3DHomMatrix HomogenMatrixToB3DHomMatrix( const HomogenMatrix & rHomogenMatrix ) +{ + B3DHomMatrix aResult; + + aResult.set( 0, 0, rHomogenMatrix.Line1.Column1 ); + aResult.set( 0, 1, rHomogenMatrix.Line1.Column2 ); + aResult.set( 0, 2, rHomogenMatrix.Line1.Column3 ); + aResult.set( 0, 3, rHomogenMatrix.Line1.Column4 ); + + aResult.set( 1, 0, rHomogenMatrix.Line2.Column1 ); + aResult.set( 1, 1, rHomogenMatrix.Line2.Column2 ); + aResult.set( 1, 2, rHomogenMatrix.Line2.Column3 ); + aResult.set( 1, 3, rHomogenMatrix.Line2.Column4 ); + + aResult.set( 2, 0, rHomogenMatrix.Line3.Column1 ); + aResult.set( 2, 1, rHomogenMatrix.Line3.Column2 ); + aResult.set( 2, 2, rHomogenMatrix.Line3.Column3 ); + aResult.set( 2, 3, rHomogenMatrix.Line3.Column4 ); + + aResult.set( 3, 0, rHomogenMatrix.Line4.Column1 ); + aResult.set( 3, 1, rHomogenMatrix.Line4.Column2 ); + aResult.set( 3, 2, rHomogenMatrix.Line4.Column3 ); + aResult.set( 3, 3, rHomogenMatrix.Line4.Column4 ); + + return aResult; +} + +HomogenMatrix B3DHomMatrixToHomogenMatrix( const B3DHomMatrix & rB3DMatrix ) +{ + HomogenMatrix aResult; + + aResult.Line1.Column1 = rB3DMatrix.get( 0, 0 ); + aResult.Line1.Column2 = rB3DMatrix.get( 0, 1 ); + aResult.Line1.Column3 = rB3DMatrix.get( 0, 2 ); + aResult.Line1.Column4 = rB3DMatrix.get( 0, 3 ); + + aResult.Line2.Column1 = rB3DMatrix.get( 1, 0 ); + aResult.Line2.Column2 = rB3DMatrix.get( 1, 1 ); + aResult.Line2.Column3 = rB3DMatrix.get( 1, 2 ); + aResult.Line2.Column4 = rB3DMatrix.get( 1, 3 ); + + aResult.Line3.Column1 = rB3DMatrix.get( 2, 0 ); + aResult.Line3.Column2 = rB3DMatrix.get( 2, 1 ); + aResult.Line3.Column3 = rB3DMatrix.get( 2, 2 ); + aResult.Line3.Column4 = rB3DMatrix.get( 2, 3 ); + + aResult.Line4.Column1 = rB3DMatrix.get( 3, 0 ); + aResult.Line4.Column2 = rB3DMatrix.get( 3, 1 ); + aResult.Line4.Column3 = rB3DMatrix.get( 3, 2 ); + aResult.Line4.Column4 = rB3DMatrix.get( 3, 3 ); + + return aResult; +} + +B3DTuple GetRotationFromMatrix( const B3DHomMatrix & rB3DMatrix ) +{ + B3DTuple aScale, aTranslation, aRotation, aShearing; + rB3DMatrix.decompose( aScale, aTranslation, aRotation, aShearing ); + return aRotation; +} + +B3DTuple GetScaleFromMatrix( const B3DHomMatrix & rB3DMatrix ) +{ + B3DTuple aScale, aTranslation, aRotation, aShearing; + rB3DMatrix.decompose( aScale, aTranslation, aRotation, aShearing ); + return aScale; +} + +void ReduceToRotationMatrix( ::basegfx::B3DHomMatrix & rB3DMatrix ) +{ + B3DTuple aR( GetRotationFromMatrix( rB3DMatrix ) ); + ::basegfx::B3DHomMatrix aRotationMatrix; + aRotationMatrix.rotate(aR.getX(),aR.getY(),aR.getZ()); + rB3DMatrix = aRotationMatrix; +} + +} // namespace chart::BaseGFXHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/CachedDataSequence.cxx b/chart2/source/tools/CachedDataSequence.cxx new file mode 100644 index 000000000..440e9f736 --- /dev/null +++ b/chart2/source/tools/CachedDataSequence.cxx @@ -0,0 +1,352 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +// necessary for MS compiler +using ::comphelper::OPropertyContainer; +using ::comphelper::OMutexAndBroadcastHelper; +using ::comphelper::OPropertyArrayUsageHelper; +using ::chart::impl::CachedDataSequence_Base; + +namespace +{ +constexpr OUStringLiteral lcl_aServiceName = u"com.sun.star.comp.chart.CachedDataSequence"; + +enum +{ +// PROP_SOURCE_IDENTIFIER, + PROP_NUMBERFORMAT_KEY, + PROP_PROPOSED_ROLE +}; +} // anonymous namespace + +namespace chart +{ + +CachedDataSequence::CachedDataSequence() + : OPropertyContainer( GetBroadcastHelper()), + CachedDataSequence_Base( GetMutex()), + m_eCurrentDataType( NUMERICAL ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); +} +CachedDataSequence::CachedDataSequence( const Reference< uno::XComponentContext > & /*xContext*/ ) + : OPropertyContainer( GetBroadcastHelper()), + CachedDataSequence_Base( GetMutex()), + m_eCurrentDataType( MIXED ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); +} + +CachedDataSequence::CachedDataSequence( const OUString & rSingleText ) + : OPropertyContainer( GetBroadcastHelper()), + CachedDataSequence_Base( GetMutex()), + m_eCurrentDataType( TEXTUAL ), + m_aTextualSequence({rSingleText}), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); +} + +CachedDataSequence::CachedDataSequence( const CachedDataSequence & rSource ) + : OPropertyContainer( GetBroadcastHelper()), + CachedDataSequence_Base( GetMutex()), + m_nNumberFormatKey( rSource.m_nNumberFormatKey ), + m_sRole( rSource.m_sRole ), + m_eCurrentDataType( rSource.m_eCurrentDataType ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + switch( m_eCurrentDataType ) + { + case TEXTUAL: + m_aTextualSequence = rSource.m_aTextualSequence; + break; + case NUMERICAL: + m_aNumericalSequence = rSource.m_aNumericalSequence; + break; + case MIXED: + m_aMixedSequence = rSource.m_aMixedSequence; + break; + } + + registerProperties(); +} + +CachedDataSequence::~CachedDataSequence() +{} + +void CachedDataSequence::registerProperties() +{ + registerProperty( "NumberFormatKey", + PROP_NUMBERFORMAT_KEY, + 0, // PropertyAttributes + & m_nNumberFormatKey, + cppu::UnoType::get() ); + + registerProperty( "Role", + PROP_PROPOSED_ROLE, + 0, // PropertyAttributes + & m_sRole, + cppu::UnoType::get() ); +} + +Sequence< double > CachedDataSequence::Impl_getNumericalData() const +{ + if( m_eCurrentDataType == NUMERICAL ) + return m_aNumericalSequence; + + sal_Int32 nSize = ( m_eCurrentDataType == TEXTUAL ) + ? m_aTextualSequence.getLength() + : m_aMixedSequence.getLength(); + + Sequence< double > aResult( nSize ); + double * pResultArray = aResult.getArray(); + + if( m_eCurrentDataType == TEXTUAL ) + { + const OUString * pTextArray = m_aTextualSequence.getConstArray(); + std::transform( pTextArray, pTextArray + nSize, + pResultArray, + CommonFunctors::OUStringToDouble() ); + } + else + { + OSL_ASSERT( m_eCurrentDataType == MIXED ); + const Any * pMixedArray = m_aMixedSequence.getConstArray(); + std::transform( pMixedArray, pMixedArray + nSize, + pResultArray, + CommonFunctors::AnyToDouble() ); + } + return aResult; +} + +Sequence< OUString > CachedDataSequence::Impl_getTextualData() const +{ + if( m_eCurrentDataType == TEXTUAL ) + return m_aTextualSequence; + + sal_Int32 nSize = ( m_eCurrentDataType == NUMERICAL ) + ? m_aNumericalSequence.getLength() + : m_aMixedSequence.getLength(); + + Sequence< OUString > aResult( nSize ); + OUString * pResultArray = aResult.getArray(); + + if( m_eCurrentDataType == NUMERICAL ) + { + const double * pTextArray = m_aNumericalSequence.getConstArray(); + std::transform( pTextArray, pTextArray + nSize, + pResultArray, + CommonFunctors::DoubleToOUString() ); + } + else + { + OSL_ASSERT( m_eCurrentDataType == MIXED ); + const Any * pMixedArray = m_aMixedSequence.getConstArray(); + std::transform( pMixedArray, pMixedArray + nSize, + pResultArray, + CommonFunctors::AnyToString() ); + } + + return aResult; +} + +Sequence< Any > CachedDataSequence::Impl_getMixedData() const +{ + if( m_eCurrentDataType == MIXED ) + return m_aMixedSequence; + + sal_Int32 nSize = ( m_eCurrentDataType == NUMERICAL ) + ? m_aNumericalSequence.getLength() + : m_aTextualSequence.getLength(); + + Sequence< Any > aResult( nSize ); + Any * pResultArray = aResult.getArray(); + + if( m_eCurrentDataType == NUMERICAL ) + { + const double * pTextArray = m_aNumericalSequence.getConstArray(); + std::transform( pTextArray, pTextArray + nSize, + pResultArray, + CommonFunctors::makeAny< double >() ); + } + else + { + OSL_ASSERT( m_eCurrentDataType == TEXTUAL ); + const OUString * pMixedArray = m_aTextualSequence.getConstArray(); + std::transform( pMixedArray, pMixedArray + nSize, + pResultArray, + CommonFunctors::makeAny< OUString >() ); + } + + return aResult; +} + +IMPLEMENT_FORWARD_XINTERFACE2( CachedDataSequence, CachedDataSequence_Base, OPropertyContainer ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( CachedDataSequence, CachedDataSequence_Base, OPropertyContainer ) + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL CachedDataSequence::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +// ____ ::comphelper::OPropertySetHelper ____ +::cppu::IPropertyArrayHelper& CachedDataSequence::getInfoHelper() +{ + return *getArrayHelper(); +} + +// ____ ::comphelper::OPropertyArrayHelper ____ +::cppu::IPropertyArrayHelper* CachedDataSequence::createArrayHelper() const +{ + Sequence< beans::Property > aProps; + // describes all properties which have been registered in the ctor + describeProperties( aProps ); + + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +OUString SAL_CALL CachedDataSequence::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL CachedDataSequence::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL CachedDataSequence::getSupportedServiceNames() +{ + return { + lcl_aServiceName, + "com.sun.star.chart2.data.DataSequence", + "com.sun.star.chart2.data.NumericalDataSequence", + "com.sun.star.chart2.data.TextualDataSequence" + }; +} + +// ________ XNumericalDataSequence ________ +Sequence< double > SAL_CALL CachedDataSequence::getNumericalData() +{ + MutexGuard aGuard( GetMutex() ); + + if( m_eCurrentDataType == NUMERICAL ) + return m_aNumericalSequence; + else + return Impl_getNumericalData(); +} + +// ________ XTextualDataSequence ________ +Sequence< OUString > SAL_CALL CachedDataSequence::getTextualData() +{ + MutexGuard aGuard( GetMutex() ); + + if( m_eCurrentDataType == TEXTUAL ) + return m_aTextualSequence; + else + return Impl_getTextualData(); +} + +// ________ XDataSequence ________ +Sequence< Any > SAL_CALL CachedDataSequence::getData() +{ + MutexGuard aGuard( GetMutex() ); + return Impl_getMixedData(); +} + +OUString SAL_CALL CachedDataSequence::getSourceRangeRepresentation() +{ + return m_sRole; +} + +Sequence< OUString > SAL_CALL CachedDataSequence::generateLabel( chart2::data::LabelOrigin /*eLabelOrigin*/ ) +{ + // return empty label, as we have no range representations to determine something useful + return Sequence< OUString >(); +} + +::sal_Int32 SAL_CALL CachedDataSequence::getNumberFormatKeyByIndex( ::sal_Int32 /*nIndex*/ ) +{ + return 0; +} + +Reference< util::XCloneable > SAL_CALL CachedDataSequence::createClone() +{ + return new CachedDataSequence( *this ); +} + +void SAL_CALL CachedDataSequence::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL CachedDataSequence::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// lang::XInitialization: +void SAL_CALL CachedDataSequence::initialize(const uno::Sequence< uno::Any > & _aArguments) +{ + ::comphelper::SequenceAsHashMap aMap(_aArguments); + m_aNumericalSequence = aMap.getUnpackedValueOrDefault( "DataSequence" ,m_aNumericalSequence); + if ( m_aNumericalSequence.hasElements() ) + m_eCurrentDataType = NUMERICAL; + else + { + m_aTextualSequence = aMap.getUnpackedValueOrDefault( "DataSequence" ,m_aTextualSequence); + if ( m_aTextualSequence.hasElements() ) + m_eCurrentDataType = TEXTUAL; + else + { + m_aMixedSequence = aMap.getUnpackedValueOrDefault( "DataSequence" ,m_aMixedSequence); + if ( m_aMixedSequence.hasElements() ) + m_eCurrentDataType = MIXED; + } + } +} +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_CachedDataSequence_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::CachedDataSequence(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/CharacterProperties.cxx b/chart2/source/tools/CharacterProperties.cxx new file mode 100644 index 000000000..2923cc17b --- /dev/null +++ b/chart2/source/tools/CharacterProperties.cxx @@ -0,0 +1,459 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void CharacterProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // CharacterProperties + rOutProperties.emplace_back( "CharFontName", + PROP_CHAR_FONT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "CharFontStyleName", + PROP_CHAR_FONT_STYLE_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharFontFamily (see awt.FontFamily) + rOutProperties.emplace_back( "CharFontFamily", + PROP_CHAR_FONT_FAMILY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontCharSet (see awt.CharSet) + rOutProperties.emplace_back( "CharFontCharSet", + PROP_CHAR_FONT_CHAR_SET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontPitch (see awt.FontPitch) + rOutProperties.emplace_back( "CharFontPitch", + PROP_CHAR_FONT_PITCH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharColor + rOutProperties.emplace_back( "CharColor", + PROP_CHAR_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharEscapement + rOutProperties.emplace_back( "CharEscapement", + PROP_CHAR_ESCAPEMENT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + // CharHeight + rOutProperties.emplace_back( "CharHeight", + PROP_CHAR_CHAR_HEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharUnderline (see awt.FontUnderline) + rOutProperties.emplace_back( "CharUnderline", + PROP_CHAR_UNDERLINE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharUnderlineColor + rOutProperties.emplace_back( "CharUnderlineColor", + PROP_CHAR_UNDERLINE_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharUnderlineHasColor + rOutProperties.emplace_back( "CharUnderlineHasColor", + PROP_CHAR_UNDERLINE_HAS_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharOverline (see awt.FontUnderline) + rOutProperties.emplace_back( "CharOverline", + PROP_CHAR_OVERLINE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharOverlineColor + rOutProperties.emplace_back( "CharOverlineColor", + PROP_CHAR_OVERLINE_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharOverlineHasColor + rOutProperties.emplace_back( "CharOverlineHasColor", + PROP_CHAR_OVERLINE_HAS_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharWeight (see awt.FontWeight) + rOutProperties.emplace_back( "CharWeight", + PROP_CHAR_WEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharPosture + rOutProperties.emplace_back( "CharPosture", + PROP_CHAR_POSTURE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "CharAutoKerning", + PROP_CHAR_AUTO_KERNING, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "CharKerning", + PROP_CHAR_KERNING, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharEscapementHeight + rOutProperties.emplace_back( "CharEscapementHeight", + PROP_CHAR_ESCAPEMENT_HEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + // CharStrikeout (see awt.FontStrikeout) + rOutProperties.emplace_back( "CharStrikeout", + PROP_CHAR_STRIKE_OUT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharWordMode + rOutProperties.emplace_back( "CharWordMode", + PROP_CHAR_WORD_MODE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharLocale + rOutProperties.emplace_back( "CharLocale", + PROP_CHAR_LOCALE, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + // CharShadowed + rOutProperties.emplace_back( "CharShadowed", + PROP_CHAR_SHADOWED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharContoured + rOutProperties.emplace_back( "CharContoured", + PROP_CHAR_CONTOURED, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharRelief (see text.FontRelief) + rOutProperties.emplace_back( "CharRelief", + PROP_CHAR_RELIEF, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // CharEmphasize (see text.FontEmphasis) + rOutProperties.emplace_back( "CharEmphasis", + PROP_CHAR_EMPHASIS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharacterPropertiesAsian + + // CharFontNameAsian + rOutProperties.emplace_back( "CharFontNameAsian", + PROP_CHAR_ASIAN_FONT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontStyleNameAsian + rOutProperties.emplace_back( "CharFontStyleNameAsian", + PROP_CHAR_ASIAN_FONT_STYLE_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharFontFamilyAsian (see awt.FontFamily) + rOutProperties.emplace_back( "CharFontFamilyAsian", + PROP_CHAR_ASIAN_FONT_FAMILY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontCharSetAsian (see awt.CharSet) + rOutProperties.emplace_back( "CharFontCharSetAsian", + PROP_CHAR_ASIAN_CHAR_SET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontPitchAsian (see awt.FontPitch) + rOutProperties.emplace_back( "CharFontPitchAsian", + PROP_CHAR_ASIAN_FONT_PITCH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharHeightAsian + rOutProperties.emplace_back( "CharHeightAsian", + PROP_CHAR_ASIAN_CHAR_HEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharWeightAsian + rOutProperties.emplace_back( "CharWeightAsian", + PROP_CHAR_ASIAN_WEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharPostureAsian + rOutProperties.emplace_back( "CharPostureAsian", + PROP_CHAR_ASIAN_POSTURE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharLocaleAsian + rOutProperties.emplace_back( "CharLocaleAsian", + PROP_CHAR_ASIAN_LOCALE, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + // CharacterPropertiesComplex + + // CharFontNameComplex + rOutProperties.emplace_back( "CharFontNameComplex", + PROP_CHAR_COMPLEX_FONT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontStyleNameComplex + rOutProperties.emplace_back( "CharFontStyleNameComplex", + PROP_CHAR_COMPLEX_FONT_STYLE_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + // CharFontFamilyComplex (see awt.FontFamily) + rOutProperties.emplace_back( "CharFontFamilyComplex", + PROP_CHAR_COMPLEX_FONT_FAMILY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontCharSetComplex (see awt.CharSet) + rOutProperties.emplace_back( "CharFontCharSetComplex", + PROP_CHAR_COMPLEX_CHAR_SET, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharFontPitchComplex (see awt.FontPitch) + rOutProperties.emplace_back( "CharFontPitchComplex", + PROP_CHAR_COMPLEX_FONT_PITCH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharHeightComplex + rOutProperties.emplace_back( "CharHeightComplex", + PROP_CHAR_COMPLEX_CHAR_HEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharWeightComplex + rOutProperties.emplace_back( "CharWeightComplex", + PROP_CHAR_COMPLEX_WEIGHT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharPostureComplex + rOutProperties.emplace_back( "CharPostureComplex", + PROP_CHAR_COMPLEX_POSTURE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + // CharLocaleComplex + rOutProperties.emplace_back( "CharLocaleComplex", + PROP_CHAR_COMPLEX_LOCALE, + cppu::UnoType::get(), + //#i111967# no PropertyChangeEvent is fired on change so far + beans::PropertyAttribute::MAYBEDEFAULT ); + + // Writing Mode left to right vs right to left + rOutProperties.emplace_back( "WritingMode", + PROP_WRITING_MODE, + cppu::UnoType::get(), /*css::text::WritingMode2*/ + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ParaIsCharacterDistance", + PROP_PARA_IS_CHARACTER_DISTANCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void CharacterProperties::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + const float fDefaultFontHeight = 13.0; + + SvtLinguConfig aLinguConfig; + lang::Locale aDefaultLocale; + aLinguConfig.GetProperty(u"DefaultLocale") >>= aDefaultLocale; + lang::Locale aDefaultLocale_CJK; + aLinguConfig.GetProperty(u"DefaultLocale_CJK") >>= aDefaultLocale_CJK; + lang::Locale aDefaultLocale_CTL; + aLinguConfig.GetProperty(u"DefaultLocale_CTL") >>= aDefaultLocale_CTL; + + using namespace ::com::sun::star::i18n::ScriptType; + LanguageType nLang; + nLang = MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType( aDefaultLocale, false), LATIN); + vcl::Font aFont = OutputDevice::GetDefaultFont( DefaultFontType::LATIN_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne ); + nLang = MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType( aDefaultLocale_CJK, false), ASIAN); + vcl::Font aFontCJK = OutputDevice::GetDefaultFont( DefaultFontType::CJK_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne ); + nLang = MsLangId::resolveSystemLanguageByScriptType(LanguageTag::convertToLanguageType( aDefaultLocale_CTL, false), COMPLEX); + vcl::Font aFontCTL = OutputDevice::GetDefaultFont( DefaultFontType::CTL_SPREADSHEET, nLang, GetDefaultFontFlags::OnlyOne ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_FONT_NAME, aFont.GetFamilyName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_FONT_STYLE_NAME, aFont.GetStyleName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_FONT_FAMILY, sal_Int16(aFont.GetFamilyType()) );//awt::FontFamily::SWISS + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_FONT_CHAR_SET, sal_Int16(aFont.GetCharSet()) );//use awt::CharSet::DONTKNOW instead of SYSTEM to avoid assertion issue 50249 + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_FONT_PITCH, sal_Int16(aFont.GetPitch()) );//awt::FontPitch::VARIABLE + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_CHAR_COLOR, -1 ); //automatic color (COL_AUTO) + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_CHAR_HEIGHT, fDefaultFontHeight ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_UNDERLINE, awt::FontUnderline::NONE ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_CHAR_UNDERLINE_COLOR, -1 ); //automatic color (COL_AUTO) + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_UNDERLINE_HAS_COLOR, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_OVERLINE, awt::FontUnderline::NONE ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_CHAR_OVERLINE_COLOR, -1 ); //automatic color (COL_AUTO) + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_OVERLINE_HAS_COLOR, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_WEIGHT, awt::FontWeight::NORMAL ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_POSTURE, awt::FontSlant_NONE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_AUTO_KERNING, true ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_CHAR_KERNING, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_CHAR_STRIKE_OUT, awt::FontStrikeout::NONE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_WORD_MODE, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_LOCALE, aDefaultLocale ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_SHADOWED, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_CONTOURED, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_RELIEF, text::FontRelief::NONE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_EMPHASIS, text::FontEmphasis::NONE ); + + // Asian (com.sun.star.style.CharacterPropertiesAsian) + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultFontHeight ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_WEIGHT, awt::FontWeight::NORMAL ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_POSTURE, awt::FontSlant_NONE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_LOCALE, aDefaultLocale_CJK ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_FONT_NAME, aFontCJK.GetFamilyName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_FONT_STYLE_NAME, aFontCJK.GetStyleName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_FONT_FAMILY, sal_Int16(aFontCJK.GetFamilyType()) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_CHAR_SET, sal_Int16(aFontCJK.GetCharSet()) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_ASIAN_FONT_PITCH, sal_Int16(aFontCJK.GetPitch()) ); + + // Complex Text Layout (com.sun.star.style.CharacterPropertiesComplex) + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultFontHeight ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_WEIGHT, awt::FontWeight::NORMAL ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_POSTURE, awt::FontSlant_NONE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_LOCALE, aDefaultLocale_CTL ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_FONT_NAME, aFontCTL.GetFamilyName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_FONT_STYLE_NAME, aFontCTL.GetStyleName() ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_FONT_FAMILY, sal_Int16(aFontCTL.GetFamilyType()) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_CHAR_SET, sal_Int16(aFontCTL.GetCharSet()) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_CHAR_COMPLEX_FONT_PITCH, sal_Int16(aFontCTL.GetPitch()) ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_WRITING_MODE, sal_Int16( css::text::WritingMode2::PAGE ) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_PARA_IS_CHARACTER_DISTANCE, true ); +} + +bool CharacterProperties::IsCharacterPropertyHandle( sal_Int32 nHandle ) +{ + return ( FAST_PROPERTY_ID_START_CHAR_PROP <= nHandle && + nHandle < CharacterProperties::FAST_PROPERTY_ID_END_CHAR_PROP ); +} + +awt::FontDescriptor CharacterProperties::createFontDescriptorFromPropertySet( + const uno::Reference< beans::XMultiPropertySet > & xMultiPropSet ) +{ + awt::FontDescriptor aResult; + // Note: keep this sorted! + uno::Sequence< OUString > aPropNameSeq{ + "CharFontCharSet", // CharSet + "CharFontFamily", // Family + "CharFontName", // Name + "CharFontPitch", // Pitch + "CharFontStyleName", // StyleName + "CharHeight", // Height + "CharPosture", // Slant + "CharStrikeout", // Strikeout + "CharUnderline", // Underline + "CharWeight", // Weight + "CharWordMode"}; // WordLineMode + uno::Sequence< uno::Any > aValues( xMultiPropSet->getPropertyValues( aPropNameSeq )); + + sal_Int32 i=0; + // Note keep this sorted according to the list above (comments are the fieldnames) + aValues[ i++ ] >>= aResult.CharSet; + aValues[ i++ ] >>= aResult.Family; + aValues[ i++ ] >>= aResult.Name; + aValues[ i++ ] >>= aResult.Pitch; + aValues[ i++ ] >>= aResult.StyleName; + float fCharHeight = 0; + aValues[ i++ ] >>= fCharHeight; + aResult.Height = static_cast< sal_Int16 >( fCharHeight ); + aValues[ i++ ] >>= aResult.Slant; + aValues[ i++ ] >>= aResult.Strikeout; + aValues[ i++ ] >>= aResult.Underline; + aValues[ i++ ] >>= aResult.Weight; + aValues[ i++ ] >>= aResult.WordLineMode; + OSL_ASSERT( i == aValues.getLength()); + + return aResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ChartModelHelper.cxx b/chart2/source/tools/ChartModelHelper.cxx new file mode 100644 index 000000000..16e737b83 --- /dev/null +++ b/chart2/source/tools/ChartModelHelper.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +uno::Reference< chart2::data::XRangeHighlighter > ChartModelHelper::createRangeHighlighter( + const rtl::Reference< ChartModel > & xSelectionSupplier ) +{ + return new RangeHighlighter( xSelectionSupplier ); +} + +rtl::Reference< InternalDataProvider > ChartModelHelper::createInternalDataProvider( + const rtl::Reference<::chart::ChartModel>& xChartDoc, bool bConnectToModel ) +{ + bool bDefaultDataInColumns(true); + + // #i120559# Try to access the current state of "DataRowSource" for the + // chart data and use it as default for creating a new InternalDataProvider + if(xChartDoc.is()) + { + // old XChartDocument interface + css::uno::Reference< css::chart::XChartDocument > xDoc(static_cast(xChartDoc.get()), uno::UNO_QUERY); + + if(xDoc.is()) + { + css::uno::Reference< css::chart::XDiagram > aDiagram = xDoc->getDiagram(); + + if(aDiagram.is()) + { + css::uno::Reference< css::beans::XPropertySet > xProp(aDiagram, uno::UNO_QUERY); + + if(xProp.is()) + { + css::chart::ChartDataRowSource aDataRowSource(css::chart::ChartDataRowSource_COLUMNS); + + xProp->getPropertyValue( "DataRowSource" ) >>= aDataRowSource; + + bDefaultDataInColumns = (aDataRowSource == css::chart::ChartDataRowSource_COLUMNS); + } + } + } + } + + return new InternalDataProvider( xChartDoc, bConnectToModel, bDefaultDataInColumns ); +} + +rtl::Reference< Diagram > ChartModelHelper::findDiagram( const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + try + { + if( !xChartDoc ) + return nullptr; + return xChartDoc->getFirstChartDiagram(); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; +} + +rtl::Reference< BaseCoordinateSystem > ChartModelHelper::getFirstCoordinateSystem( const rtl::Reference<::chart::ChartModel>& xModel ) +{ + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xModel ); + if( xDiagram.is() ) + { + auto& rCooSysSeq( xDiagram->getBaseCoordinateSystems() ); + if( !rCooSysSeq.empty() ) + return rCooSysSeq[0]; + } + return nullptr; +} + +std::vector< rtl::Reference< DataSeries > > ChartModelHelper::getDataSeries( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) +{ + std::vector< rtl::Reference< DataSeries > > aResult; + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDoc ); + if( xDiagram.is()) + aResult = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + return aResult; +} + +rtl::Reference< ChartType > ChartModelHelper::getChartTypeOfSeries( + const rtl::Reference<::chart::ChartModel>& xModel + , const uno::Reference< XDataSeries >& xGivenDataSeries ) +{ + return DiagramHelper::getChartTypeOfSeries( ChartModelHelper::findDiagram( xModel ), xGivenDataSeries ); +} + +rtl::Reference< ChartType > ChartModelHelper::getChartTypeOfSeries( + const rtl::Reference<::chart::ChartModel>& xModel + , const rtl::Reference< DataSeries >& xGivenDataSeries ) +{ + return DiagramHelper::getChartTypeOfSeries( ChartModelHelper::findDiagram( xModel ), xGivenDataSeries ); +} + +awt::Size ChartModelHelper::getDefaultPageSize() +{ + return awt::Size( 16000, 9000 ); +} + +awt::Size ChartModelHelper::getPageSize( const rtl::Reference<::chart::ChartModel>& xModel ) +{ + awt::Size aPageSize( ChartModelHelper::getDefaultPageSize() ); + OSL_ENSURE(xModel.is(),"need xVisualObject for page size"); + if( xModel.is() ) + aPageSize = xModel->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + return aPageSize; +} + +void ChartModelHelper::triggerRangeHighlighting( const rtl::Reference<::chart::ChartModel>& xModel ) +{ + if( xModel.is() ) + { + uno::Reference< view::XSelectionChangeListener > xSelectionChangeListener( xModel->getRangeHighlighter(), uno::UNO_QUERY ); + //trigger selection of cell range + if( xSelectionChangeListener.is() ) + { + lang::EventObject aEvent( xSelectionChangeListener ); + xSelectionChangeListener->selectionChanged( aEvent ); + } + } +} + +bool ChartModelHelper::isIncludeHiddenCells( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + bool bIncluded = true; // hidden cells are included by default. + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram(xChartModel) ); + if (!xDiagram.is()) + return bIncluded; + + try + { + xDiagram->getPropertyValue("IncludeHiddenCells") >>= bIncluded; + } + catch( const beans::UnknownPropertyException& ) + { + } + + return bIncluded; +} + +bool ChartModelHelper::setIncludeHiddenCells( bool bIncludeHiddenCells, ChartModel& rModel ) +{ + bool bChanged = false; + try + { + ControllerLockGuard aLockedControllers( rModel ); + + uno::Reference< beans::XPropertySet > xDiagramProperties( rModel.getFirstDiagram(), uno::UNO_QUERY ); + if (xDiagramProperties.is()) + { + bool bOldValue = bIncludeHiddenCells; + xDiagramProperties->getPropertyValue( "IncludeHiddenCells" ) >>= bOldValue; + if( bOldValue == bIncludeHiddenCells ) + bChanged = true; + + //set the property on all instances in all cases to get the different objects in sync! + + uno::Any aNewValue(bIncludeHiddenCells); + + try + { + uno::Reference< beans::XPropertySet > xDataProviderProperties( rModel.getDataProvider(), uno::UNO_QUERY ); + if( xDataProviderProperties.is() ) + xDataProviderProperties->setPropertyValue("IncludeHiddenCells", aNewValue ); + } + catch( const beans::UnknownPropertyException& ) + { + //the property is optional! + } + + try + { + rtl::Reference< DataSource > xUsedData = DataSourceHelper::getUsedData( rModel ); + if( xUsedData.is() ) + { + uno::Reference< beans::XPropertySet > xProp; + const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xUsedData->getDataSequences()); + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aData ) + { + xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getValues(), uno::UNO_QUERY ) ); + if(xProp.is()) + xProp->setPropertyValue("IncludeHiddenCells", aNewValue ); + xProp.set( uno::Reference< beans::XPropertySet >( labeledData->getLabel(), uno::UNO_QUERY ) ); + if(xProp.is()) + xProp->setPropertyValue("IncludeHiddenCells", aNewValue ); + } + } + } + catch( const beans::UnknownPropertyException& ) + { + //the property is optional! + } + + xDiagramProperties->setPropertyValue( "IncludeHiddenCells", aNewValue); + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return bChanged; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ChartTypeHelper.cxx b/chart2/source/tools/ChartTypeHelper.cxx new file mode 100644 index 000000000..7ea824d56 --- /dev/null +++ b/chart2/source/tools/ChartTypeHelper.cxx @@ -0,0 +1,724 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart +{ + +bool ChartTypeHelper::isSupportingAxisSideBySide( + const rtl::Reference< ::chart::ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + bool bResult = false; + + if( xChartType.is() && + nDimensionCount < 3 ) + { + bool bFound=false; + bool bAmbiguous=false; + StackMode eStackMode = DiagramHelper::getStackModeFromChartType( xChartType, bFound, bAmbiguous, nullptr ); + if( eStackMode == StackMode::NONE && !bAmbiguous ) + { + OUString aChartTypeName = xChartType->getChartType(); + bResult = ( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) ); + } + } + + return bResult; +} + +bool ChartTypeHelper::isSupportingGeometryProperties( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //form tab only for 3D-bar and 3D-column charts. + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_BAR ) + return true; + if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) + return true; + } + } + return false; +} + +bool ChartTypeHelper::isSupportingStatisticProperties( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //3D charts, pie, net and stock do not support statistic properties + + //@todo ask charttype itself (and series? --> stock chart?) --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + return false; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) ) //todo: BubbleChart support error bars and trend lines + return false; + } + return true; +} + +bool ChartTypeHelper::isSupportingRegressionProperties( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + // note: old chart: only scatter chart + return isSupportingStatisticProperties( xChartType, nDimensionCount ); +} + +bool ChartTypeHelper::isSupportingAreaProperties( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //2D line charts, net and stock do not support area properties + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==2) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + return false; + } + } + return true; +} + +bool ChartTypeHelper::isSupportingSymbolProperties( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //2D line charts, 2D scatter charts and 2D net charts do support symbols + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + return false; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) ) + return true; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + return true; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return true; + } + return false; +} + +bool ChartTypeHelper::isSupportingMainAxis( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount, sal_Int32 nDimensionIndex ) +{ + //pie charts do not support axis at all + //no 3rd axis for 2D charts + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + + if( nDimensionIndex == 2 ) + return nDimensionCount == 3; + } + return true; +} + +bool ChartTypeHelper::isSupportingSecondaryAxis( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //3D, pie and net charts do not support a secondary axis at all + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + return false; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + } + return true; +} + +bool ChartTypeHelper::isSupportingOverlapAndGapWidthProperties( + const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //2D bar charts do support a this special properties + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + return false; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) ) + return true; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) ) + return true; + } + return false; +} + +bool ChartTypeHelper::isSupportingBarConnectors( + const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + //2D bar charts with stacked series support this + + //@todo ask charttype itself --> need model change first + if(xChartType.is()) + { + if(nDimensionCount==3) + return false; + + bool bFound=false; + bool bAmbiguous=false; + StackMode eStackMode = DiagramHelper::getStackModeFromChartType( xChartType, bFound, bAmbiguous, nullptr ); + if( eStackMode != StackMode::YStacked || bAmbiguous ) + return false; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) ) + return true; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) ) + return true; // note: old chart was false here + } + return false; +} + +uno::Sequence < sal_Int32 > ChartTypeHelper::getSupportedLabelPlacements( const rtl::Reference< ChartType >& xChartType + , bool bSwapXAndY + , const uno::Reference< chart2::XDataSeries >& xSeries ) +{ + uno::Sequence < sal_Int32 > aRet; + if( !xChartType.is() ) + return aRet; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + { + bool bDonut = false; + xChartType->getPropertyValue( "UseRings") >>= bDonut; + + if(!bDonut) + { + aRet.realloc(5); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::AVOID_OVERLAP; + *pSeq++ = css::chart::DataLabelPlacement::OUTSIDE; + *pSeq++ = css::chart::DataLabelPlacement::INSIDE; + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + *pSeq++ = css::chart::DataLabelPlacement::CUSTOM; + } + else + { + aRet.realloc(1); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + } + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) + ) + { + aRet.realloc(5); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::TOP; + *pSeq++ = css::chart::DataLabelPlacement::BOTTOM; + *pSeq++ = css::chart::DataLabelPlacement::LEFT; + *pSeq++ = css::chart::DataLabelPlacement::RIGHT; + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) ) + { + + bool bStacked = false; + { + uno::Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY ); + chart2::StackingDirection eStacking = chart2::StackingDirection_NO_STACKING; + xSeriesProp->getPropertyValue( "StackingDirection" ) >>= eStacking; + bStacked = (eStacking == chart2::StackingDirection_Y_STACKING); + } + + aRet.realloc( bStacked ? 3 : 6 ); + sal_Int32* pSeq = aRet.getArray(); + if(!bStacked) + { + if(bSwapXAndY) + { + *pSeq++ = css::chart::DataLabelPlacement::RIGHT; + *pSeq++ = css::chart::DataLabelPlacement::LEFT; + } + else + { + *pSeq++ = css::chart::DataLabelPlacement::TOP; + *pSeq++ = css::chart::DataLabelPlacement::BOTTOM; + } + } + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + if(!bStacked) + *pSeq++ = css::chart::DataLabelPlacement::OUTSIDE; + *pSeq++ = css::chart::DataLabelPlacement::INSIDE; + *pSeq++ = css::chart::DataLabelPlacement::NEAR_ORIGIN; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_AREA) ) + { + bool bStacked = false; + { + uno::Reference xSeriesProp(xSeries, uno::UNO_QUERY); + chart2::StackingDirection eStacking = chart2::StackingDirection_NO_STACKING; + xSeriesProp->getPropertyValue("StackingDirection") >>= eStacking; + bStacked = (eStacking == chart2::StackingDirection_Y_STACKING); + } + + aRet.realloc(2); + sal_Int32* pSeq = aRet.getArray(); + if (bStacked) + { + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + *pSeq++ = css::chart::DataLabelPlacement::TOP; + } + else + { + *pSeq++ = css::chart::DataLabelPlacement::TOP; + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + } + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + { + aRet.realloc(6); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::OUTSIDE; + *pSeq++ = css::chart::DataLabelPlacement::TOP; + *pSeq++ = css::chart::DataLabelPlacement::BOTTOM; + *pSeq++ = css::chart::DataLabelPlacement::LEFT; + *pSeq++ = css::chart::DataLabelPlacement::RIGHT; + *pSeq++ = css::chart::DataLabelPlacement::CENTER; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + { + aRet.realloc(1); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::OUTSIDE; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + { + aRet.realloc( 1 ); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::DataLabelPlacement::OUTSIDE; + } + else + { + OSL_FAIL( "unknown charttype" ); + } + + return aRet; +} + +bool ChartTypeHelper::isSupportingRightAngledAxes( const rtl::Reference< ChartType >& xChartType ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + } + return true; +} + +bool ChartTypeHelper::isSupportingStartingAngle( const rtl::Reference< ChartType >& xChartType ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return true; + } + return false; +} +bool ChartTypeHelper::isSupportingBaseValue( const rtl::Reference< ChartType >& xChartType ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_AREA) + ) + return true; + } + return false; +} + +bool ChartTypeHelper::isSupportingAxisPositioning( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount, sal_Int32 nDimensionIndex ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + } + if( nDimensionCount==3 ) + return nDimensionIndex<2; + return true; +} + +bool ChartTypeHelper::isSupportingDateAxis( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionIndex ) +{ + if( nDimensionIndex!=0 ) + return false; + if( xChartType.is() ) + { + sal_Int32 nType = ChartTypeHelper::getAxisType( xChartType, nDimensionIndex ); + if( nType != AxisType::CATEGORY ) + return false; + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + } + return true; +} + +bool ChartTypeHelper::isSupportingComplexCategory( const rtl::Reference< ChartType >& xChartType ) +{ + if( xChartType.is() ) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + } + return true; +} + +bool ChartTypeHelper::isSupportingCategoryPositioning( const rtl::Reference< ChartType >& xChartType, sal_Int32 nDimensionCount ) +{ + if( xChartType.is() ) + { + OUString aChartTypeName = xChartType->getChartType(); + if (aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_AREA) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK)) + return true; + else if (nDimensionCount == 2 && + (aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR))) + return true; + } + return false; +} + +bool ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault( const rtl::Reference< ChartType >& xChartType ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + return true; + } + return false; +} + +bool ChartTypeHelper::noBordersForSimpleScheme( const rtl::Reference< ChartType >& xChartType ) +{ + if(xChartType.is()) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return true; + } + return false; +} + +sal_Int32 ChartTypeHelper::getDefaultDirectLightColor( bool bSimple, const rtl::Reference< ChartType >& xChartType ) +{ + sal_Int32 nRet = static_cast< sal_Int32 >( 0x808080 ); // grey + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + { + if( bSimple ) + nRet = static_cast< sal_Int32 >( 0x333333 ); // grey80 + else + nRet = static_cast< sal_Int32 >( 0xb3b3b3 ); // grey30 + } + else if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_LINE + || aChartType == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ) + nRet = static_cast< sal_Int32 >( 0x666666 ); // grey60 + } + return nRet; +} + +sal_Int32 ChartTypeHelper::getDefaultAmbientLightColor( bool bSimple, const rtl::Reference< ChartType >& xChartType ) +{ + sal_Int32 nRet = static_cast< sal_Int32 >( 0x999999 ); // grey40 + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + { + if( bSimple ) + nRet = static_cast< sal_Int32 >( 0xcccccc ); // grey20 + else + nRet = static_cast< sal_Int32 >( 0x666666 ); // grey60 + } + } + return nRet; +} + +drawing::Direction3D ChartTypeHelper::getDefaultSimpleLightDirection( const rtl::Reference< ChartType >& xChartType ) +{ + drawing::Direction3D aRet(0.0, 0.0, 1.0); + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + aRet = drawing::Direction3D(0.0, 0.8, 0.5); + else if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_LINE + || aChartType == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ) + aRet = drawing::Direction3D(0.9, 0.5, 0.05); + } + return aRet; +} + +drawing::Direction3D ChartTypeHelper::getDefaultRealisticLightDirection( const rtl::Reference< ChartType >& xChartType ) +{ + drawing::Direction3D aRet(0.0, 0.0, 1.0); + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + aRet = drawing::Direction3D(0.6, 0.6, 0.6); + else if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_LINE + || aChartType == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ) + aRet = drawing::Direction3D(0.9, 0.5, 0.05); + } + return aRet; +} + +sal_Int32 ChartTypeHelper::getAxisType( const rtl::Reference< + ChartType >& xChartType, sal_Int32 nDimensionIndex ) +{ + //returned is a constant from constant group css::chart2::AxisType + + //@todo ask charttype itself --> need model change first + if(!xChartType.is()) + return AxisType::CATEGORY; + + OUString aChartTypeName = xChartType->getChartType(); + if(nDimensionIndex==2)//z-axis + return AxisType::SERIES; + if(nDimensionIndex==1)//y-axis + return AxisType::REALNUMBER; + if(nDimensionIndex==0)//x-axis + { + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) ) + return AxisType::REALNUMBER; + return AxisType::CATEGORY; + } + return AxisType::CATEGORY; +} + +sal_Int32 ChartTypeHelper::getNumberOfDisplayedSeries( + const rtl::Reference< ChartType >& xChartType, + sal_Int32 nNumberOfSeries ) +{ + if( xChartType.is() ) + { + try + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + { + bool bDonut = false; + if( (xChartType->getPropertyValue( "UseRings") >>= bDonut) + && !bDonut ) + { + return nNumberOfSeries>0 ? 1 : 0; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return nNumberOfSeries; +} + +uno::Sequence < sal_Int32 > ChartTypeHelper::getSupportedMissingValueTreatments( const rtl::Reference< ChartType >& xChartType ) +{ + uno::Sequence < sal_Int32 > aRet; + if( !xChartType.is() ) + return aRet; + + bool bFound=false; + bool bAmbiguous=false; + StackMode eStackMode = DiagramHelper::getStackModeFromChartType( xChartType, bFound, bAmbiguous, nullptr ); + bool bStacked = bFound && (eStackMode == StackMode::YStacked); + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BAR) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) ) + { + aRet.realloc( 2 ); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::MissingValueTreatment::LEAVE_GAP; + *pSeq++ = css::chart::MissingValueTreatment::USE_ZERO; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_AREA) ) + { + aRet.realloc( bStacked ? 1 : 2 ); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::MissingValueTreatment::USE_ZERO; + if( !bStacked ) + *pSeq++ = css::chart::MissingValueTreatment::CONTINUE; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + { + aRet.realloc( bStacked ? 2 : 3 ); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::MissingValueTreatment::LEAVE_GAP; + *pSeq++ = css::chart::MissingValueTreatment::USE_ZERO; + if( !bStacked ) + *pSeq++ = css::chart::MissingValueTreatment::CONTINUE; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + { + aRet.realloc( 3 ); + sal_Int32* pSeq = aRet.getArray(); + *pSeq++ = css::chart::MissingValueTreatment::CONTINUE; + *pSeq++ = css::chart::MissingValueTreatment::LEAVE_GAP; + *pSeq++ = css::chart::MissingValueTreatment::USE_ZERO; + } + else if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + { + aRet.realloc( 0 ); + } + else + { + OSL_FAIL( "unknown charttype" ); + } + + return aRet; +} + +bool ChartTypeHelper::isSeriesInFrontOfAxisLine( const rtl::Reference< ChartType >& xChartType ) +{ + if( xChartType.is() ) + { + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match( CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET ) ) + return false; + } + return true; +} + +OUString ChartTypeHelper::getRoleOfSequenceForYAxisNumberFormatDetection( const rtl::Reference< ChartType >& xChartType ) +{ + OUString aRet( "values-y" ); + if( !xChartType.is() ) + return aRet; + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + aRet = xChartType->getRoleOfSequenceForSeriesLabel(); + return aRet; +} + +OUString ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( const rtl::Reference< ChartType >& xChartType ) +{ + OUString aRet( "values-y" ); + if( !xChartType.is() ) + return aRet; + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) + || aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) ) + aRet = xChartType->getRoleOfSequenceForSeriesLabel(); + return aRet; +} + +bool ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( const rtl::Reference< ChartType >& xChartType ) +{ + bool bRet = false; + if( !xChartType.is() ) + return bRet; + + OUString aChartTypeName = xChartType->getChartType(); + if( aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_LINE) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) || + aChartTypeName.match(CHART2_SERVICE_NAME_CHARTTYPE_AREA) ) + { + bRet = true; + } + return bRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ChartViewHelper.cxx b/chart2/source/tools/ChartViewHelper.cxx new file mode 100644 index 000000000..8caaeddb1 --- /dev/null +++ b/chart2/source/tools/ChartViewHelper.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +void ChartViewHelper::setViewToDirtyState(const uno::Reference& xChartModel) +{ + try + { + uno::Reference xFact(xChartModel, uno::UNO_QUERY); + if (xFact.is()) + { + Reference xModifyListener( + xFact->createInstance(CHART_VIEW_SERVICE_NAME), uno::UNO_QUERY); + if (xModifyListener.is()) + { + lang::EventObject aEvent(xChartModel); + xModifyListener->modified(aEvent); + } + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ColorPerPointHelper.cxx b/chart2/source/tools/ColorPerPointHelper.cxx new file mode 100644 index 000000000..34aeb7866 --- /dev/null +++ b/chart2/source/tools/ColorPerPointHelper.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +bool ColorPerPointHelper::hasPointOwnColor( + const css::uno::Reference< css::beans::XPropertySet >& xDataSeriesProperties + , sal_Int32 nPointIndex + , const css::uno::Reference< css::beans::XPropertySet >& xDataPointProperties //may be NULL this is just for performance + ) +{ + if( !xDataSeriesProperties.is() ) + return false; + + if( hasPointOwnProperties( xDataSeriesProperties, nPointIndex )) + { + uno::Reference< beans::XPropertyState > xPointState( xDataPointProperties, uno::UNO_QUERY ); + if( !xPointState.is() ) + { + uno::Reference< XDataSeries > xSeries( xDataSeriesProperties, uno::UNO_QUERY ); + if(xSeries.is()) + xPointState.set( xSeries->getDataPointByIndex( nPointIndex ), uno::UNO_QUERY ); + } + if( !xPointState.is() ) + return false; + + return (xPointState->getPropertyState( "Color") != beans::PropertyState_DEFAULT_VALUE ); + } + + return false; +} + +bool ColorPerPointHelper::hasPointOwnProperties( + const css::uno::Reference< css::beans::XPropertySet >& xSeriesProperties + , sal_Int32 nPointIndex ) +{ + if( xSeriesProperties.is() ) + { + uno::Sequence< sal_Int32 > aIndexList; + if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aIndexList ) + { + const sal_Int32 * pBegIt = aIndexList.getConstArray(); + const sal_Int32 * pEndIt = pBegIt + aIndexList.getLength(); + return ( std::find( pBegIt, pEndIt, nPointIndex ) != pEndIt ); + } + } + + return false; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/CommonConverters.cxx b/chart2/source/tools/CommonConverters.cxx new file mode 100644 index 000000000..6e47b5483 --- /dev/null +++ b/chart2/source/tools/CommonConverters.cxx @@ -0,0 +1,600 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; + +// diverse methods for class conversions; e.g. ::basegfx::B3DHomMatrix to HomogenMatrix + +drawing::HomogenMatrix B3DHomMatrixToHomogenMatrix( const ::basegfx::B3DHomMatrix& rM ) +{ + drawing::HomogenMatrix aHM; + aHM.Line1.Column1 = rM.get(0, 0); + aHM.Line1.Column2 = rM.get(0, 1); + aHM.Line1.Column3 = rM.get(0, 2); + aHM.Line1.Column4 = rM.get(0, 3); + aHM.Line2.Column1 = rM.get(1, 0); + aHM.Line2.Column2 = rM.get(1, 1); + aHM.Line2.Column3 = rM.get(1, 2); + aHM.Line2.Column4 = rM.get(1, 3); + aHM.Line3.Column1 = rM.get(2, 0); + aHM.Line3.Column2 = rM.get(2, 1); + aHM.Line3.Column3 = rM.get(2, 2); + aHM.Line3.Column4 = rM.get(2, 3); + aHM.Line4.Column1 = rM.get(3, 0); + aHM.Line4.Column2 = rM.get(3, 1); + aHM.Line4.Column3 = rM.get(3, 2); + aHM.Line4.Column4 = rM.get(3, 3); + return aHM; +} + +::basegfx::B3DHomMatrix HomogenMatrixToB3DHomMatrix( const drawing::HomogenMatrix& rHM ) +{ + ::basegfx::B3DHomMatrix aM; + aM.set(0, 0, rHM.Line1.Column1); + aM.set(0, 1, rHM.Line1.Column2); + aM.set(0, 2, rHM.Line1.Column3); + aM.set(0, 3, rHM.Line1.Column4); + aM.set(1, 0, rHM.Line2.Column1); + aM.set(1, 1, rHM.Line2.Column2); + aM.set(1, 2, rHM.Line2.Column3); + aM.set(1, 3, rHM.Line2.Column4); + aM.set(2, 0, rHM.Line3.Column1); + aM.set(2, 1, rHM.Line3.Column2); + aM.set(2, 2, rHM.Line3.Column3); + aM.set(2, 3, rHM.Line3.Column4); + aM.set(3, 0, rHM.Line4.Column1); + aM.set(3, 1, rHM.Line4.Column2); + aM.set(3, 2, rHM.Line4.Column3); + aM.set(3, 3, rHM.Line4.Column4); + return aM; +} + +::basegfx::B2DHomMatrix IgnoreZ( const ::basegfx::B3DHomMatrix& rM ) +{ + ::basegfx::B2DHomMatrix aM; + aM.set(0, 0, rM.get(0, 0)); + aM.set(0, 1, rM.get(0, 1)); + aM.set(0, 2, rM.get(0, 3)); + aM.set(1, 0, rM.get(1, 0)); + aM.set(1, 1, rM.get(1, 1)); + aM.set(1, 2, rM.get(1, 3)); + aM.set(2, 0, rM.get(3, 0)); + aM.set(2, 1, rM.get(3, 1)); + aM.set(2, 2, rM.get(3, 3)); + return aM; +} + +drawing::HomogenMatrix3 B2DHomMatrixToHomogenMatrix3( const ::basegfx::B2DHomMatrix& rM ) +{ + drawing::HomogenMatrix3 aHM; + aHM.Line1.Column1 = rM.get(0, 0); + aHM.Line1.Column2 = rM.get(0, 1); + aHM.Line1.Column3 = rM.get(0, 2); + aHM.Line2.Column1 = rM.get(1, 0); + aHM.Line2.Column2 = rM.get(1, 1); + aHM.Line2.Column3 = rM.get(1, 2); + aHM.Line3.Column1 = rM.get(2, 0); + aHM.Line3.Column2 = rM.get(2, 1); + aHM.Line3.Column3 = rM.get(2, 2); + return aHM; +} + +::basegfx::B3DPoint Position3DToB3DPoint( const drawing::Position3D& rPosition ) +{ + return ::basegfx::B3DPoint( + rPosition.PositionX , + rPosition.PositionY , + rPosition.PositionZ ); +} + +drawing::Direction3D B3DVectorToDirection3D( const ::basegfx::B3DVector& rVector) +{ + return drawing::Direction3D( + rVector.getX() + , rVector.getY() + , rVector.getZ() + ); +} + +drawing::Position3D B3DPointToPosition3D( const ::basegfx::B3DPoint& rPoint) +{ + return drawing::Position3D( + rPoint.getX() + , rPoint.getY() + , rPoint.getZ() + ); +} + +::basegfx::B3DVector Direction3DToB3DVector( const drawing::Direction3D& rDirection) +{ + return ::basegfx::B3DVector( + rDirection.DirectionX + , rDirection.DirectionY + , rDirection.DirectionZ + ); +} + +void AddPointToPoly( drawing::PolyPolygonShape3D& rPoly, const drawing::Position3D& rPos, sal_Int32 nPolygonIndex ) +{ + if(nPolygonIndex<0) + { + OSL_FAIL( "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); + } + + drawing::DoubleSequence* pOuterSequenceX = &rPoly.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &rPoly.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &rPoly.SequenceZ.getArray()[nPolygonIndex]; + + sal_Int32 nOldPointCount = pOuterSequenceX->getLength(); + + pOuterSequenceX->realloc(nOldPointCount+1); + pOuterSequenceY->realloc(nOldPointCount+1); + pOuterSequenceZ->realloc(nOldPointCount+1); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + pInnerSequenceX[nOldPointCount] = rPos.PositionX; + pInnerSequenceY[nOldPointCount] = rPos.PositionY; + pInnerSequenceZ[nOldPointCount] = rPos.PositionZ; +} + +void AddPointToPoly( std::vector>& rPoly, const drawing::Position3D& rPos, sal_Int32 nPolygonIndex ) +{ + if(nPolygonIndex<0) + { + OSL_FAIL( "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(o3tl::make_unsigned(nPolygonIndex) >= rPoly.size() ) + { + rPoly.resize(nPolygonIndex+1); + } + + std::vector* pOuterSequence = &rPoly[nPolygonIndex]; + pOuterSequence->push_back(rPos); +} + +drawing::Position3D getPointFromPoly( const drawing::PolyPolygonShape3D& rPolygon, sal_Int32 nPointIndex, sal_Int32 nPolyIndex ) +{ + drawing::Position3D aRet(0.0,0.0,0.0); + + if( nPolyIndex>=0 && nPolyIndex>& rPolygon, sal_Int32 nPointIndex, sal_Int32 nPolyIndex ) +{ + drawing::Position3D aRet(0.0,0.0,0.0); + + if( nPolyIndex>=0 && o3tl::make_unsigned(nPolyIndex)(rPolygon[nPolyIndex].size())) + { + aRet = rPolygon[nPolyIndex][nPointIndex]; + } + else + { + OSL_FAIL("polygon was accessed with a wrong index"); + } + } + else + { + OSL_FAIL("polygon was accessed with a wrong index"); + } + return aRet; +} + +void addPolygon( std::vector>& rRet, const std::vector>& rAdd ) +{ + sal_Int32 nAddOuterCount = rAdd.size(); + sal_Int32 nOuterCount = rRet.size() + nAddOuterCount; + rRet.resize( nOuterCount ); + auto pSequence = rRet.data(); + + sal_Int32 nIndex = 0; + sal_Int32 nOuter = nOuterCount - nAddOuterCount; + for( ; nOuter < nOuterCount; nOuter++ ) + { + if( nIndex >= nAddOuterCount ) + break; + + pSequence[nOuter] = rAdd[nIndex]; + + nIndex++; + } +} + +void appendPoly( std::vector>& rRet, const std::vector>& rAdd ) +{ + std::size_t nOuterCount = std::max( rRet.size(), rAdd.size() ); + rRet.resize(nOuterCount); + auto pSequence = rRet.data(); + + for( std::size_t nOuter=0;nOuter0 ) + nRealOuter++; + } + + aRet.SequenceX.realloc( nRealOuter ); + aRet.SequenceY.realloc( nRealOuter ); + aRet.SequenceZ.realloc( nRealOuter ); + + return aRet; +} + +drawing::PointSequenceSequence PolyToPointSequence( + const drawing::PolyPolygonShape3D& rPolyPolygon ) +{ + drawing::PointSequenceSequence aRet; + aRet.realloc( rPolyPolygon.SequenceX.getLength() ); + auto pRet = aRet.getArray(); + + for(sal_Int32 nN = 0; nN < rPolyPolygon.SequenceX.getLength(); nN++) + { + sal_Int32 nInnerLength = rPolyPolygon.SequenceX[nN].getLength(); + pRet[nN].realloc( nInnerLength ); + auto pRet_nN = pRet[nN].getArray(); + for( sal_Int32 nM = 0; nM < nInnerLength; nM++) + { + pRet_nN[nM].X = static_cast(rPolyPolygon.SequenceX[nN][nM]); + pRet_nN[nM].Y = static_cast(rPolyPolygon.SequenceY[nN][nM]); + } + } + return aRet; +} + +drawing::PointSequenceSequence PolyToPointSequence( + const std::vector>& rPolyPolygon ) +{ + drawing::PointSequenceSequence aRet; + aRet.realloc( rPolyPolygon.size() ); + auto pRet = aRet.getArray(); + + for(std::size_t nN = 0; nN < rPolyPolygon.size(); nN++) + { + sal_Int32 nInnerLength = rPolyPolygon[nN].size(); + pRet[nN].realloc( nInnerLength ); + auto pRet_nN = pRet[nN].getArray(); + for( sal_Int32 nM = 0; nM < nInnerLength; nM++) + { + pRet_nN[nM].X = static_cast(rPolyPolygon[nN][nM].PositionX); + pRet_nN[nM].Y = static_cast(rPolyPolygon[nN][nM].PositionY); + } + } + return aRet; +} + +basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( + const std::vector>& rPolyPolygon ) +{ + basegfx::B2DPolyPolygon aRetval; + + for(auto const & nN: rPolyPolygon) + { + basegfx::B2DPolygon aNewPolygon; + sal_Int32 nInnerLength = nN.size(); + if(nInnerLength) + { + aNewPolygon.reserve(nInnerLength); + for( sal_Int32 nM = 0; nM < nInnerLength; nM++) + { + auto X = static_cast(nN[nM].PositionX); + auto Y = static_cast(nN[nM].PositionY); + aNewPolygon.append(basegfx::B2DPoint(X, Y)); + } + // check for closed state flag + basegfx::utils::checkClosed(aNewPolygon); + } + aRetval.append(std::move(aNewPolygon)); + } + + return aRetval; +} + +void appendPointSequence( drawing::PointSequenceSequence& rTarget + , const drawing::PointSequenceSequence& rAdd ) +{ + sal_Int32 nAddCount = rAdd.getLength(); + if(!nAddCount) + return; + sal_Int32 nOldCount = rTarget.getLength(); + + rTarget.realloc(nOldCount+nAddCount); + auto pTarget = rTarget.getArray(); + for(sal_Int32 nS=0; nS(rPos.PositionX); + aRet.Y = static_cast(rPos.PositionY); + return aRet; +} + +awt::Point ToPoint( const awt::Rectangle& rRectangle ) +{ + return awt::Point( rRectangle.X, rRectangle.Y ); +} + +awt::Size ToSize( const awt::Rectangle& rRectangle ) +{ + return awt::Size( rRectangle.Width, rRectangle.Height ); +} + +awt::Size Direction3DToAWTSize( const drawing::Direction3D& rDirection ) +{ + awt::Size aRet; + aRet.Width = static_cast(rDirection.DirectionX); + aRet.Height = static_cast(rDirection.DirectionY); + return aRet; +} + +drawing::Position3D SequenceToPosition3D( const uno::Sequence< double >& rSeq ) +{ + OSL_ENSURE(rSeq.getLength()==3,"The sequence needs to have length 3 for conversion into vector"); + + drawing::Position3D aRet; + aRet.PositionX = rSeq.getLength()>0?rSeq[0]:0.0; + aRet.PositionY = rSeq.getLength()>1?rSeq[1]:0.0; + aRet.PositionZ = rSeq.getLength()>2?rSeq[2]:0.0; + return aRet; +} + +using namespace ::com::sun::star::chart2; + +uno::Sequence< double > DataSequenceToDoubleSequence( + const uno::Reference< data::XDataSequence >& xDataSequence ) +{ + uno::Sequence< double > aResult; + OSL_ASSERT( xDataSequence.is()); + if(!xDataSequence.is()) + return aResult; + + uno::Reference< data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xNumericalDataSequence.is() ) + { + aResult = xNumericalDataSequence->getNumericalData(); + } + else + { + uno::Sequence< uno::Any > aValues = xDataSequence->getData(); + aResult.realloc(aValues.getLength()); + auto pResult = aResult.getArray(); + for(sal_Int32 nN=aValues.getLength();nN--;) + { + if( !(aValues[nN] >>= pResult[nN]) ) + pResult[nN] = std::numeric_limits::quiet_NaN(); + } + } + + return aResult; +} + +uno::Sequence< OUString > DataSequenceToStringSequence( + const uno::Reference< data::XDataSequence >& xDataSequence ) +{ + uno::Sequence< OUString > aResult; + if(!xDataSequence.is()) + return aResult; + + uno::Reference< data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xTextualDataSequence.is() ) + { + aResult = xTextualDataSequence->getTextualData(); + } + else + { + uno::Sequence< uno::Any > aValues = xDataSequence->getData(); + aResult.realloc(aValues.getLength()); + auto pResult = aResult.getArray(); + + for(sal_Int32 nN=aValues.getLength();nN--;) + aValues[nN] >>= pResult[nN]; + } + + return aResult; +} + +bool hasDoubleValue( const uno::Any& rAny ) +{ + bool bRet = false; + double fValue = 0.0; + if( rAny >>= fValue ) + bRet = true; + return bRet; +} + +bool hasLongOrShortValue( const uno::Any& rAny ) +{ + bool bRet = false; + sal_Int32 n32 = 0; + if( rAny >>= n32 ) + bRet = true; + else + { + sal_Int16 n16 = 0; + if( rAny >>= n16 ) + bRet = true; + } + return bRet; +} +sal_Int16 getShortForLongAlso( const uno::Any& rAny ) +{ + sal_Int16 nRet = 0; + + if( !(rAny >>= nRet) ) + { + sal_Int32 n32 = 0; + if( rAny >>= n32 ) + nRet = static_cast(n32); + } + return nRet; +} + +bool replaceParamterInString( OUString & rInOutResourceString, + const OUString & rParamToReplace, + std::u16string_view rReplaceWith ) +{ + sal_Int32 nPos = rInOutResourceString.indexOf( rParamToReplace ); + if( nPos == -1 ) + return false; + + rInOutResourceString = rInOutResourceString.replaceAt( nPos + , rParamToReplace.getLength(), rReplaceWith ); + return true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ConfigColorScheme.cxx b/chart2/source/tools/ConfigColorScheme.cxx new file mode 100644 index 000000000..f6bbfe232 --- /dev/null +++ b/chart2/source/tools/ConfigColorScheme.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +constexpr OUStringLiteral aSeriesPropName = u"Series"; + +} // anonymous namespace + +namespace chart +{ + +uno::Reference< chart2::XColorScheme > createConfigColorScheme( const uno::Reference< uno::XComponentContext > & xContext ) +{ + return new ConfigColorScheme( xContext ); +} + +namespace impl +{ +class ChartConfigItem : public ::utl::ConfigItem +{ +public: + explicit ChartConfigItem( ConfigColorScheme & rListener ); + + void addPropertyNotification( const OUString & rPropertyName ); + uno::Any getProperty( const OUString & aPropertyName ); + +protected: + // ____ ::utl::ConfigItem ____ + virtual void ImplCommit() override; + virtual void Notify( const Sequence< OUString > & aPropertyNames ) override; + +private: + ConfigColorScheme & m_rListener; + std::set< OUString > m_aPropertiesToNotify; +}; + +ChartConfigItem::ChartConfigItem( ConfigColorScheme & rListener ) : + ::utl::ConfigItem( "Office.Chart/DefaultColor" ), + m_rListener( rListener ) +{} + +void ChartConfigItem::Notify( const Sequence< OUString > & aPropertyNames ) +{ + for( OUString const & s : aPropertyNames ) + { + if( m_aPropertiesToNotify.find( s ) != m_aPropertiesToNotify.end()) + m_rListener.notify( s ); + } +} + +void ChartConfigItem::ImplCommit() +{} + +void ChartConfigItem::addPropertyNotification( const OUString & rPropertyName ) +{ + m_aPropertiesToNotify.insert( rPropertyName ); + EnableNotification( comphelper::containerToSequence( m_aPropertiesToNotify )); +} + +uno::Any ChartConfigItem::getProperty( const OUString & aPropertyName ) +{ + Sequence< uno::Any > aValues( + GetProperties( Sequence< OUString >( &aPropertyName, 1 ))); + if( ! aValues.hasElements()) + return uno::Any(); + return aValues[0]; +} + +} // namespace impl + +// explicit +ConfigColorScheme::ConfigColorScheme( + const Reference< uno::XComponentContext > & xContext ) : + m_xContext( xContext ), + m_nNumberOfColors( 0 ), + m_bNeedsUpdate( true ) +{ +} + +ConfigColorScheme::~ConfigColorScheme() +{} + +void ConfigColorScheme::retrieveConfigColors() +{ + if( ! m_xContext.is()) + return; + + // create config item if necessary + if (!m_apChartConfigItem) + { + m_apChartConfigItem.reset( + new impl::ChartConfigItem( *this )); + m_apChartConfigItem->addPropertyNotification( aSeriesPropName ); + } + assert(m_apChartConfigItem && "this can only be set at this point"); + + // retrieve colors + uno::Any aValue( + m_apChartConfigItem->getProperty( aSeriesPropName )); + if( aValue >>= m_aColorSequence ) + m_nNumberOfColors = m_aColorSequence.getLength(); + m_bNeedsUpdate = false; +} + +// ____ XColorScheme ____ +::sal_Int32 SAL_CALL ConfigColorScheme::getColorByIndex( ::sal_Int32 nIndex ) +{ + if( m_bNeedsUpdate ) + retrieveConfigColors(); + + if( m_nNumberOfColors > 0 ) + return static_cast< sal_Int32 >( m_aColorSequence[ nIndex % m_nNumberOfColors ] ); + + // fall-back: hard-coded standard colors + static const sal_Int32 nDefaultColors[] = { + 0x9999ff, 0x993366, 0xffffcc, + 0xccffff, 0x660066, 0xff8080, + 0x0066cc, 0xccccff, 0x000080, + 0xff00ff, 0x00ffff, 0xffff00 + }; + + static const sal_Int32 nMaxDefaultColors = std::size( nDefaultColors ); + return nDefaultColors[ nIndex % nMaxDefaultColors ]; +} + +void ConfigColorScheme::notify( std::u16string_view rPropertyName ) +{ + if( rPropertyName == aSeriesPropName ) + m_bNeedsUpdate = true; +} + +OUString SAL_CALL ConfigColorScheme::getImplementationName() +{ + return "com.sun.star.comp.chart2.ConfigDefaultColorScheme" ; +} + +sal_Bool SAL_CALL ConfigColorScheme::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ConfigColorScheme::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.ColorScheme" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ConfigDefaultColorScheme_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ConfigColorScheme(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ControllerLockGuard.cxx b/chart2/source/tools/ControllerLockGuard.cxx new file mode 100644 index 000000000..9ae942a5a --- /dev/null +++ b/chart2/source/tools/ControllerLockGuard.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +ControllerLockGuardUNO::ControllerLockGuardUNO( const rtl::Reference<::chart::ChartModel>& xModel ) : + mxModel( xModel ) +{ + mxModel->lockControllers(); +} + +ControllerLockGuardUNO::~ControllerLockGuardUNO() +{ + mxModel->unlockControllers(); +} + +ControllerLockGuard::ControllerLockGuard( ChartModel& rModel ) : + mrModel( rModel ) +{ + mrModel.lockControllers(); +} + +ControllerLockGuard::~ControllerLockGuard() +{ + mrModel.unlockControllers(); +} + +ControllerLockHelper::ControllerLockHelper( const rtl::Reference<::chart::ChartModel> & xModel ) : + m_xModel( xModel ) +{} + +ControllerLockHelper::~ControllerLockHelper() +{} + +void ControllerLockHelper::lockControllers() +{ + if( m_xModel.is()) + m_xModel->lockControllers(); +} + +void ControllerLockHelper::unlockControllers() +{ + if( m_xModel.is()) + m_xModel->unlockControllers(); +} + +ControllerLockHelperGuard::ControllerLockHelperGuard( ControllerLockHelper & rHelper ) : + m_rHelper( rHelper ) +{ + m_rHelper.lockControllers(); +} + +ControllerLockHelperGuard::~ControllerLockHelperGuard() +{ + m_rHelper.unlockControllers(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/DataSeriesHelper.cxx b/chart2/source/tools/DataSeriesHelper.cxx new file mode 100644 index 000000000..a4b4dec45 --- /dev/null +++ b/chart2/source/tools/DataSeriesHelper.cxx @@ -0,0 +1,884 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +class lcl_MatchesRole +{ +public: + explicit lcl_MatchesRole( const OUString & aRole, bool bMatchPrefix ) : + m_aRole( aRole ), + m_bMatchPrefix( bMatchPrefix ) + {} + + bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const + { + if(!xSeq.is()) + return false; + Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY ); + OUString aRole; + + if( m_bMatchPrefix ) + return ( xProp.is() && + (xProp->getPropertyValue( "Role" ) >>= aRole ) && + aRole.match( m_aRole )); + + return ( xProp.is() && + (xProp->getPropertyValue( "Role" ) >>= aRole ) && + m_aRole == aRole ); + } + +private: + OUString m_aRole; + bool m_bMatchPrefix; +}; + +Reference< chart2::data::XLabeledDataSequence > lcl_findLSequenceWithOnlyLabel( + const Reference< chart2::data::XDataSource > & xDataSource ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences()); + + for( auto const & labeledData : aSequences ) + { + OSL_ENSURE( labeledData.is(), "empty LabeledDataSequence" ); + // no values are set but a label exists + if( labeledData.is() && + ( ! labeledData->getValues().is() && + labeledData->getLabel().is())) + { + xResult.set( labeledData ); + break; + } + } + + return xResult; +} + +void lcl_getCooSysAndChartTypeOfSeries( + const rtl::Reference< ::chart::DataSeries > & xSeries, + const Reference< chart2::XDiagram > & xDiagram, + rtl::Reference< ::chart::BaseCoordinateSystem > & xOutCooSys, + rtl::Reference< ::chart::ChartType > & xOutChartType ) +{ + if( !xDiagram.is()) + return; + ::chart::Diagram* pDiagram = dynamic_cast<::chart::Diagram*>(xDiagram.get()); + + for( rtl::Reference< ::chart::BaseCoordinateSystem > const & coords : pDiagram->getBaseCoordinateSystems() ) + { + for( rtl::Reference< ::chart::ChartType > const & chartType : coords->getChartTypes2() ) + { + for( rtl::Reference< ::chart::DataSeries > const & dataSeries : chartType->getDataSeries2() ) + { + if( dataSeries == xSeries ) + { + xOutCooSys = coords; + xOutChartType = chartType; + } + } + } + } +} + +void lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries, bool bInsert ) +{ + try + { + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + DataPointLabel aLabelAtSeries; + xSeriesProperties->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabelAtSeries; + aLabelAtSeries.ShowNumber = bInsert; + if( !bInsert ) + { + aLabelAtSeries.ShowNumberInPercent = false; + aLabelAtSeries.ShowCategoryName = false; + } + xSeriesProperties->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabelAtSeries)); + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel; + aLabel.ShowNumber = bInsert; + if( !bInsert ) + { + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + aLabel.ShowCustomLabel = false; + aLabel.ShowSeriesName = false; + } + xPointProp->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + xPointProp->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + } + } + } + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} // anonymous namespace + +namespace chart::DataSeriesHelper +{ + +OUString getRole( const uno::Reference< chart2::data::XLabeledDataSequence >& xLabeledDataSequence ) +{ + OUString aRet; + if( xLabeledDataSequence.is() ) + { + Reference< beans::XPropertySet > xProp( xLabeledDataSequence->getValues(), uno::UNO_QUERY ); + if( xProp.is() ) + xProp->getPropertyValue( "Role" ) >>= aRet; + } + return aRet; +} + +uno::Reference< chart2::data::XLabeledDataSequence > + getDataSequenceByRole( + const Reference< chart2::data::XDataSource > & xSource, + const OUString& aRole, + bool bMatchPrefix /* = false */ ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > aNoResult; + if( ! xSource.is()) + return aNoResult; + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( xSource->getDataSequences()); + for (auto const & i : aLabeledSeq) + { + if (lcl_MatchesRole(aRole, bMatchPrefix)(i)) + return i; + } + + return aNoResult; +} + +std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > + getAllDataSequencesByRole( const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aDataSequences, + const OUString& aRole ) +{ + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aResultVec; + for (const auto & i : aDataSequences) + { + if (lcl_MatchesRole(aRole, /*bMatchPrefix*/true)(i)) + aResultVec.push_back(i); + } + return aResultVec; +} + +std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + getAllDataSequencesByRole( const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSequences, + const OUString& aRole ) +{ + std::vector< css::uno::Reference< css::chart2::data::XLabeledDataSequence > > aResultVec; + std::copy_if( aDataSequences.begin(), aDataSequences.end(), + std::back_inserter( aResultVec ), + lcl_MatchesRole(aRole, /*bMatchPrefix*/true) ); + return aResultVec; +} + +std::vector > +getAllDataSequences( const uno::Sequence >& aSeries ) +{ + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVec; + + for( uno::Reference const & dataSeries : aSeries ) + { + Reference< chart2::data::XDataSource > xSource( dataSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + for (const auto & i : aSeq) + { + aSeqVec.push_back(i); + } + } + } + + return aSeqVec; +} + +std::vector > +getAllDataSequences( const std::vector >& aSeries ) +{ + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVec; + + for( rtl::Reference const & dataSeries : aSeries ) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aSeq( dataSeries->getDataSequences2()); + aSeqVec.insert( aSeqVec.end(), aSeq.begin(), aSeq.end() ); + } + + return aSeqVec; +} + +rtl::Reference< DataSource > + getDataSource( const std::vector< rtl::Reference< DataSeries > > & aSeries ) +{ + return new DataSource(getAllDataSequences(aSeries)); +} + +namespace +{ +OUString lcl_getDataSequenceLabel( const Reference< chart2::data::XDataSequence > & xSequence ) +{ + OUString aResult; + + Reference< chart2::data::XTextualDataSequence > xTextSeq( xSequence, uno::UNO_QUERY ); + if( xTextSeq.is()) + { + Sequence< OUString > aSeq( xTextSeq->getTextualData()); + + const sal_Int32 nMax = aSeq.getLength() - 1; + OUStringBuffer aBuf; + + for( sal_Int32 i = 0; i <= nMax; ++i ) + { + aBuf.append( aSeq[i] ); + if( i < nMax ) + aBuf.append( ' '); + } + aResult = aBuf.makeStringAndClear(); + } + else if( xSequence.is()) + { + Sequence< uno::Any > aSeq( xSequence->getData()); + + const sal_Int32 nMax = aSeq.getLength() - 1; + OUString aVal; + OUStringBuffer aBuf; + double fNum = 0; + + for( sal_Int32 i = 0; i <= nMax; ++i ) + { + if( aSeq[i] >>= aVal ) + { + aBuf.append( aVal ); + if( i < nMax ) + aBuf.append( ' '); + } + else if( aSeq[ i ] >>= fNum ) + { + aBuf.append( fNum ); + if( i < nMax ) + aBuf.append( ' '); + } + } + aResult = aBuf.makeStringAndClear(); + } + + return aResult; +} +} + +OUString getLabelForLabeledDataSequence( + const Reference< chart2::data::XLabeledDataSequence > & xLabeledSeq ) +{ + OUString aResult; + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is() ) + aResult = lcl_getDataSequenceLabel( xSeq ); + if( !xSeq.is() || aResult.isEmpty() ) + { + // no label set or label content is empty -> use auto-generated one + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() ); + if( xValueSeq.is() ) + { + Sequence< OUString > aLabels( xValueSeq->generateLabel( + chart2::data::LabelOrigin_SHORT_SIDE ) ); + // no labels returned is interpreted as: auto-generation not + // supported by sequence + if( aLabels.hasElements() ) + aResult=aLabels[0]; + else + { + //todo?: maybe use the index of the series as name + //but as the index may change it would be better to have such a name persistent + //what is not possible at the moment + //--> maybe use the identifier as part of the name ... + aResult = lcl_getDataSequenceLabel( xValueSeq ); + } + } + } + } + return aResult; +} + +OUString getDataSeriesLabel( + const rtl::Reference< DataSeries > & xSeries, + const OUString & rLabelSequenceRole ) +{ + OUString aResult; + + if( xSeries.is()) + { + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + ::chart::DataSeriesHelper::getDataSequenceByRole( xSeries, rLabelSequenceRole )); + if( xLabeledSeq.is()) + aResult = getLabelForLabeledDataSequence( xLabeledSeq ); + else + { + // special case: labeled data series with only a label and no values may + // serve as label + xLabeledSeq.set( lcl_findLSequenceWithOnlyLabel( xSeries )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is()) + aResult = lcl_getDataSequenceLabel( xSeq ); + } + } + + } + + return aResult; +} + +void setStackModeAtSeries( + const std::vector< rtl::Reference< DataSeries > > & aSeries, + const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem, + StackMode eStackMode ) +{ + const uno::Any aPropValue( + ( (eStackMode == StackMode::YStacked) || + (eStackMode == StackMode::YStackedPercent) ) + ? chart2::StackingDirection_Y_STACKING + : (eStackMode == StackMode::ZStacked ) + ? chart2::StackingDirection_Z_STACKING + : chart2::StackingDirection_NO_STACKING ); + + std::set< sal_Int32 > aAxisIndexSet; + for( rtl::Reference< DataSeries > const & dataSeries : aSeries ) + { + try + { + if( dataSeries.is() ) + { + dataSeries->setPropertyValue( "StackingDirection", aPropValue ); + + sal_Int32 nAxisIndex; + dataSeries->getPropertyValue( "AttachedAxisIndex" ) >>= nAxisIndex; + aAxisIndexSet.insert(nAxisIndex); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( !(xCorrespondingCoordinateSystem.is() && + 1 < xCorrespondingCoordinateSystem->getDimension()) ) + return; + + if( aAxisIndexSet.empty() ) + { + aAxisIndexSet.insert(0); + } + + for (auto const& axisIndex : aAxisIndexSet) + { + rtl::Reference< Axis > xAxis = + xCorrespondingCoordinateSystem->getAxisByDimension2(1, axisIndex); + if( xAxis.is()) + { + bool bPercent = (eStackMode == StackMode::YStackedPercent); + chart2::ScaleData aScaleData = xAxis->getScaleData(); + + if( bPercent != (aScaleData.AxisType==chart2::AxisType::PERCENT) ) + { + if( bPercent ) + aScaleData.AxisType = chart2::AxisType::PERCENT; + else + aScaleData.AxisType = chart2::AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } +} + +sal_Int32 getAttachedAxisIndex( const Reference< chart2::XDataSeries > & xSeries ) +{ + sal_Int32 nRet = 0; + try + { + Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY ); + if( xProp.is() ) + { + xProp->getPropertyValue( "AttachedAxisIndex" ) >>= nRet; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nRet; +} + +sal_Int32 getNumberFormatKeyFromAxis( + const Reference< chart2::XDataSeries > & xSeries, + const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem, + sal_Int32 nDimensionIndex, + sal_Int32 nAxisIndex /* = -1 */ ) +{ + sal_Int32 nResult = 0; + if( nAxisIndex == -1 ) + nAxisIndex = getAttachedAxisIndex( xSeries ); + try + { + rtl::Reference< Axis > xAxisProp = + xCorrespondingCoordinateSystem->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + if( xAxisProp.is()) + xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nResult; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nResult; +} + +rtl::Reference< ::chart::BaseCoordinateSystem > getCoordinateSystemOfSeries( + const Reference< chart2::XDataSeries > & xSeries, + const rtl::Reference< Diagram > & xDiagram ) +{ + rtl::Reference< ::chart::BaseCoordinateSystem > xResult; + rtl::Reference< ::chart::ChartType > xDummy; + rtl::Reference< DataSeries> pSeries = dynamic_cast(xSeries.get()); + assert(pSeries); + lcl_getCooSysAndChartTypeOfSeries( pSeries, xDiagram, xResult, xDummy ); + + return xResult; +} + +rtl::Reference< ::chart::ChartType > getChartTypeOfSeries( + const Reference< chart2::XDataSeries > & xSeries, + const rtl::Reference< Diagram > & xDiagram ) +{ + rtl::Reference< ::chart::ChartType > xResult; + rtl::Reference< ::chart::BaseCoordinateSystem > xDummy; + rtl::Reference< DataSeries> pSeries = dynamic_cast(xSeries.get()); + assert(pSeries); + lcl_getCooSysAndChartTypeOfSeries( pSeries, xDiagram, xDummy, xResult ); + + return xResult; +} + +void deleteSeries( + const Reference< chart2::XDataSeries > & xSeries, + const rtl::Reference< ::chart::ChartType > & xChartType ) +{ + try + { + rtl::Reference pSeries = dynamic_cast(xSeries.get()); + assert(pSeries); + std::vector< rtl::Reference< DataSeries > > aSeries = xChartType->getDataSeries2(); + auto aIt = std::find( aSeries.begin(), aSeries.end(), pSeries ); + if( aIt != aSeries.end()) + { + aSeries.erase( aIt ); + xChartType->setDataSeries( aSeries ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void switchSymbolsOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties, + bool bSymbolsOn, sal_Int32 nSeriesIndex ) +{ + if( !xSeriesProperties.is() ) + return; + + chart2::Symbol aSymbProp; + if( xSeriesProperties->getPropertyValue( "Symbol") >>= aSymbProp ) + { + if( !bSymbolsOn ) + aSymbProp.Style = chart2::SymbolStyle_NONE; + else if( aSymbProp.Style == chart2::SymbolStyle_NONE ) + { + aSymbProp.Style = chart2::SymbolStyle_STANDARD; + aSymbProp.StandardSymbol = nSeriesIndex; + } + xSeriesProperties->setPropertyValue( "Symbol", uno::Any( aSymbProp )); + } + //todo: check attributed data points +} + +void switchLinesOnOrOff( const Reference< beans::XPropertySet > & xSeriesProperties, bool bLinesOn ) +{ + if( !xSeriesProperties.is() ) + return; + + if( bLinesOn ) + { + // keep line-styles that are not NONE + drawing::LineStyle eLineStyle; + if( (xSeriesProperties->getPropertyValue( "LineStyle") >>= eLineStyle ) && + eLineStyle == drawing::LineStyle_NONE ) + { + xSeriesProperties->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + } + } + else + xSeriesProperties->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); +} + +void makeLinesThickOrThin( const Reference< beans::XPropertySet > & xSeriesProperties, bool bThick ) +{ + if( !xSeriesProperties.is() ) + return; + + sal_Int32 nNewValue = bThick ? 80 : 0; + sal_Int32 nOldValue = 0; + if( (xSeriesProperties->getPropertyValue( "LineWidth") >>= nOldValue ) && + nOldValue != nNewValue ) + { + if( !(bThick && nOldValue>0)) + xSeriesProperties->setPropertyValue( "LineWidth", uno::Any( nNewValue ) ); + } +} + +void setPropertyAlsoToAllAttributedDataPoints( const Reference< chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, const uno::Any& rPropertyValue ) +{ + rtl::Reference pSeries = dynamic_cast(xSeries.get()); + assert(!xSeries || pSeries); + setPropertyAlsoToAllAttributedDataPoints(pSeries, rPropertyName, rPropertyValue); +} + +void setPropertyAlsoToAllAttributedDataPoints( const rtl::Reference< ::chart::DataSeries >& xSeries, + const OUString& rPropertyName, const uno::Any& rPropertyValue ) +{ + if( !xSeries.is() ) + return; + + xSeries->setPropertyValue( rPropertyName, rPropertyValue ); + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeries->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if(!xPointProp.is()) + continue; + xPointProp->setPropertyValue( rPropertyName, rPropertyValue ); + if( rPropertyName == "LabelPlacement" ) + xPointProp->setPropertyValue("CustomLabelPosition", uno::Any()); + } + } +} + +bool hasAttributedDataPointDifferentValue( const Reference< chart2::XDataSeries >& xSeries, + const OUString& rPropertyName, const uno::Any& rPropertyValue ) +{ + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( !xSeriesProperties.is() ) + return false; + + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if(!xPointProp.is()) + continue; + uno::Any aPointValue( xPointProp->getPropertyValue( rPropertyName ) ); + if( rPropertyValue != aPointValue ) + return true; + } + } + return false; +} + +namespace +{ + +bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + if( !xDataSequence.is() ) + return false; + uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Sequence< sal_Int32 > aHiddenValues; + try + { + xProp->getPropertyValue( "HiddenValues" ) >>= aHiddenValues; + if( !aHiddenValues.hasElements() ) + return true; + } + catch( const uno::Exception& ) + { + return true; + } + } + return xDataSequence->getData().hasElements(); +} + +} + +bool hasUnhiddenData( const uno::Reference< chart2::XDataSeries >& xSeries ) +{ + uno::Reference< chart2::data::XDataSource > xDataSource( xSeries, uno::UNO_QUERY ); + + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aDataSequences = xDataSource->getDataSequences(); + + for(sal_Int32 nN = aDataSequences.getLength();nN--;) + { + if( !aDataSequences[nN].is() ) + continue; + if( lcl_SequenceHasUnhiddenData( aDataSequences[nN]->getValues() ) ) + return true; + } + return false; +} + +sal_Int32 translateIndexFromHiddenToFullSequence( sal_Int32 nIndex, const Reference< chart2::data::XDataSequence >& xDataSequence, bool bTranslate ) +{ + if( !bTranslate ) + return nIndex; + + try + { + uno::Reference xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + Sequence aHiddenIndicesSeq; + xProp->getPropertyValue( "HiddenValues" ) >>= aHiddenIndicesSeq; + if( aHiddenIndicesSeq.hasElements() ) + { + auto aHiddenIndices( comphelper::sequenceToContainer>( aHiddenIndicesSeq ) ); + std::sort( aHiddenIndices.begin(), aHiddenIndices.end() ); + + sal_Int32 nHiddenCount = static_cast(aHiddenIndices.size()); + for( sal_Int32 nN = 0; nN < nHiddenCount; ++nN) + { + if( aHiddenIndices[nN] <= nIndex ) + nIndex += 1; + else + break; + } + } + } + } + catch (const beans::UnknownPropertyException&) + { + } + return nIndex; +} + +bool hasDataLabelsAtSeries( const Reference< chart2::XDataSeries >& xSeries ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY ); + if( xProp.is() ) + { + DataPointLabel aLabel; + if( xProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent || aLabel.ShowCategoryName + || aLabel.ShowSeriesName; + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return bRet; +} + +bool hasDataLabelsAtPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + Reference< beans::XPropertySet > xPointProp( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]) ); + if( xPointProp.is() ) + { + DataPointLabel aLabel; + if( xPointProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent + || aLabel.ShowCategoryName || aLabel.ShowCustomLabel + || aLabel.ShowSeriesName; + if( bRet ) + break; + } + } + } + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return bRet; +} + +bool hasDataLabelAtPoint( const Reference< chart2::XDataSeries >& xSeries, sal_Int32 nPointIndex ) +{ + bool bRet = false; + try + { + Reference< beans::XPropertySet > xProp; + Reference< beans::XPropertySet > xSeriesProperties( xSeries, uno::UNO_QUERY ); + if( xSeriesProperties.is() ) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProperties->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + auto aIt = std::find( std::as_const(aAttributedDataPointIndexList).begin(), std::as_const(aAttributedDataPointIndexList).end(), nPointIndex ); + if( aIt != std::as_const(aAttributedDataPointIndexList).end()) + xProp = xSeries->getDataPointByIndex(nPointIndex); + else + xProp = xSeriesProperties; + } + if( xProp.is() ) + { + DataPointLabel aLabel; + if( xProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel ) + bRet = aLabel.ShowNumber || aLabel.ShowNumberInPercent + || aLabel.ShowCategoryName || aLabel.ShowCustomLabel + || aLabel.ShowSeriesName; + } + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return bRet; +} + +void insertDataLabelsToSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, true /*bInsert*/ ); +} + +void deleteDataLabelsFromSeriesAndAllPoints( const Reference< chart2::XDataSeries >& xSeries ) +{ + lcl_insertOrDeleteDataLabelsToSeriesAndAllPoints( xSeries, false /*bInsert*/ ); +} + +void insertDataLabelToPoint( const Reference< beans::XPropertySet >& xPointProp ) +{ + try + { + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel; + aLabel.ShowNumber = true; + xPointProp->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void deleteDataLabelsFromPoint( const Reference< beans::XPropertySet >& xPointProp ) +{ + try + { + if( xPointProp.is() ) + { + DataPointLabel aLabel; + xPointProp->getPropertyValue(CHART_UNONAME_LABEL) >>= aLabel; + aLabel.ShowNumber = false; + aLabel.ShowNumberInPercent = false; + aLabel.ShowCategoryName = false; + aLabel.ShowCustomLabel = false; + aLabel.ShowSeriesName = false; + xPointProp->setPropertyValue(CHART_UNONAME_LABEL, uno::Any(aLabel)); + xPointProp->setPropertyValue(CHART_UNONAME_CUSTOM_LABEL_FIELDS, uno::Any()); + } + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/DataSource.cxx b/chart2/source/tools/DataSource.cxx new file mode 100644 index 000000000..c74687c14 --- /dev/null +++ b/chart2/source/tools/DataSource.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +using namespace ::com::sun::star; + + +namespace chart +{ + +DataSource::DataSource() +{} + +DataSource::DataSource( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & rSequences ) : + m_aDataSeq( rSequences ) +{} + +DataSource::DataSource( + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & rSequences ) +{ + m_aDataSeq = comphelper::containerToSequence< Reference< chart2::data::XLabeledDataSequence > >(rSequences); +} + +DataSource::~DataSource() +{} + +// ____ XDataSource ____ +Sequence< Reference< chart2::data::XLabeledDataSequence > > SAL_CALL DataSource::getDataSequences() +{ + return m_aDataSeq; +} + +// ____ XDataSink ____ +void SAL_CALL DataSource::setData( const Sequence< Reference< chart2::data::XLabeledDataSequence > >& aData ) +{ + m_aDataSeq = aData; +} + +OUString SAL_CALL DataSource::getImplementationName() +{ + return "com.sun.star.comp.chart.DataSource"; +} + +sal_Bool SAL_CALL DataSource::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DataSource::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.data.DataSource" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_DataSource_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::DataSource); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/DataSourceHelper.cxx b/chart2/source/tools/DataSourceHelper.cxx new file mode 100644 index 000000000..8e8dd2f3a --- /dev/null +++ b/chart2/source/tools/DataSourceHelper.cxx @@ -0,0 +1,471 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +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; + +namespace +{ +void lcl_addRanges( std::vector< OUString > & rOutResult, + const uno::Reference< data::XLabeledDataSequence > & xLabeledSeq ) +{ + if( ! xLabeledSeq.is()) + return; + uno::Reference< data::XDataSequence > xSeq( xLabeledSeq->getLabel()); + if( xSeq.is()) + rOutResult.push_back( xSeq->getSourceRangeRepresentation()); + xSeq.set( xLabeledSeq->getValues()); + if( xSeq.is()) + rOutResult.push_back( xSeq->getSourceRangeRepresentation()); +} + +void lcl_addDataSourceRanges( + std::vector< OUString > & rOutResult, + const uno::Reference< data::XDataSource > & xDataSource ) +{ + if( xDataSource.is() ) + { + const auto aDataSequences(xDataSource->getDataSequences()); + for (const auto& rDataSequence : aDataSequences) + lcl_addRanges(rOutResult, rDataSequence); + } +} + +void lcl_addErrorBarRanges( + std::vector< OUString > & rOutResult, + const rtl::Reference< DataSeries > & xDataSeries ) +{ + if( !xDataSeries.is()) + return; + + try + { + uno::Reference< beans::XPropertySet > xErrorBarProp; + if( ( xDataSeries->getPropertyValue( CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp ) && + xErrorBarProp.is()) + { + sal_Int32 eStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue( "ErrorBarStyle") >>= eStyle ) && + eStyle == css::chart::ErrorBarStyle::FROM_DATA ) + { + uno::Reference< data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY ); + if( xErrorBarDataSource.is() ) + lcl_addDataSourceRanges( rOutResult, xErrorBarDataSource ); + } + } + + if( ( xDataSeries->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp ) && xErrorBarProp.is()) + { + sal_Int32 eStyle = css::chart::ErrorBarStyle::NONE; + if( ( xErrorBarProp->getPropertyValue("ErrorBarStyle") >>= eStyle ) && + eStyle == css::chart::ErrorBarStyle::FROM_DATA ) + { + uno::Reference< data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY ); + if( xErrorBarDataSource.is() ) + lcl_addDataSourceRanges( rOutResult, xErrorBarDataSource ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +Reference< chart2::data::XDataSequence > DataSourceHelper::createCachedDataSequence() +{ + return new ::chart::CachedDataSequence(); +} + +Reference< chart2::data::XDataSequence > DataSourceHelper::createCachedDataSequence( const OUString& rSingleText ) +{ + return new ::chart::CachedDataSequence( rSingleText ); +} + +rtl::Reference< LabeledDataSequence > DataSourceHelper::createLabeledDataSequence( + const Reference< chart2::data::XDataSequence >& xValues , + const Reference< chart2::data::XDataSequence >& xLabels ) +{ + return new ::chart::LabeledDataSequence( xValues, xLabels ); +} + +rtl::Reference< LabeledDataSequence > DataSourceHelper::createLabeledDataSequence( + const Reference< chart2::data::XDataSequence >& xValues ) +{ + return new ::chart::LabeledDataSequence( xValues ); +} + +rtl::Reference< LabeledDataSequence > DataSourceHelper::createLabeledDataSequence() +{ + return new ::chart::LabeledDataSequence; +} + +uno::Sequence< beans::PropertyValue > DataSourceHelper::createArguments( + bool bUseColumns, bool bFirstCellAsLabel, bool bHasCategories ) +{ + css::chart::ChartDataRowSource eRowSource = css::chart::ChartDataRowSource_ROWS; + if( bUseColumns ) + eRowSource = css::chart::ChartDataRowSource_COLUMNS; + + return + { + { "DataRowSource", -1, uno::Any( eRowSource), beans::PropertyState_DIRECT_VALUE }, + { "FirstCellAsLabel", -1, uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE }, + { "HasCategories", -1, uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE } + }; +} + +uno::Sequence< beans::PropertyValue > DataSourceHelper::createArguments( + const OUString & rRangeRepresentation, + const uno::Sequence< sal_Int32 >& rSequenceMapping, + bool bUseColumns, bool bFirstCellAsLabel, bool bHasCategories ) +{ + uno::Sequence< beans::PropertyValue > aArguments( createArguments( bUseColumns, bFirstCellAsLabel, bHasCategories )); + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "CellRangeRepresentation" + , -1, uno::Any( rRangeRepresentation ) + , beans::PropertyState_DIRECT_VALUE ); + if( rSequenceMapping.hasElements() ) + { + aArguments.realloc( aArguments.getLength() + 1 ); + aArguments.getArray()[aArguments.getLength() - 1] = + beans::PropertyValue( "SequenceMapping" + , -1, uno::Any( rSequenceMapping ) + , beans::PropertyState_DIRECT_VALUE ); + } + return aArguments; +} + +void DataSourceHelper::readArguments( const uno::Sequence< beans::PropertyValue >& rArguments + , OUString & rRangeRepresentation, uno::Sequence< sal_Int32 >& rSequenceMapping + , bool& bUseColumns, bool& bFirstCellAsLabel, bool& bHasCategories ) +{ + for(const beans::PropertyValue& rProperty : rArguments) + { + if ( rProperty.Name == "DataRowSource" ) + { + css::chart::ChartDataRowSource eRowSource; + if( rProperty.Value >>= eRowSource ) + bUseColumns = (eRowSource==css::chart::ChartDataRowSource_COLUMNS); + } + else if ( rProperty.Name == "FirstCellAsLabel" ) + { + rProperty.Value >>= bFirstCellAsLabel; + } + else if ( rProperty.Name == "HasCategories" ) + { + rProperty.Value >>= bHasCategories; + } + else if ( rProperty.Name == "CellRangeRepresentation" ) + { + rProperty.Value >>= rRangeRepresentation; + } + else if ( rProperty.Name == "SequenceMapping" ) + { + rProperty.Value >>= rSequenceMapping; + } + } +} + +rtl::Reference< DataSource > DataSourceHelper::pressUsedDataIntoRectangularFormat( + const rtl::Reference< ChartModel >& xChartDoc ) +{ + std::vector< Reference< chart2::data::XLabeledDataSequence > > aResultVector; + + //categories are always the first sequence + rtl::Reference< Diagram > xDiagram( xChartDoc->getFirstChartDiagram()); + + Reference< chart2::data::XLabeledDataSequence > xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram ) ); + if( xCategories.is() ) + aResultVector.push_back( xCategories ); + + std::vector< rtl::Reference< DataSeries > > aSeriesVector = DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + uno::Reference< chart2::data::XDataSource > xSeriesSource = + DataSeriesHelper::getDataSource( aSeriesVector ); + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xSeriesSource->getDataSequences() ); + + //the first x-values is always the next sequence //todo ... other x-values get lost for old format + Reference< chart2::data::XLabeledDataSequence > xXValues( + DataSeriesHelper::getDataSequenceByRole( xSeriesSource, "values-x" ) ); + if( xXValues.is() ) + aResultVector.push_back( xXValues ); + + //add all other sequences now without x-values + for( Reference< chart2::data::XLabeledDataSequence > const & labeledData : aDataSequences ) + { + OUString aRole = DataSeriesHelper::getRole(labeledData); + if( aRole != "values-x" ) + aResultVector.push_back( labeledData ); + } + + return new DataSource( aResultVector ); +} + +uno::Sequence< OUString > DataSourceHelper::getUsedDataRanges( + const rtl::Reference< Diagram > & xDiagram ) +{ + std::vector< OUString > aResult; + + if( xDiagram.is()) + { + uno::Reference< data::XLabeledDataSequence > xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram ) ); + if( xCategories.is() ) + lcl_addRanges( aResult, xCategories ); + + std::vector< rtl::Reference< DataSeries > > aSeriesVector( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); + for (auto const& series : aSeriesVector) + { + lcl_addDataSourceRanges( aResult, series ); + lcl_addErrorBarRanges( aResult, series ); + } + } + + return comphelper::containerToSequence( aResult ); +} + +uno::Sequence< OUString > DataSourceHelper::getUsedDataRanges( const rtl::Reference<::chart::ChartModel> & xChartModel ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + return getUsedDataRanges( xDiagram ); +} + +rtl::Reference< DataSource > DataSourceHelper::getUsedData( + ChartModel& rModel ) +{ + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aResult; + + rtl::Reference< Diagram > xDiagram = rModel.getFirstChartDiagram(); + uno::Reference< chart2::data::XLabeledDataSequence > xCategories( DiagramHelper::getCategoriesFromDiagram( xDiagram ) ); + if( xCategories.is() ) + aResult.push_back( xCategories ); + + std::vector< rtl::Reference< DataSeries > > aSeriesVector = ChartModelHelper::getDataSeries( &rModel ); + for (auto const& series : aSeriesVector) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSequences( series->getDataSequences2() ); + aResult.insert( aResult.end(), aDataSequences.begin(), aDataSequences.end() ); + } + + return new DataSource( aResult ); +} + +bool DataSourceHelper::detectRangeSegmentation( + const rtl::Reference<::chart::ChartModel>& xChartModel + , OUString& rOutRangeString + , css::uno::Sequence< sal_Int32 >& rSequenceMapping + , bool& rOutUseColumns + , bool& rOutFirstCellAsLabel + , bool& rOutHasCategories ) +{ + bool bSomethingDetected = false; + + if( !xChartModel.is() ) + return bSomethingDetected; + uno::Reference< data::XDataProvider > xDataProvider( xChartModel->getDataProvider() ); + if( !xDataProvider.is() ) + return bSomethingDetected; + + try + { + DataSourceHelper::readArguments( + xDataProvider->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel ) ), + rOutRangeString, rSequenceMapping, rOutUseColumns, rOutFirstCellAsLabel, rOutHasCategories ); + bSomethingDetected = !rOutRangeString.isEmpty(); + + uno::Reference< chart2::data::XLabeledDataSequence > xCategories( + DiagramHelper::getCategoriesFromDiagram( xChartModel->getFirstChartDiagram() )); + rOutHasCategories = xCategories.is(); + } + catch( uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bSomethingDetected; +} + +bool DataSourceHelper::allArgumentsForRectRangeDetected( + const rtl::Reference<::chart::ChartModel>& xChartDocument ) +{ + bool bHasDataRowSource = false; + bool bHasFirstCellAsLabel = false; + bool bHasCellRangeRepresentation = false; + + uno::Reference< data::XDataProvider > xDataProvider( xChartDocument->getDataProvider() ); + if( !xDataProvider.is() ) + return false; + + try + { + const uno::Sequence< beans::PropertyValue > aArguments( + xDataProvider->detectArguments( pressUsedDataIntoRectangularFormat( xChartDocument ))); + for(const beans::PropertyValue& rProperty : aArguments) + { + if ( rProperty.Name == "DataRowSource" ) + { + bHasDataRowSource = + (rProperty.Value.hasValue() && rProperty.Value.isExtractableTo( + cppu::UnoType::get())); + } + else if ( rProperty.Name == "FirstCellAsLabel" ) + { + bHasFirstCellAsLabel = + (rProperty.Value.hasValue() && rProperty.Value.isExtractableTo(cppu::UnoType::get())); + } + else if ( rProperty.Name == "CellRangeRepresentation" ) + { + OUString aRange; + bHasCellRangeRepresentation = + (rProperty.Value.hasValue() && (rProperty.Value >>= aRange) && !aRange.isEmpty()); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return (bHasCellRangeRepresentation && bHasDataRowSource && bHasFirstCellAsLabel); +} + +void DataSourceHelper::setRangeSegmentation( + const rtl::Reference<::chart::ChartModel>& xChartModel + , const css::uno::Sequence< sal_Int32 >& rSequenceMapping + , bool bUseColumns , bool bFirstCellAsLabel, bool bUseCategories ) +{ + uno::Reference< data::XDataProvider > xDataProvider( xChartModel->getDataProvider() ); + if( !xDataProvider.is() ) + return; + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( !xDiagram.is() ) + return; + rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = xChartModel->getTypeManager(); + if( !xChartTypeManager.is() ) + return; + + OUString aRangeString; + bool bDummy; + uno::Sequence< sal_Int32 > aDummy; + readArguments( xDataProvider->detectArguments( pressUsedDataIntoRectangularFormat( xChartModel )), + aRangeString, aDummy, bDummy, bDummy, bDummy ); + + uno::Sequence< beans::PropertyValue > aArguments( + createArguments( aRangeString, rSequenceMapping, bUseColumns, bFirstCellAsLabel, bUseCategories ) ); + + uno::Reference< chart2::data::XDataSource > xDataSource( xDataProvider->createDataSource( + aArguments ) ); + if( !xDataSource.is() ) + return; + + ControllerLockGuardUNO aCtrlLockGuard( xChartModel ); + xDiagram->setDiagramData( xDataSource, aArguments ); +} + +Sequence< OUString > DataSourceHelper::getRangesFromLabeledDataSequence( + const Reference< data::XLabeledDataSequence > & xLSeq ) +{ + Sequence< OUString > aResult; + if( xLSeq.is()) + { + Reference< data::XDataSequence > xLabel( xLSeq->getLabel()); + Reference< data::XDataSequence > xValues( xLSeq->getValues()); + + if( xLabel.is()) + { + if( xValues.is()) + { + aResult = { xLabel->getSourceRangeRepresentation(), + xValues->getSourceRangeRepresentation() }; + } + else + { + aResult = { xLabel->getSourceRangeRepresentation() }; + } + } + else if( xValues.is()) + { + aResult = { xValues->getSourceRangeRepresentation() }; + } + } + return aResult; +} + +OUString DataSourceHelper::getRangeFromValues( + const Reference< data::XLabeledDataSequence > & xLSeq ) +{ + OUString aResult; + if( xLSeq.is() ) + { + Reference< data::XDataSequence > xValues( xLSeq->getValues() ); + if( xValues.is() ) + aResult = xValues->getSourceRangeRepresentation(); + } + return aResult; +} + +Sequence< OUString > DataSourceHelper::getRangesFromDataSource( const Reference< data::XDataSource > & xSource ) +{ + std::vector< OUString > aResult; + if( xSource.is()) + { + const Sequence< Reference< data::XLabeledDataSequence > > aLSeqSeq( xSource->getDataSequences()); + for( Reference< data::XLabeledDataSequence > const & labeledData : aLSeqSeq ) + { + Reference< data::XDataSequence > xLabel( labeledData->getLabel()); + Reference< data::XDataSequence > xValues( labeledData->getValues()); + + if( xLabel.is()) + aResult.push_back( xLabel->getSourceRangeRepresentation()); + if( xValues.is()) + aResult.push_back( xValues->getSourceRangeRepresentation()); + } + } + return comphelper::containerToSequence( aResult ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/DiagramHelper.cxx b/chart2/source/tools/DiagramHelper.cxx new file mode 100644 index 000000000..04556b6ed --- /dev/null +++ b/chart2/source/tools/DiagramHelper.cxx @@ -0,0 +1,1571 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::chart2::XAnyDescriptionAccess; + +namespace chart +{ + +DiagramHelper::tTemplateWithServiceName + DiagramHelper::getTemplateForDiagram( + const rtl::Reference< Diagram > & xDiagram, + const rtl::Reference< ::chart::ChartTypeManager > & xChartTypeManager ) +{ + DiagramHelper::tTemplateWithServiceName aResult; + + if( ! (xChartTypeManager.is() && xDiagram.is())) + return aResult; + + Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames()); + const sal_Int32 nLength = aServiceNames.getLength(); + + bool bTemplateFound = false; + + for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i ) + { + try + { + rtl::Reference< ::chart::ChartTypeTemplate > xTempl = + xChartTypeManager->createTemplate( aServiceNames[ i ] ); + + if (xTempl.is() && xTempl->matchesTemplate2(xDiagram, true)) + { + aResult.xChartTypeTemplate = xTempl; + aResult.sServiceName = aServiceNames[ i ]; + bTemplateFound = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +void DiagramHelper::setVertical( + const rtl::Reference< Diagram > & xDiagram, + bool bVertical /* = true */ ) +{ + try + { + if (!xDiagram.is()) + return; + + uno::Any aValue; + aValue <<= bVertical; + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + bool bChanged = false; + bool bOldSwap = false; + if( !(xCooSys->getPropertyValue("SwapXAndYAxis") >>= bOldSwap) + || bVertical != bOldSwap ) + bChanged = true; + + if( bChanged ) + xCooSys->setPropertyValue("SwapXAndYAxis", aValue); + + const sal_Int32 nDimensionCount = xCooSys->getDimension(); + sal_Int32 nDimIndex = 0; + for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); + for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI) + { + rtl::Reference xAxis = xCooSys->getAxisByDimension2(nDimIndex,nI); + if (!xAxis.is()) + continue; + + //adapt title rotation only when axis swapping has changed + if (!bChanged) + continue; + + Reference< beans::XPropertySet > xTitleProps( xAxis->getTitleObject(), uno::UNO_QUERY ); + if (!xTitleProps.is()) + continue; + + double fAngleDegree = 0.0; + xTitleProps->getPropertyValue("TextRotation") >>= fAngleDegree; + if (fAngleDegree != 0.0 && + !rtl::math::approxEqual(fAngleDegree, 90.0)) + continue; + + double fNewAngleDegree = 0.0; + if( !bVertical && nDimIndex == 1 ) + fNewAngleDegree = 90.0; + else if( bVertical && nDimIndex == 0 ) + fNewAngleDegree = 90.0; + + xTitleProps->setPropertyValue("TextRotation", uno::Any(fNewAngleDegree)); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool DiagramHelper::getVertical( const rtl::Reference< Diagram > & xDiagram, + bool& rbFound, bool& rbAmbiguous ) +{ + bool bValue = false; + rbFound = false; + rbAmbiguous = false; + + if (!xDiagram.is()) + return false; + + for (rtl::Reference const & coords : xDiagram->getBaseCoordinateSystems()) + { + bool bCurrent = false; + if (coords->getPropertyValue("SwapXAndYAxis") >>= bCurrent) + { + if (!rbFound) + { + bValue = bCurrent; + rbFound = true; + } + else if (bCurrent != bValue) + { + // ambiguous -> choose always first found + rbAmbiguous = true; + } + } + } + return bValue; +} + +void DiagramHelper::setStackMode( + const rtl::Reference< Diagram > & xDiagram, + StackMode eStackMode +) +{ + try + { + bool bValueFound = false; + bool bIsAmbiguous = false; + StackMode eOldStackMode = DiagramHelper::getStackMode( xDiagram, bValueFound, bIsAmbiguous ); + + if( eStackMode == eOldStackMode && !bIsAmbiguous ) + return; + + StackingDirection eNewDirection = StackingDirection_NO_STACKING; + if( eStackMode == StackMode::YStacked || eStackMode == StackMode::YStackedPercent ) + eNewDirection = StackingDirection_Y_STACKING; + else if( eStackMode == StackMode::ZStacked ) + eNewDirection = StackingDirection_Z_STACKING; + + uno::Any aNewDirection( eNewDirection ); + + bool bPercent = false; + if( eStackMode == StackMode::YStackedPercent ) + bPercent = true; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + //set correct percent stacking + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1,nI ); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( (aScaleData.AxisType==AxisType::PERCENT) != bPercent ) + { + if( bPercent ) + aScaleData.AxisType = AxisType::PERCENT; + else + aScaleData.AxisType = AxisType::REALNUMBER; + xAxis->setScaleData( aScaleData ); + } + } + } + //iterate through all chart types in the current coordinate system + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() ); + if (aChartTypeList.empty()) + continue; + + rtl::Reference< ChartType > xChartType( aChartTypeList[0] ); + + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() ) + { + dataSeries->setPropertyValue( "StackingDirection", aNewDirection ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +StackMode DiagramHelper::getStackMode( const rtl::Reference< Diagram > & xDiagram, bool& rbFound, bool& rbAmbiguous ) +{ + rbFound=false; + rbAmbiguous=false; + + StackMode eGlobalStackMode = StackMode::NONE; + + if( !xDiagram.is() ) + return eGlobalStackMode; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + for( std::size_t nT = 0; nT < aChartTypeList.size(); ++nT ) + { + rtl::Reference< ChartType > xChartType( aChartTypeList[nT] ); + + StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType( + xChartType, rbFound, rbAmbiguous, xCooSys ); + + if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 ) + { + rbAmbiguous = true; + return eGlobalStackMode; + } + + eGlobalStackMode = eLocalStackMode; + } + } + + return eGlobalStackMode; +} + +StackMode DiagramHelper::getStackModeFromChartType( + const rtl::Reference< ChartType > & xChartType, + bool& rbFound, bool& rbAmbiguous, + const rtl::Reference< BaseCoordinateSystem > & xCorrespondingCoordinateSystem ) +{ + StackMode eStackMode = StackMode::NONE; + rbFound = false; + rbAmbiguous = false; + + try + { + const std::vector< rtl::Reference< DataSeries > > & aSeries = xChartType->getDataSeries2(); + + chart2::StackingDirection eCommonDirection = chart2::StackingDirection_NO_STACKING; + bool bDirectionInitialized = false; + + // first series is irrelevant for stacking, start with second, unless + // there is only one series + const sal_Int32 nSeriesCount = aSeries.size(); + sal_Int32 i = (nSeriesCount == 1) ? 0: 1; + for( ; igetPropertyValue( "StackingDirection" ) >>= eCurrentDirection ); + OSL_ASSERT( bSuccess ); + if( ! bDirectionInitialized ) + { + eCommonDirection = eCurrentDirection; + bDirectionInitialized = true; + } + else + { + if( eCommonDirection != eCurrentDirection ) + { + rbAmbiguous = true; + break; + } + } + } + + if( rbFound ) + { + if( eCommonDirection == chart2::StackingDirection_Z_STACKING ) + eStackMode = StackMode::ZStacked; + else if( eCommonDirection == chart2::StackingDirection_Y_STACKING ) + { + eStackMode = StackMode::YStacked; + + // percent stacking + if( xCorrespondingCoordinateSystem.is() ) + { + if( 1 < xCorrespondingCoordinateSystem->getDimension() ) + { + sal_Int32 nAxisIndex = 0; + if( nSeriesCount ) + nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(aSeries[0]); + + rtl::Reference< Axis > xAxis = + xCorrespondingCoordinateSystem->getAxisByDimension2( 1,nAxisIndex ); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.AxisType==chart2::AxisType::PERCENT ) + eStackMode = StackMode::YStackedPercent; + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return eStackMode; +} + +sal_Int32 DiagramHelper::getDimension( const rtl::Reference< Diagram > & xDiagram ) +{ + // -1: not yet set + sal_Int32 nResult = -1; + if (!xDiagram) + return nResult; + + try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + if(xCooSys.is()) + { + nResult = xCooSys->getDimension(); + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nResult; +} + +void DiagramHelper::setDimension( + const rtl::Reference< Diagram > & xDiagram, + sal_Int32 nNewDimensionCount ) +{ + if( ! xDiagram.is()) + return; + + if( DiagramHelper::getDimension( xDiagram ) == nNewDimensionCount ) + return; + + try + { + bool rbFound = false; + bool rbAmbiguous = true; + StackMode eStackMode = DiagramHelper::getStackMode( xDiagram, rbFound, rbAmbiguous ); + bool bIsSupportingOnlyDeepStackingFor3D=false; + + //change all coordinate systems: + auto aCoordSystems = xDiagram->getBaseCoordinateSystems(); + for( rtl::Reference const & xOldCooSys : aCoordSystems ) + { + rtl::Reference< BaseCoordinateSystem > xNewCooSys; + + const std::vector< rtl::Reference< ChartType > > aChartTypeList( xOldCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & xChartType : aChartTypeList ) + { + bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType ); + if(!xNewCooSys.is()) + { + xNewCooSys = dynamic_cast(xChartType->createCoordinateSystem( nNewDimensionCount ).get()); + assert(xNewCooSys); + break; + } + //@todo make sure that all following charttypes are also capable of the new dimension + //otherwise separate them in a different group + //BM: might be done in replaceCoordinateSystem() + } + + // replace the old coordinate system at all places where it was used + DiagramHelper::replaceCoordinateSystem( xDiagram, xOldCooSys, xNewCooSys ); + } + + //correct stack mode if necessary + if( nNewDimensionCount==3 && eStackMode != StackMode::ZStacked && bIsSupportingOnlyDeepStackingFor3D ) + DiagramHelper::setStackMode( xDiagram, StackMode::ZStacked ); + else if( nNewDimensionCount==2 && eStackMode == StackMode::ZStacked ) + DiagramHelper::setStackMode( xDiagram, StackMode::NONE ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void DiagramHelper::replaceCoordinateSystem( + const rtl::Reference< Diagram > & xDiagram, + const rtl::Reference< BaseCoordinateSystem > & xCooSysToReplace, + const rtl::Reference< BaseCoordinateSystem > & xReplacement ) +{ + OSL_ASSERT( xDiagram.is()); + if( ! xDiagram.is()) + return; + + // update the coordinate-system container + + try + { + uno::Reference< chart2::data::XLabeledDataSequence > xCategories = DiagramHelper::getCategoriesFromDiagram( xDiagram ); + + // move chart types of xCooSysToReplace to xReplacement + xReplacement->setChartTypes( xCooSysToReplace->getChartTypes()); + + xDiagram->removeCoordinateSystem( xCooSysToReplace ); + xDiagram->addCoordinateSystem( xReplacement ); + + if( xCategories.is() ) + DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +bool DiagramHelper::isSeriesAttachedToMainAxis( + const uno::Reference< chart2::XDataSeries >& xDataSeries ) +{ + sal_Int32 nAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + return (nAxisIndex==0); +} + +bool DiagramHelper::attachSeriesToAxis( bool bAttachToMainAxis + , const uno::Reference< chart2::XDataSeries >& xDataSeries + , const rtl::Reference< Diagram >& xDiagram + , const uno::Reference< uno::XComponentContext > & xContext + , bool bAdaptAxes ) +{ + bool bChanged = false; + + //set property at axis + Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW ); + + sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1; + sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries); + rtl::Reference< Axis > xOldAxis = DiagramHelper::getAttachedAxis( xDataSeries, xDiagram ); + + if( nOldAxisIndex != nNewAxisIndex ) + { + try + { + xProp->setPropertyValue( "AttachedAxisIndex", uno::Any( nNewAxisIndex ) ); + bChanged = true; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( bChanged && xDiagram.is() ) + { + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, bAttachToMainAxis, xDiagram ); + if(!xAxis.is()) //create an axis if necessary + xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, xDiagram, xContext ); + if( bAdaptAxes ) + { + AxisHelper::makeAxisVisible( xAxis ); + AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, xDiagram ); + } + } + + return bChanged; +} + +rtl::Reference< Axis > DiagramHelper::getAttachedAxis( + const uno::Reference< XDataSeries >& xSeries, + const rtl::Reference< Diagram >& xDiagram ) +{ + return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram ); +} + +rtl::Reference< Axis > DiagramHelper::getAttachedAxis( + const rtl::Reference< DataSeries >& xSeries, + const rtl::Reference< Diagram >& xDiagram ) +{ + return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), xDiagram ); +} + +rtl::Reference< ChartType > DiagramHelper::getChartTypeOfSeries( + const rtl::Reference< Diagram >& xDiagram + , const uno::Reference< XDataSeries >& xGivenDataSeries ) +{ + if( !xGivenDataSeries.is() ) + return nullptr; + if(!xDiagram.is()) + return nullptr; + rtl::Reference pGivenDataSeries = dynamic_cast(xGivenDataSeries.get()); + assert(pGivenDataSeries); + + //iterate through the model to find the given xSeries + //the found parent indicates the charttype + + //iterate through all coordinate systems + + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & xChartType : aChartTypeList ) + { + //iterate through all series in this chart type + for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() ) + { + if( pGivenDataSeries==dataSeries ) + return xChartType; + } + } + } + return nullptr; +} + +std::vector< rtl::Reference< ::chart::DataSeries > > + DiagramHelper::getDataSeriesFromDiagram( + const rtl::Reference< Diagram > & xDiagram ) +{ + std::vector< rtl::Reference< DataSeries > > aResult; + if (!xDiagram) + return aResult; + + try + { + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + for( rtl::Reference< ChartType> const & chartType : coords->getChartTypes2() ) + { + const std::vector< rtl::Reference< DataSeries > > aSeriesSeq( chartType->getDataSeries2() ); + aResult.insert( aResult.end(), aSeriesSeq.begin(), aSeriesSeq.end() ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +std::vector< std::vector< rtl::Reference< DataSeries > > > + DiagramHelper::getDataSeriesGroups( const rtl::Reference< Diagram > & xDiagram ) +{ + if (!xDiagram) + return {}; + + vector< std::vector< rtl::Reference< DataSeries > > > aResult; + + //iterate through all coordinate systems + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + //iterate through all chart types in the current coordinate system + for( rtl::Reference< ChartType > const & chartType : coords->getChartTypes2() ) + { + aResult.push_back( chartType->getDataSeries2() ); + } + } + return aResult; +} + +rtl::Reference< ChartType > + DiagramHelper::getChartTypeByIndex( const rtl::Reference< Diagram >& xDiagram, sal_Int32 nIndex ) +{ + if (!xDiagram) + return nullptr; + + rtl::Reference< ChartType > xChartType; + + //iterate through all coordinate systems + sal_Int32 nTypesSoFar = 0; + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + const std::vector< rtl::Reference< ChartType > > & aChartTypeList( coords->getChartTypes2() ); + if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < nTypesSoFar + aChartTypeList.size() ) + { + xChartType = aChartTypeList[nIndex - nTypesSoFar]; + break; + } + nTypesSoFar += aChartTypeList.size(); + } + + return xChartType; +} + +namespace +{ + +std::vector< rtl::Reference< Axis > > lcl_getAxisHoldingCategoriesFromDiagram( + const rtl::Reference< Diagram > & xDiagram ) +{ + std::vector< rtl::Reference< Axis > > aRet; + + // return first x-axis as fall-back + rtl::Reference< Axis > xFallBack; + if (xDiagram.is()) try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + OSL_ASSERT( xCooSys.is()); + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.Categories.is() || (aScaleData.AxisType == AxisType::CATEGORY) ) + { + aRet.push_back(xAxis); + } + if( (nN == 0) && !xFallBack.is()) + xFallBack = xAxis; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + if( aRet.empty() ) + aRet.push_back(xFallBack); + + return aRet; +} + +} // anonymous namespace + +bool DiagramHelper::isCategoryDiagram( + const rtl::Reference< Diagram >& xDiagram ) +{ + try + { + for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : xDiagram->getBaseCoordinateSystems() ) + { + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI ); + OSL_ASSERT( xAxis.is()); + if( xAxis.is()) + { + ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE ) + return true; + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return false; +} + +void DiagramHelper::setCategoriesToDiagram( + const uno::Reference< chart2::data::XLabeledDataSequence >& xCategories, + const rtl::Reference< Diagram >& xDiagram, + bool bSetAxisType /* = false */, + bool bCategoryAxis /* = true */ ) +{ + std::vector< rtl::Reference< Axis > > aCatAxes( + lcl_getAxisHoldingCategoriesFromDiagram( xDiagram )); + + for (const rtl::Reference< Axis >& xCatAxis : aCatAxes) + { + if( xCatAxis.is()) + { + ScaleData aScaleData( xCatAxis->getScaleData()); + aScaleData.Categories = xCategories; + if( bSetAxisType ) + { + if( bCategoryAxis ) + aScaleData.AxisType = AxisType::CATEGORY; + else if( aScaleData.AxisType == AxisType::CATEGORY || aScaleData.AxisType == AxisType::DATE ) + aScaleData.AxisType = AxisType::REALNUMBER; + } + xCatAxis->setScaleData( aScaleData ); + } + } +} + +uno::Reference< chart2::data::XLabeledDataSequence > + DiagramHelper::getCategoriesFromDiagram( + const rtl::Reference< Diagram > & xDiagram ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + + try + { + std::vector< rtl::Reference< Axis > > aCatAxes( + lcl_getAxisHoldingCategoriesFromDiagram( xDiagram )); + //search for first categories + if (!aCatAxes.empty()) + { + rtl::Reference< Axis > xCatAxis(aCatAxes[0]); + if( xCatAxis.is()) + { + ScaleData aScaleData( xCatAxis->getScaleData()); + if( aScaleData.Categories.is() ) + { + xResult = aScaleData.Categories; + uno::Reference xProp(xResult->getValues(), uno::UNO_QUERY ); + if( xProp.is() ) + { + try + { + xProp->setPropertyValue( "Role", uno::Any( OUString("categories") ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +static void lcl_generateAutomaticCategoriesFromChartType( + Sequence< OUString >& rRet, + const rtl::Reference< ChartType >& xChartType ) +{ + if(!xChartType.is()) + return; + OUString aMainSeq( xChartType->getRoleOfSequenceForSeriesLabel() ); + + const std::vector< rtl::Reference< DataSeries > > & aSeriesSeq = xChartType->getDataSeries2(); + for( rtl::Reference< DataSeries > const & dataSeries : aSeriesSeq ) + { + uno::Reference< data::XLabeledDataSequence > xLabeledSeq = + ::chart::DataSeriesHelper::getDataSequenceByRole( dataSeries, aMainSeq ); + if( !xLabeledSeq.is() ) + continue; + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues() ); + if( !xValueSeq.is() ) + continue; + rRet = xValueSeq->generateLabel( chart2::data::LabelOrigin_LONG_SIDE ); + if( rRet.hasElements() ) + return; + } +} + +Sequence< OUString > DiagramHelper::generateAutomaticCategoriesFromCooSys( const rtl::Reference< BaseCoordinateSystem > & xCooSys ) +{ + Sequence< OUString > aRet; + + if( xCooSys.is() ) + { + const std::vector< rtl::Reference< ChartType > > & aChartTypes( xCooSys->getChartTypes2() ); + for( rtl::Reference< ChartType > const & chartType : aChartTypes ) + { + lcl_generateAutomaticCategoriesFromChartType( aRet, chartType ); + if( aRet.hasElements() ) + return aRet; + } + } + return aRet; +} + +Sequence< OUString > DiagramHelper::getExplicitSimpleCategories( + ChartModel& rModel ) +{ + rtl::Reference< BaseCoordinateSystem > xCooSys( ChartModelHelper::getFirstCoordinateSystem( &rModel ) ); + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSys, rModel ); + return aExplicitCategoriesProvider.getSimpleCategories(); +} + +namespace +{ +void lcl_switchToDateCategories( const rtl::Reference< ChartModel >& xChartDoc, const Reference< XAxis >& xAxis ) +{ + if( !xAxis.is() ) + return; + if( !xChartDoc.is() ) + return; + + ScaleData aScale( xAxis->getScaleData() ); + if( xChartDoc->hasInternalDataProvider() ) + { + //remove all content the is not of type double and remove multiple level + Reference< XAnyDescriptionAccess > xDataAccess( xChartDoc->getDataProvider(), uno::UNO_QUERY ); + if( xDataAccess.is() ) + { + Sequence< Sequence< Any > > aAnyCategories( xDataAccess->getAnyRowDescriptions() ); + auto aAnyCategoriesRange = asNonConstRange(aAnyCategories); + double fTest = 0.0; + sal_Int32 nN = aAnyCategories.getLength(); + for( ; nN--; ) + { + Sequence< Any >& rCat = aAnyCategoriesRange[nN]; + if( rCat.getLength() > 1 ) + rCat.realloc(1); + if( rCat.getLength() == 1 ) + { + Any& rAny = rCat.getArray()[0]; + if( !(rAny>>=fTest) ) + { + rAny <<= std::numeric_limits::quiet_NaN(); + } + } + } + xDataAccess->setAnyRowDescriptions( aAnyCategories ); + } + //check the numberformat at the axis + Reference< beans::XPropertySet > xAxisProps( xAxis, uno::UNO_QUERY ); + if( xAxisProps.is() ) + { + sal_Int32 nNumberFormat = -1; + xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormat; + + Reference< util::XNumberFormats > xNumberFormats( xChartDoc->getNumberFormats() ); + if( xNumberFormats.is() ) + { + Reference< beans::XPropertySet > xKeyProps; + try + { + xKeyProps = xNumberFormats->getByKey( nNumberFormat ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + sal_Int32 nType = util::NumberFormat::UNDEFINED; + if( xKeyProps.is() ) + xKeyProps->getPropertyValue( "Type" ) >>= nType; + if( !( nType & util::NumberFormat::DATE ) ) + { + //set a date format to the axis + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + Sequence aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, rLocaleDataWrapper.getLanguageTag().getLocale(), true/*bCreate*/ ); + if( aKeySeq.hasElements() ) + { + xAxisProps->setPropertyValue(CHART_UNONAME_NUMFMT, uno::Any(aKeySeq[0])); + } + } + } + } + } + if( aScale.AxisType != chart2::AxisType::DATE ) + AxisHelper::removeExplicitScaling( aScale ); + aScale.AxisType = chart2::AxisType::DATE; + xAxis->setScaleData( aScale ); +} + +void lcl_switchToTextCategories( const rtl::Reference< ChartModel >& xChartDoc, const Reference< XAxis >& xAxis ) +{ + if( !xAxis.is() ) + return; + if( !xChartDoc.is() ) + return; + ScaleData aScale( xAxis->getScaleData() ); + if( aScale.AxisType != chart2::AxisType::CATEGORY ) + AxisHelper::removeExplicitScaling( aScale ); + //todo migrate dates to text? + aScale.AxisType = chart2::AxisType::CATEGORY; + aScale.AutoDateAxis = false; + xAxis->setScaleData( aScale ); +} + +} + +void DiagramHelper::switchToDateCategories( const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + if(xChartDoc.is()) + { + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + + rtl::Reference< BaseCoordinateSystem > xCooSys = ChartModelHelper::getFirstCoordinateSystem( xChartDoc ); + if( xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(0,0); + lcl_switchToDateCategories( xChartDoc, xAxis ); + } + } +} + +void DiagramHelper::switchToTextCategories( const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + if(xChartDoc.is()) + { + ControllerLockGuardUNO aCtrlLockGuard( xChartDoc ); + + rtl::Reference< BaseCoordinateSystem > xCooSys = ChartModelHelper::getFirstCoordinateSystem( xChartDoc ); + if( xCooSys.is() ) + { + rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2(0,0); + lcl_switchToTextCategories( xChartDoc, xAxis ); + } + } +} + +bool DiagramHelper::isSupportingDateAxis( const rtl::Reference< Diagram >& xDiagram ) +{ + return ::chart::ChartTypeHelper::isSupportingDateAxis( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ), 0 ); +} + +bool DiagramHelper::isDateNumberFormat( sal_Int32 nNumberFormat, const Reference< util::XNumberFormats >& xNumberFormats ) +{ + bool bIsDate = false; + if( !xNumberFormats.is() ) + return bIsDate; + + Reference< beans::XPropertySet > xKeyProps = xNumberFormats->getByKey( nNumberFormat ); + if( xKeyProps.is() ) + { + sal_Int32 nType = util::NumberFormat::UNDEFINED; + xKeyProps->getPropertyValue( "Type" ) >>= nType; + bIsDate = nType & util::NumberFormat::DATE; + } + return bIsDate; +} + +sal_Int32 DiagramHelper::getDateNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + sal_Int32 nRet=-1; + + //try to get a date format with full year display + const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag(); + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + if( pNumFormatter ) + { + nRet = pNumFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, rLanguageTag.getLanguageType() ); + } + else + { + Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() ); + if( xNumberFormats.is() ) + { + Sequence aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::DATE, + rLanguageTag.getLocale(), true/*bCreate */); + if( aKeySeq.hasElements() ) + { + nRet = aKeySeq[0]; + } + } + } + return nRet; +} + +sal_Int32 DiagramHelper::getDateTimeInputNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier, double fNumber ) +{ + sal_Int32 nRet = 0; + + // Get the most detailed date/time format according to fNumber. + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + if (!pNumFormatter) + SAL_WARN("chart2", "DiagramHelper::getDateTimeInputNumberFormat - no SvNumberFormatter"); + else + { + SvNumFormatType nType; + // Obtain best matching date, time or datetime format. + nRet = pNumFormatter->GuessDateTimeFormat( nType, fNumber, LANGUAGE_SYSTEM); + // Obtain the corresponding edit format. + nRet = pNumFormatter->GetEditFormat( fNumber, nRet, nType, nullptr); + } + return nRet; +} + +sal_Int32 DiagramHelper::getPercentNumberFormat( const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) +{ + sal_Int32 nRet=-1; + const LanguageTag& rLanguageTag = Application::GetSettings().GetLanguageTag(); + NumberFormatterWrapper aNumberFormatterWrapper( xNumberFormatsSupplier ); + SvNumberFormatter* pNumFormatter = aNumberFormatterWrapper.getSvNumberFormatter(); + if( pNumFormatter ) + { + nRet = pNumFormatter->GetFormatIndex( NF_PERCENT_INT, rLanguageTag.getLanguageType() ); + } + else + { + Reference< util::XNumberFormats > xNumberFormats( xNumberFormatsSupplier->getNumberFormats() ); + if( xNumberFormats.is() ) + { + Sequence aKeySeq = xNumberFormats->queryKeys( util::NumberFormat::PERCENT, + rLanguageTag.getLocale(), true/*bCreate*/ ); + if( aKeySeq.hasElements() ) + { + // This *assumes* the sequence is sorted as in + // NfIndexTableOffset and the first format is the integer 0% + // format by chance... which usually is the case, but... anyway, + // we usually also have a number formatter so don't reach here. + nRet = aKeySeq[0]; + } + } + } + return nRet; +} + +std::vector< rtl::Reference< ChartType > > + DiagramHelper::getChartTypesFromDiagram( + const rtl::Reference< Diagram > & xDiagram ) +{ + if(!xDiagram) + return {}; + + std::vector< rtl::Reference< ChartType > > aResult; + try + { + for( rtl::Reference< BaseCoordinateSystem > const & coords : xDiagram->getBaseCoordinateSystems() ) + { + const std::vector< rtl::Reference< ChartType > > & aChartTypeSeq( coords->getChartTypes2()); + aResult.insert( aResult.end(), aChartTypeSeq.begin(), aChartTypeSeq.end() ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return aResult; +} + +bool DiagramHelper::areChartTypesCompatible( const rtl::Reference< ChartType >& xFirstType, + const rtl::Reference< ChartType >& xSecondType ) +{ + if( !xFirstType.is() || !xSecondType.is() ) + return false; + + auto aFirstRoles( comphelper::sequenceToContainer>( xFirstType->getSupportedMandatoryRoles() ) ); + auto aSecondRoles( comphelper::sequenceToContainer>( xSecondType->getSupportedMandatoryRoles() ) ); + std::sort( aFirstRoles.begin(), aFirstRoles.end() ); + std::sort( aSecondRoles.begin(), aSecondRoles.end() ); + return ( aFirstRoles == aSecondRoles ); +} + +namespace +{ + /** + * This method implements the logic of checking if a series can be moved + * forward/backward. Depending on the "bDoMove" parameter the series will + * be moved (bDoMove = true) or the function just will test if the + * series can be moved without doing the move (bDoMove = false). + * + * @param xDiagram + * Reference to the diagram that contains the series. + * + * @param xGivenDataSeries + * Reference to the series that should moved or tested for moving. + * + * @param bForward + * Direction in which the series should be moved or tested for moving. + * + * @param bDoMove + * Should this function really move the series (true) or just test if it is + * possible (false). + * + * + * @returns + * in case of bDoMove == true + * - True : if the move was done + * - False : the move failed + * in case of bDoMove == false + * - True : the series can be moved + * - False : the series can not be moved + * + */ + +bool lcl_moveSeriesOrCheckIfMoveIsAllowed( + const rtl::Reference< Diagram >& xDiagram, + const rtl::Reference< DataSeries >& xGivenDataSeries, + bool bForward, + bool bDoMove ) +{ + bool bMovedOrMoveAllowed = false; + + try + { + if( xGivenDataSeries.is() && xDiagram.is() ) + { + //find position of series. + bool bFound = false; + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); + + for( std::size_t nCS = 0; !bFound && nCS < aCooSysList.size(); ++nCS ) + { + const rtl::Reference< BaseCoordinateSystem > & xCooSys( aCooSysList[nCS] ); + + //iterate through all chart types in the current coordinate system + std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() ); + rtl::Reference< ChartType > xFormerChartType; + + for( std::size_t nT = 0; !bFound && nT < aChartTypeList.size(); ++nT ) + { + rtl::Reference< ChartType > xCurrentChartType( aChartTypeList[nT] ); + + //iterate through all series in this chart type + + std::vector< rtl::Reference< DataSeries > > aSeriesList = xCurrentChartType->getDataSeries2(); + + for( std::size_t nS = 0; !bFound && nS < aSeriesList.size(); ++nS ) + { + + // We found the series we are interested in! + if( xGivenDataSeries==aSeriesList[nS] ) + { + std::size_t nOldSeriesIndex = nS; + bFound = true; + + try + { + sal_Int32 nNewSeriesIndex = nS; + + // tdf#34517 Bringing forward means increasing, backwards means decreasing series position + if( !bForward ) + nNewSeriesIndex--; + else + nNewSeriesIndex++; + + if( nNewSeriesIndex >= 0 && o3tl::make_unsigned(nNewSeriesIndex) < aSeriesList.size() ) + { + //move series in the same charttype + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ]; + aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries; + xCurrentChartType->setDataSeries( aSeriesList ); + } + } + else if( nNewSeriesIndex<0 ) + { + //exchange series with former charttype + if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) ) + { + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xFormerChartType->getDataSeries2(); + sal_Int32 nOtherSeriesIndex = aOtherSeriesList.size()-1; + if( nOtherSeriesIndex >= 0 && o3tl::make_unsigned(nOtherSeriesIndex) < aOtherSeriesList.size() ) + { + rtl::Reference< DataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] ); + aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries; + xFormerChartType->setDataSeries(aOtherSeriesList); + + aSeriesList[nOldSeriesIndex]=xExchangeSeries; + xCurrentChartType->setDataSeries(aSeriesList); + } + } + } + } + else if( nT+1 < aChartTypeList.size() ) + { + //exchange series with next charttype + rtl::Reference< ChartType > xOtherChartType( aChartTypeList[nT+1] ); + if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) ) + { + bMovedOrMoveAllowed = true; + if( bDoMove ) + { + std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xOtherChartType->getDataSeries2(); + if( !aOtherSeriesList.empty() ) + { + rtl::Reference< DataSeries > xExchangeSeries( aOtherSeriesList[0] ); + aOtherSeriesList[0] = xGivenDataSeries; + xOtherChartType->setDataSeries(aOtherSeriesList); + + aSeriesList[nOldSeriesIndex]=xExchangeSeries; + xCurrentChartType->setDataSeries(aSeriesList); + } + } + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + } + } + xFormerChartType = xCurrentChartType; + } + } + } + } + catch( const util::CloseVetoException& ) + { + } + catch( const uno::RuntimeException& ) + { + } + return bMovedOrMoveAllowed; +} +} // anonymous namespace + +bool DiagramHelper::isSeriesMoveable( + const rtl::Reference< Diagram >& xDiagram, + const Reference< XDataSeries >& xGivenDataSeries, + bool bForward ) +{ + const bool bDoMove = false; + + rtl::Reference pGivenDataSeries = dynamic_cast(xGivenDataSeries.get()); + assert(pGivenDataSeries || !xGivenDataSeries); + + bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed( + xDiagram, pGivenDataSeries, bForward, bDoMove ); + + return bIsMoveable; +} + +bool DiagramHelper::moveSeries( const rtl::Reference< Diagram >& xDiagram, const Reference< XDataSeries >& xGivenDataSeries, bool bForward ) +{ + const bool bDoMove = true; + + rtl::Reference pGivenDataSeries = dynamic_cast(xGivenDataSeries.get()); + assert(pGivenDataSeries || !xGivenDataSeries); + + bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed( + xDiagram, pGivenDataSeries, bForward, bDoMove ); + + return bMoved; +} + +bool DiagramHelper::isSupportingFloorAndWall( const rtl::Reference< Diagram >& xDiagram ) +{ + //pies and donuts currently do not support this because of wrong files from older versions + //todo: allow this in future again, if fileversion is available for OLE objects (metastream) + //thus the wrong bottom can be removed on import + + const std::vector< rtl::Reference< ChartType > > aTypes( + ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ) ); + for( rtl::Reference< ChartType > const & xType : aTypes ) + { + if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + return false; + if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + return false; + if( xType.is() && xType->getChartType().match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + return false; + } + return true; +} + +bool DiagramHelper::isPieOrDonutChart( const rtl::Reference< Diagram >& xDiagram ) +{ + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( + xDiagram, 0 ) ); + + if( xChartType .is() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE ) + return true; + } + return false; +} + +sal_Int32 DiagramHelper::getGeometry3D( + const rtl::Reference< Diagram > & xDiagram, + bool& rbFound, bool& rbAmbiguous ) +{ + sal_Int32 nCommonGeom( DataPointGeometry3D::CUBOID ); + rbFound = false; + rbAmbiguous = false; + + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + if( aSeriesVec.empty()) + rbAmbiguous = true; + + for (auto const& series : aSeriesVec) + { + try + { + sal_Int32 nGeom = 0; + if( series->getPropertyValue( "Geometry3D") >>= nGeom ) + { + if( ! rbFound ) + { + // first series + nCommonGeom = nGeom; + rbFound = true; + } + // further series: compare for uniqueness + else if( nCommonGeom != nGeom ) + { + rbAmbiguous = true; + break; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nCommonGeom; +} + +void DiagramHelper::setGeometry3D( + const rtl::Reference< Diagram > & xDiagram, + sal_Int32 nNewGeometry ) +{ + std::vector< rtl::Reference< DataSeries > > aSeriesVec = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& series : aSeriesVec) + { + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( + series, "Geometry3D", uno::Any( nNewGeometry )); + } +} + +sal_Int32 DiagramHelper::getCorrectedMissingValueTreatment( + const rtl::Reference< Diagram > & xDiagram, + const rtl::Reference< ChartType >& xChartType ) +{ + sal_Int32 nResult = css::chart::MissingValueTreatment::LEAVE_GAP; + const uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments( + ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) ); + + if( xDiagram.is() && (xDiagram->getPropertyValue( "MissingValueTreatment" ) >>= nResult) ) + { + //ensure that the set value is supported by this charttype + for( sal_Int32 n : aAvailableMissingValueTreatments ) + if( n == nResult ) + return nResult; //ok + } + + //otherwise use the first supported one + if( aAvailableMissingValueTreatments.hasElements() ) + { + nResult = aAvailableMissingValueTreatments[0]; + return nResult; + } + + return nResult; +} + +DiagramPositioningMode DiagramHelper::getDiagramPositioningMode( const rtl::Reference< + Diagram > & xDiagram ) +{ + DiagramPositioningMode eMode = DiagramPositioningMode_AUTO; + if( xDiagram.is() ) + { + RelativePosition aRelPos; + RelativeSize aRelSize; + if( (xDiagram->getPropertyValue("RelativePosition") >>= aRelPos ) && + (xDiagram->getPropertyValue("RelativeSize") >>= aRelSize ) ) + { + bool bPosSizeExcludeAxes=false; + xDiagram->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxes; + if( bPosSizeExcludeAxes ) + eMode = DiagramPositioningMode_EXCLUDING; + else + eMode = DiagramPositioningMode_INCLUDING; + } + } + return eMode; +} + +static void lcl_ensureRange0to1( double& rValue ) +{ + if(rValue<0.0) + rValue=0.0; + if(rValue>1.0) + rValue=1.0; +} + +bool DiagramHelper::setDiagramPositioning( const rtl::Reference<::chart::ChartModel>& xChartModel, + const awt::Rectangle& rPosRect /*100th mm*/ ) +{ + ControllerLockGuardUNO aCtrlLockGuard( xChartModel ); + + bool bChanged = false; + awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) ); + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + if( !xDiagram.is() ) + return bChanged; + + RelativePosition aOldPos; + RelativeSize aOldSize; + xDiagram->getPropertyValue("RelativePosition" ) >>= aOldPos; + xDiagram->getPropertyValue("RelativeSize" ) >>= aOldSize; + + RelativePosition aNewPos; + aNewPos.Anchor = drawing::Alignment_TOP_LEFT; + aNewPos.Primary = double(rPosRect.X)/double(aPageSize.Width); + aNewPos.Secondary = double(rPosRect.Y)/double(aPageSize.Height); + + chart2::RelativeSize aNewSize; + aNewSize.Primary = double(rPosRect.Width)/double(aPageSize.Width); + aNewSize.Secondary = double(rPosRect.Height)/double(aPageSize.Height); + + lcl_ensureRange0to1( aNewPos.Primary ); + lcl_ensureRange0to1( aNewPos.Secondary ); + lcl_ensureRange0to1( aNewSize.Primary ); + lcl_ensureRange0to1( aNewSize.Secondary ); + if( (aNewPos.Primary + aNewSize.Primary) > 1.0 ) + aNewPos.Primary = 1.0 - aNewSize.Primary; + if( (aNewPos.Secondary + aNewSize.Secondary) > 1.0 ) + aNewPos.Secondary = 1.0 - aNewSize.Secondary; + + xDiagram->setPropertyValue( "RelativePosition", uno::Any(aNewPos) ); + xDiagram->setPropertyValue( "RelativeSize", uno::Any(aNewSize) ); + + bChanged = (aOldPos.Anchor!=aNewPos.Anchor) || + (aOldPos.Primary!=aNewPos.Primary) || + (aOldPos.Secondary!=aNewPos.Secondary) || + (aOldSize.Primary!=aNewSize.Primary) || + (aOldSize.Secondary!=aNewSize.Secondary); + return bChanged; +} + +awt::Rectangle DiagramHelper::getDiagramRectangleFromModel( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + awt::Rectangle aRet(-1,-1,-1,-1); + + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartModel ); + if( !xDiagram.is() ) + return aRet; + + awt::Size aPageSize( ChartModelHelper::getPageSize(xChartModel) ); + + RelativePosition aRelPos; + RelativeSize aRelSize; + xDiagram->getPropertyValue("RelativePosition" ) >>= aRelPos; + xDiagram->getPropertyValue("RelativeSize" ) >>= aRelSize; + + awt::Size aAbsSize( + static_cast< sal_Int32 >( aRelSize.Primary * aPageSize.Width ), + static_cast< sal_Int32 >( aRelSize.Secondary * aPageSize.Height )); + + awt::Point aAbsPos( + static_cast< sal_Int32 >( aRelPos.Primary * aPageSize.Width ), + static_cast< sal_Int32 >( aRelPos.Secondary * aPageSize.Height )); + + awt::Point aAbsPosLeftTop = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( aAbsPos, aAbsSize, aRelPos.Anchor ); + + aRet = awt::Rectangle(aAbsPosLeftTop.X, aAbsPosLeftTop.Y, aAbsSize.Width, aAbsSize.Height ); + + return aRet; +} + +bool DiagramHelper::switchDiagramPositioningToExcludingPositioning( + ChartModel& rModel, bool bResetModifiedState, bool bConvertAlsoFromAutoPositioning ) +{ + //return true if something was changed + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(GetODFSaneDefaultVersion()); + if (SvtSaveOptions::ODFSVER_012 < nCurrentODFVersion) + { + uno::Reference< css::chart::XDiagramPositioning > xDiagramPositioning( rModel.getFirstDiagram(), uno::UNO_QUERY ); + if( xDiagramPositioning.is() && ( bConvertAlsoFromAutoPositioning || !xDiagramPositioning->isAutomaticDiagramPositioning() ) + && !xDiagramPositioning->isExcludingDiagramPositioning() ) + { + ControllerLockGuard aCtrlLockGuard( rModel ); + bool bModelWasModified = rModel.isModified(); + xDiagramPositioning->setDiagramPositionExcludingAxes( xDiagramPositioning->calculateDiagramPositionExcludingAxes() ); + if(bResetModifiedState && !bModelWasModified ) + rModel.setModified(false); + return true; + } + } + return false; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ErrorBar.cxx b/chart2/source/tools/ErrorBar.cxx new file mode 100644 index 000000000..f55b0637d --- /dev/null +++ b/chart2/source/tools/ErrorBar.cxx @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace +{ + +constexpr OUStringLiteral lcl_aServiceName = u"com.sun.star.comp.chart2.ErrorBar"; + +bool lcl_isInternalData( const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq ) +{ + uno::Reference< lang::XServiceInfo > xServiceInfo( xLSeq, uno::UNO_QUERY ); + return ( xServiceInfo.is() && xServiceInfo->getImplementationName() == "com.sun.star.comp.chart2.LabeledDataSequence" ); +} + +const SfxItemPropertySet* GetErrorBarPropertySet() +{ + static const SfxItemPropertyMapEntry aErrorBarPropertyMap_Impl[] = + { + {u"ShowPositiveError",0,cppu::UnoType::get(), 0, 0}, + {u"ShowNegativeError",1,cppu::UnoType::get(), 0, 0}, + {u"PositiveError",2,cppu::UnoType::get(),0,0}, + {u"NegativeError",3,cppu::UnoType::get(), 0, 0}, + {u"PercentageError",4,cppu::UnoType::get(), 0, 0}, + {u"ErrorBarStyle",5,cppu::UnoType::get(),0,0}, + {u"ErrorBarRangePositive",6,cppu::UnoType::get(),0,0}, // read-only for export + {u"ErrorBarRangeNegative",7,cppu::UnoType::get(),0,0}, // read-only for export + {u"Weight",8,cppu::UnoType::get(),0,0}, + {u"LineStyle",9,cppu::UnoType::get(),0,0}, + {u"LineDash",10,cppu::UnoType::get(),0,0}, + {u"LineWidth",11,cppu::UnoType::get(),0,0}, + {u"LineColor",12,cppu::UnoType::get(),0,0}, + {u"LineTransparence",13,cppu::UnoType::get(),0,0}, + {u"LineJoint",14,cppu::UnoType::get(),0,0}, + { u"", 0, css::uno::Type(), 0, 0 } + }; + static SfxItemPropertySet aPropSet( aErrorBarPropertyMap_Impl ); + return &aPropSet; +} + +} // anonymous namespace + +namespace chart +{ + +ErrorBar::ErrorBar() : + mnLineWidth(0), + meLineStyle(drawing::LineStyle_SOLID), + maLineColor(0), + mnLineTransparence(0), + meLineJoint(drawing::LineJoint_ROUND), + mbShowPositiveError(true), + mbShowNegativeError(true), + mfPositiveError(0), + mfNegativeError(0), + mfWeight(1), + meStyle(css::chart::ErrorBarStyle::NONE), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +ErrorBar::ErrorBar( const ErrorBar & rOther ) : + impl::ErrorBar_Base(rOther), + maDashName(rOther.maDashName), + maLineDash(rOther.maLineDash), + mnLineWidth(rOther.mnLineWidth), + meLineStyle(rOther.meLineStyle), + maLineColor(rOther.maLineColor), + mnLineTransparence(rOther.mnLineTransparence), + meLineJoint(rOther.meLineJoint), + mbShowPositiveError(rOther.mbShowPositiveError), + mbShowNegativeError(rOther.mbShowNegativeError), + mfPositiveError(rOther.mfPositiveError), + mfNegativeError(rOther.mfNegativeError), + mfWeight(rOther.mfWeight), + meStyle(rOther.meStyle), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + if( ! rOther.m_aDataSequences.empty()) + { + if( lcl_isInternalData( rOther.m_aDataSequences.front())) + CloneHelper::CloneRefVector< css::chart2::data::XLabeledDataSequence >( + rOther.m_aDataSequences, m_aDataSequences ); + else + m_aDataSequences = rOther.m_aDataSequences; + ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); + } +} + +ErrorBar::~ErrorBar() +{} + +uno::Reference< util::XCloneable > SAL_CALL ErrorBar::createClone() +{ + return uno::Reference< util::XCloneable >( new ErrorBar( *this )); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL ErrorBar::getPropertySetInfo() +{ + static uno::Reference< beans::XPropertySetInfo > aRef ( + new SfxItemPropertySetInfo( GetErrorBarPropertySet()->getPropertyMap() ) ); + return aRef; +} + +void ErrorBar::setPropertyValue( const OUString& rPropName, const uno::Any& rAny ) +{ + SolarMutexGuard aGuard; + + if(rPropName == "ErrorBarStyle") + rAny >>= meStyle; + else if(rPropName == "PositiveError") + rAny >>= mfPositiveError; + else if(rPropName == "PercentageError") + { + rAny >>= mfPositiveError; + rAny >>= mfNegativeError; + } + else if(rPropName == "Weight") + { + rAny >>= mfWeight; + } + else if(rPropName == "NegativeError") + rAny >>= mfNegativeError; + else if(rPropName == "ShowPositiveError") + rAny >>= mbShowPositiveError; + else if(rPropName == "ShowNegativeError") + rAny >>= mbShowNegativeError; + else if(rPropName == "ErrorBarRangePositive" || rPropName == "ErrorBarRangeNegative") + throw beans::UnknownPropertyException("read-only property", static_cast< uno::XWeak*>(this)); + else if(rPropName == "LineDashName") + rAny >>= maDashName; + else if(rPropName == "LineDash") + rAny >>= maLineDash; + else if(rPropName == "LineWidth") + rAny >>= mnLineWidth; + else if(rPropName == "LineStyle") + rAny >>= meLineStyle; + else if(rPropName == "LineColor") + rAny >>= maLineColor; + else if(rPropName == "LineTransparence") + rAny >>= mnLineTransparence; + else if(rPropName == "LineJoint") + rAny >>= meLineJoint; + + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +namespace { + +OUString getSourceRangeStrFromLabeledSequences( const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aSequences, bool bPositive ) +{ + OUString aDirection; + if(bPositive) + aDirection = "positive"; + else + aDirection = "negative"; + + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labeledData : aSequences ) + { + try + { + if( labeledData.is()) + { + uno::Reference< chart2::data::XDataSequence > xSequence( labeledData->getValues()); + uno::Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW ); + OUString aRole; + if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) && + aRole.match( "error-bars" ) && aRole.indexOf(aDirection) >= 0 ) + { + return xSequence->getSourceRangeRepresentation(); + } + } + } + catch (uno::Exception const &) + { + // we can't be sure that this is 100% safe and we don't want to kill the export + // we should at least check why the exception is thrown + TOOLS_WARN_EXCEPTION("chart2", "unexpected exception"); + } + catch (...) + { + // we can't be sure that this is 100% safe and we don't want to kill the export + // we should at least check why the exception is thrown + SAL_WARN("chart2", "unexpected exception! "); + } + } + + return OUString(); +} + +} + +uno::Any ErrorBar::getPropertyValue(const OUString& rPropName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + if(rPropName == "ErrorBarStyle") + aRet <<= meStyle; + else if(rPropName == "PositiveError") + aRet <<= mfPositiveError; + else if(rPropName == "NegativeError") + aRet <<= mfNegativeError; + else if(rPropName == "PercentageError") + aRet <<= mfPositiveError; + else if(rPropName == "ShowPositiveError") + aRet <<= mbShowPositiveError; + else if(rPropName == "ShowNegativeError") + aRet <<= mbShowNegativeError; + else if(rPropName == "Weight") + aRet <<= mfWeight; + else if(rPropName == "ErrorBarRangePositive") + { + OUString aRange; + if(meStyle == css::chart::ErrorBarStyle::FROM_DATA) + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences = + getDataSequences(); + + aRange = getSourceRangeStrFromLabeledSequences( aSequences, true ); + } + + aRet <<= aRange; + } + else if(rPropName == "ErrorBarRangeNegative") + { + OUString aRange; + if(meStyle == css::chart::ErrorBarStyle::FROM_DATA) + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences = + getDataSequences(); + + aRange = getSourceRangeStrFromLabeledSequences( aSequences, false ); + } + + aRet <<= aRange; + } + else if(rPropName == "LineDashName") + aRet <<= maDashName; + else if(rPropName == "LineDash") + aRet <<= maLineDash; + else if(rPropName == "LineWidth") + aRet <<= mnLineWidth; + else if(rPropName == "LineStyle") + aRet <<= meLineStyle; + else if(rPropName == "LineColor") + aRet <<= maLineColor; + else if(rPropName == "LineTransparence") + aRet <<= mnLineTransparence; + else if(rPropName == "LineJoint") + aRet <<= meLineJoint; + + SAL_WARN_IF(!aRet.hasValue(), "chart2", "asked for property value: " << rPropName); + return aRet; +} + +beans::PropertyState ErrorBar::getPropertyState( const OUString& rPropName ) +{ + if(rPropName == "ErrorBarStyle") + { + if(meStyle == css::chart::ErrorBarStyle::NONE) + return beans::PropertyState_DEFAULT_VALUE; + return beans::PropertyState_DIRECT_VALUE; + } + else if(rPropName == "PositiveError") + { + if(mbShowPositiveError) + { + switch(meStyle) + { + case css::chart::ErrorBarStyle::ABSOLUTE: + case css::chart::ErrorBarStyle::ERROR_MARGIN: + return beans::PropertyState_DIRECT_VALUE; + default: + break; + } + } + return beans::PropertyState_DEFAULT_VALUE; + } + else if(rPropName == "NegativeError") + { + if(mbShowNegativeError) + { + switch(meStyle) + { + case css::chart::ErrorBarStyle::ABSOLUTE: + case css::chart::ErrorBarStyle::ERROR_MARGIN: + return beans::PropertyState_DIRECT_VALUE; + default: + break; + } + } + return beans::PropertyState_DEFAULT_VALUE; + } + else if(rPropName == "PercentageError") + { + if(meStyle != css::chart::ErrorBarStyle::RELATIVE) + return beans::PropertyState_DEFAULT_VALUE; + return beans::PropertyState_DIRECT_VALUE; + } + else if(rPropName == "ShowPositiveError") + { + // this value should be never default + return beans::PropertyState_DIRECT_VALUE; + } + else if(rPropName == "ShowNegativeError") + { + // this value should be never default + return beans::PropertyState_DIRECT_VALUE; + } + else if(rPropName == "ErrorBarRangePositive") + { + if(meStyle == css::chart::ErrorBarStyle::FROM_DATA && mbShowPositiveError) + return beans::PropertyState_DIRECT_VALUE; + return beans::PropertyState_DEFAULT_VALUE; + } + else if(rPropName == "ErrorBarRangeNegative") + { + if(meStyle == css::chart::ErrorBarStyle::FROM_DATA && mbShowNegativeError) + return beans::PropertyState_DIRECT_VALUE; + return beans::PropertyState_DEFAULT_VALUE; + } + else + return beans::PropertyState_DIRECT_VALUE; +} + +uno::Sequence< beans::PropertyState > ErrorBar::getPropertyStates( const uno::Sequence< OUString >& rPropNames ) +{ + uno::Sequence< beans::PropertyState > aRet( rPropNames.getLength() ); + auto aRetRange = asNonConstRange(aRet); + for(sal_Int32 i = 0; i < rPropNames.getLength(); ++i) + { + aRetRange[i] = getPropertyState(rPropNames[i]); + } + return aRet; +} + +void ErrorBar::setPropertyToDefault( const OUString& ) +{ + //keep them unimplemented for now +} + +uno::Any ErrorBar::getPropertyDefault( const OUString& ) +{ + //keep them unimplemented for now + return uno::Any(); +} + +void ErrorBar::addPropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) +{ +} + +void ErrorBar::removePropertyChangeListener( const OUString&, const css::uno::Reference< css::beans::XPropertyChangeListener >& ) +{ +} + +void ErrorBar::addVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) +{ +} + +void ErrorBar::removeVetoableChangeListener( const OUString&, const css::uno::Reference< css::beans::XVetoableChangeListener >& ) +{ +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL ErrorBar::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL ErrorBar::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL ErrorBar::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL ErrorBar::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ XDataSink ____ +void SAL_CALL ErrorBar::setData( const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > >& aData ) +{ + ModifyListenerHelper::removeListenerFromAllElements( m_aDataSequences, m_xModifyEventForwarder ); + EventListenerHelper::removeListenerFromAllElements( m_aDataSequences, this ); + m_aDataSequences = comphelper::sequenceToContainer( aData ); + EventListenerHelper::addListenerToAllElements( m_aDataSequences, this ); + ModifyListenerHelper::addListenerToAllElements( m_aDataSequences, m_xModifyEventForwarder ); +} + +// ____ XDataSource ____ +uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > SAL_CALL ErrorBar::getDataSequences() +{ + return comphelper::containerToSequence( m_aDataSequences ); +} + +OUString SAL_CALL ErrorBar::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL ErrorBar::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ErrorBar::getSupportedServiceNames() +{ + return { + lcl_aServiceName, + "com.sun.star.chart2.ErrorBar" + }; +} + +// needed by MSC compiler +using impl::ErrorBar_Base; + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ErrorBar_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ErrorBar); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ExplicitCategoriesProvider.cxx b/chart2/source/tools/ExplicitCategoriesProvider.cxx new file mode 100644 index 000000000..2a4eee8a7 --- /dev/null +++ b/chart2/source/tools/ExplicitCategoriesProvider.cxx @@ -0,0 +1,564 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +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 std::vector; + +ExplicitCategoriesProvider::ExplicitCategoriesProvider( const rtl::Reference< BaseCoordinateSystem >& xCooSysModel + , ChartModel& rModel ) + : m_bDirty(true) + , m_xCooSysModel( xCooSysModel.get() ) + , mrModel(rModel) + , m_bIsExplicitCategoriesInited(false) + , m_bIsDateAxis(false) + , m_bIsAutoDate(false) +{ + try + { + if( xCooSysModel.is() ) + { + // TODO: handle different category names on the primary and secondary category axis. + rtl::Reference< Axis > xAxis = xCooSysModel->getAxisByDimension2(0,0); + if( xAxis.is() ) + { + ScaleData aScale( xAxis->getScaleData() ); + m_xOriginalCategories = aScale.Categories; + m_bIsAutoDate = (aScale.AutoDateAxis && aScale.AxisType==chart2::AxisType::CATEGORY); + m_bIsDateAxis = (aScale.AxisType == chart2::AxisType::DATE || m_bIsAutoDate); + } + } + + if( m_xOriginalCategories.is() ) + { + uno::Reference< data::XDataProvider > xDataProvider( mrModel.getDataProvider() ); + + OUString aCategoriesRange( DataSourceHelper::getRangeFromValues( m_xOriginalCategories ) ); + if( xDataProvider.is() && !aCategoriesRange.isEmpty() ) + { + const bool bFirstCellAsLabel = false; + const bool bHasCategories = false; + const uno::Sequence< sal_Int32 > aSequenceMapping; + + uno::Reference< data::XDataSource > xColumnCategoriesSource( xDataProvider->createDataSource( + DataSourceHelper::createArguments( aCategoriesRange, aSequenceMapping, true /*bUseColumns*/ + , bFirstCellAsLabel, bHasCategories ) ) ); + + uno::Reference< data::XDataSource > xRowCategoriesSource( xDataProvider->createDataSource( + DataSourceHelper::createArguments( aCategoriesRange, aSequenceMapping, false /*bUseColumns*/ + , bFirstCellAsLabel, bHasCategories ) ) ); + + if( xColumnCategoriesSource.is() && xRowCategoriesSource.is() ) + { + Sequence< Reference< data::XLabeledDataSequence> > aColumns = xColumnCategoriesSource->getDataSequences(); + Sequence< Reference< data::XLabeledDataSequence> > aRows = xRowCategoriesSource->getDataSequences(); + + sal_Int32 nColumnCount = aColumns.getLength(); + sal_Int32 nRowCount = aRows.getLength(); + if( nColumnCount>1 && nRowCount>1 ) + { + //we have complex categories + //->split them in the direction of the first series + //detect whether the first series is a row or a column + bool bSeriesUsesColumns = true; + std::vector< rtl::Reference< DataSeries > > aSeries = ChartModelHelper::getDataSeries( &mrModel ); + if( !aSeries.empty() ) + { + rtl::Reference< DataSeries > xSeriesSource = aSeries.front(); + OUString aStringDummy; + bool bDummy; + uno::Sequence< sal_Int32 > aSeqDummy; + DataSourceHelper::readArguments( xDataProvider->detectArguments( xSeriesSource), + aStringDummy, aSeqDummy, bSeriesUsesColumns, bDummy, bDummy ); + } + if( bSeriesUsesColumns ) + m_aSplitCategoriesList = comphelper::sequenceToContainer>>(aColumns); + else + m_aSplitCategoriesList = comphelper::sequenceToContainer>>(aRows); + } + } + } + if( m_aSplitCategoriesList.empty() ) + { + m_aSplitCategoriesList = { m_xOriginalCategories }; + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +ExplicitCategoriesProvider::~ExplicitCategoriesProvider() +{ +} + +Reference< chart2::data::XDataSequence > ExplicitCategoriesProvider::getOriginalCategories() +{ + if( m_xOriginalCategories.is() ) + return m_xOriginalCategories->getValues(); + return nullptr; +} + +bool ExplicitCategoriesProvider::hasComplexCategories() const +{ + return m_aSplitCategoriesList.size() > 1; +} + +sal_Int32 ExplicitCategoriesProvider::getCategoryLevelCount() const +{ + sal_Int32 nCount = m_aSplitCategoriesList.size(); + if(!nCount) + nCount = 1; + return nCount; +} + +static std::vector lcl_getLimitingBorders( const std::vector< ComplexCategory >& rComplexCategories ) +{ + std::vector aLimitingBorders; + sal_Int32 nBorderIndex = 0; /*border below the index*/ + for (auto const& complexCategory : rComplexCategories) + { + nBorderIndex += complexCategory.Count; + aLimitingBorders.push_back(nBorderIndex); + } + return aLimitingBorders; +} + +void ExplicitCategoriesProvider::convertCategoryAnysToText( uno::Sequence< OUString >& rOutTexts, const uno::Sequence< uno::Any >& rInAnys, ChartModel& rModel ) +{ + sal_Int32 nCount = rInAnys.getLength(); + if(!nCount) + return; + rOutTexts.realloc(nCount); + auto pOutTexts = rOutTexts.getArray(); + + sal_Int32 nAxisNumberFormat = 0; + rtl::Reference< BaseCoordinateSystem > xCooSysModel( ChartModelHelper::getFirstCoordinateSystem( &rModel ) ); + if( xCooSysModel.is() ) + { + rtl::Reference< Axis > xAxis = xCooSysModel->getAxisByDimension2(0,0); + nAxisNumberFormat = AxisHelper::getExplicitNumberFormatKeyForAxis( + xAxis, xCooSysModel, &rModel, false ); + } + + Color nLabelColor; + bool bColorChanged = false; + + NumberFormatterWrapper aNumberFormatterWrapper( rModel.getNumberFormatsSupplier() ); + + for(sal_Int32 nN=0;nN>=fDouble ) + { + if( !std::isnan(fDouble) ) + aText = aNumberFormatterWrapper.getFormattedString( + nAxisNumberFormat, fDouble, nLabelColor, bColorChanged ); + } + else + { + aAny>>=aText; + } + } + pOutTexts[nN] = aText; + } +} + +SplitCategoriesProvider::~SplitCategoriesProvider() +{ +} + +namespace { + +class SplitCategoriesProvider_ForLabeledDataSequences : public SplitCategoriesProvider +{ +public: + + explicit SplitCategoriesProvider_ForLabeledDataSequences( + const std::vector< Reference< data::XLabeledDataSequence> >& rSplitCategoriesList + , ChartModel& rModel ) + : m_rSplitCategoriesList( rSplitCategoriesList ) + , mrModel( rModel ) + {} + + virtual sal_Int32 getLevelCount() const override; + virtual uno::Sequence< OUString > getStringsForLevel( sal_Int32 nIndex ) const override; + +private: + const std::vector< Reference< data::XLabeledDataSequence> >& m_rSplitCategoriesList; + + ChartModel& mrModel; +}; + +} + +sal_Int32 SplitCategoriesProvider_ForLabeledDataSequences::getLevelCount() const +{ + return m_rSplitCategoriesList.size(); +} +uno::Sequence< OUString > SplitCategoriesProvider_ForLabeledDataSequences::getStringsForLevel( sal_Int32 nLevel ) const +{ + uno::Sequence< OUString > aRet; + Reference< data::XLabeledDataSequence > xLabeledDataSequence( m_rSplitCategoriesList[nLevel] ); + if( xLabeledDataSequence.is() ) + { + uno::Reference< data::XDataSequence > xDataSequence( xLabeledDataSequence->getValues() ); + if( xDataSequence.is() ) + ExplicitCategoriesProvider::convertCategoryAnysToText( aRet, xDataSequence->getData(), mrModel ); + } + return aRet; +} + +static std::vector< ComplexCategory > lcl_DataSequenceToComplexCategoryVector( + const uno::Sequence< OUString >& rStrings + , const std::vector& rLimitingBorders, bool bCreateSingleCategories ) +{ + std::vector< ComplexCategory > aResult; + + sal_Int32 nMaxCount = rStrings.getLength(); + OUString aPrevious; + sal_Int32 nCurrentCount=0; + for( sal_Int32 nN=0; nN& rComplexCategories ) +{ + sal_Int32 nCount = 0; + for (auto const& complexCategory : rComplexCategories) + nCount+=complexCategory.Count; + return nCount; +} + +static Sequence< OUString > lcl_getExplicitSimpleCategories( + const SplitCategoriesProvider& rSplitCategoriesProvider, + std::vector< std::vector< ComplexCategory > >& rComplexCats ) +{ + Sequence< OUString > aRet; + + rComplexCats.clear(); + sal_Int32 nLCount = rSplitCategoriesProvider.getLevelCount(); + for( sal_Int32 nL = 0; nL < nLCount; nL++ ) + { + std::vector aLimitingBorders; + if(nL>0) + aLimitingBorders = lcl_getLimitingBorders( rComplexCats.back() ); + rComplexCats.push_back( lcl_DataSequenceToComplexCategoryVector( + rSplitCategoriesProvider.getStringsForLevel(nL), aLimitingBorders, nL==(nLCount-1) ) ); + } + + //ensure that the category count is the same on each level + sal_Int32 nMaxCategoryCount = 0; + { + for (auto & complexCat : rComplexCats) + { + sal_Int32 nCurrentCount = lcl_getCategoryCount(complexCat); + nMaxCategoryCount = std::max( nCurrentCount, nMaxCategoryCount ); + } + for (auto & complexCat : rComplexCats) + { + if ( !complexCat.empty() ) + { + sal_Int32 nCurrentCount = lcl_getCategoryCount(complexCat); + if( nCurrentCount< nMaxCategoryCount ) + { + ComplexCategory& rComplexCategory = complexCat.back(); + rComplexCategory.Count += (nMaxCategoryCount-nCurrentCount); + } + } + } + } + + //create a list with an element for every index + std::vector< std::vector< ComplexCategory > > aComplexCatsPerIndex; + for (auto const& complexCat : rComplexCats) + { + std::vector< ComplexCategory > aSingleLevel; + for (auto const& elem : complexCat) + { + sal_Int32 nCount = elem.Count; + while( nCount-- ) + aSingleLevel.push_back(elem); + } + aComplexCatsPerIndex.push_back( aSingleLevel ); + } + + if(nMaxCategoryCount) + { + aRet.realloc(nMaxCategoryCount); + auto pRet = aRet.getArray(); + for(sal_Int32 nN=0; nN ExplicitCategoriesProvider::getExplicitSimpleCategories( + const SplitCategoriesProvider& rSplitCategoriesProvider ) +{ + vector< vector< ComplexCategory > > aComplexCats; + return lcl_getExplicitSimpleCategories( rSplitCategoriesProvider, aComplexCats ); +} + +static bool lcl_fillDateCategories( const uno::Reference< data::XDataSequence >& xDataSequence, std::vector< double >& rDateCategories, bool bIsAutoDate, ChartModel& rModel ) +{ + bool bOnlyDatesFound = true; + bool bAnyDataFound = false; + + if( xDataSequence.is() ) + { + uno::Sequence< uno::Any > aValues = xDataSequence->getData(); + sal_Int32 nCount = aValues.getLength(); + rDateCategories.reserve(nCount); + Reference< util::XNumberFormats > xNumberFormats( rModel.getNumberFormats() ); + + bool bOwnData = false; + bool bOwnDataAnddAxisHasAnyFormat = false; + bool bOwnDataAnddAxisHasDateFormat = false; + rtl::Reference< BaseCoordinateSystem > xCooSysModel( ChartModelHelper::getFirstCoordinateSystem( &rModel ) ); + if( xCooSysModel.is() ) + { + if( rModel.hasInternalDataProvider() ) + { + bOwnData = true; + rtl::Reference< Axis > xAxisProps = xCooSysModel->getAxisByDimension2(0,0); + sal_Int32 nAxisNumberFormat = 0; + if (xAxisProps.is() && (xAxisProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nAxisNumberFormat)) + { + bOwnDataAnddAxisHasAnyFormat = true; + bOwnDataAnddAxisHasDateFormat = DiagramHelper::isDateNumberFormat( nAxisNumberFormat, xNumberFormats ); + } + } + } + + for(sal_Int32 nN=0;nNgetNumberFormatKeyByIndex( nN ), xNumberFormats ); + } + else + bIsDate = true; + + bool bContainsEmptyString = false; + uno::Any aAny = aValues[nN]; + if( aAny.hasValue() ) + { + OUString aTest; + double fTest = 0; + bool bContainsNan = false; + if( (aAny>>=aTest) && aTest.isEmpty() ) //empty String + bContainsEmptyString = true; + else if( (aAny>>=fTest) && std::isnan(fTest) ) + bContainsNan = true; + + if( !bContainsEmptyString && !bContainsNan ) + bAnyDataFound = true; + } + double aDate( 1.0 ); + if( bIsDate && (aAny >>= aDate) ) + rDateCategories.push_back( aDate ); + else + { + if( aAny.hasValue() && !bContainsEmptyString )//empty string does not count as non date value! + bOnlyDatesFound=false; + rDateCategories.push_back( std::numeric_limits::quiet_NaN() ); + } + } + std::sort( rDateCategories.begin(), rDateCategories.end() ); + } + + return bAnyDataFound && bOnlyDatesFound; +} + +void ExplicitCategoriesProvider::init() +{ + if( !m_bDirty ) + return; + + m_aComplexCats.clear();//not one per index + m_aDateCategories.clear(); + + if( m_xOriginalCategories.is() ) + { + if( !hasComplexCategories() ) + { + if(m_bIsDateAxis) + { + if( ChartTypeHelper::isSupportingDateAxis( AxisHelper::getChartTypeByIndex( m_xCooSysModel.get(), 0 ), 0 ) ) + m_bIsDateAxis = lcl_fillDateCategories( m_xOriginalCategories->getValues(), m_aDateCategories, m_bIsAutoDate, mrModel ); + else + m_bIsDateAxis = false; + } + } + else + { + m_bIsDateAxis = false; + } + } + else + m_bIsDateAxis=false; + m_bDirty = false; +} + +Sequence< OUString > const & ExplicitCategoriesProvider::getSimpleCategories() +{ + if( !m_bIsExplicitCategoriesInited ) + { + init(); + m_aExplicitCategories.realloc(0); + if( m_xOriginalCategories.is() ) + { + if( !hasComplexCategories() ) + { + uno::Reference< data::XDataSequence > xDataSequence( m_xOriginalCategories->getValues() ); + if( xDataSequence.is() ) + ExplicitCategoriesProvider::convertCategoryAnysToText( m_aExplicitCategories, xDataSequence->getData(), mrModel ); + } + else + { + m_aExplicitCategories = lcl_getExplicitSimpleCategories( + SplitCategoriesProvider_ForLabeledDataSequences( m_aSplitCategoriesList, mrModel ), m_aComplexCats ); + } + } + if(!m_aExplicitCategories.hasElements()) + m_aExplicitCategories = DiagramHelper::generateAutomaticCategoriesFromCooSys( m_xCooSysModel.get() ); + m_bIsExplicitCategoriesInited = true; + } + return m_aExplicitCategories; +} + +const std::vector* ExplicitCategoriesProvider::getCategoriesByLevel( sal_Int32 nLevel ) +{ + init(); + sal_Int32 nMaxIndex = m_aComplexCats.size()-1; + if (nLevel >= 0 && nLevel <= nMaxIndex) + return &m_aComplexCats[nMaxIndex-nLevel]; + return nullptr; +} + +OUString ExplicitCategoriesProvider::getCategoryByIndex( + const rtl::Reference< BaseCoordinateSystem >& xCooSysModel + , ChartModel& rModel + , sal_Int32 nIndex ) +{ + if( xCooSysModel.is()) + { + ExplicitCategoriesProvider aExplicitCategoriesProvider( xCooSysModel, rModel ); + Sequence< OUString > aCategories( aExplicitCategoriesProvider.getSimpleCategories()); + if( nIndex < aCategories.getLength()) + return aCategories[ nIndex ]; + } + return OUString(); +} + +bool ExplicitCategoriesProvider::isDateAxis() +{ + init(); + return m_bIsDateAxis; +} + +const std::vector< double >& ExplicitCategoriesProvider::getDateCategories() +{ + init(); + return m_aDateCategories; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx b/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx new file mode 100644 index 000000000..9c41822d3 --- /dev/null +++ b/chart2/source/tools/ExponentialRegressionCurveCalculator.cxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +ExponentialRegressionCurveCalculator::ExponentialRegressionCurveCalculator() + : m_fLogSlope(std::numeric_limits::quiet_NaN()) + , m_fLogIntercept(std::numeric_limits::quiet_NaN()) + , m_fSign(1.0) +{ +} + +ExponentialRegressionCurveCalculator::~ExponentialRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL ExponentialRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) +{ + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValidAndYPositive())); + m_fSign = 1.0; + + size_t nMax = aValues.first.size(); + if( nMax <= 1 ) // at least 2 points + { + aValues = RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValidAndYNegative()); + nMax = aValues.first.size(); + if( nMax <= 1 ) + { + m_fLogSlope = std::numeric_limits::quiet_NaN(); + m_fLogIntercept = std::numeric_limits::quiet_NaN(); + m_fCorrelationCoefficient = std::numeric_limits::quiet_NaN();// actual it is coefficient of determination + return; + } + m_fSign = -1.0; + } + + double fAverageX = 0.0, fAverageY = 0.0; + double fLogIntercept = ( mForceIntercept && (m_fSign * mInterceptValue)>0 ) ? log(m_fSign * mInterceptValue) : 0.0; + std::vector yVector; + yVector.resize(nMax, 0.0); + + size_t i = 0; + for( i = 0; i < nMax; ++i ) + { + double yValue = log( m_fSign *aValues.second[i] ); + if (mForceIntercept) + { + yValue -= fLogIntercept; + } + else + { + fAverageX += aValues.first[i]; + fAverageY += yValue; + } + yVector[i] = yValue; + } + + const double fN = static_cast< double >( nMax ); + fAverageX /= fN; + fAverageY /= fN; + + double fQx = 0.0, fQy = 0.0, fQxy = 0.0; + for( i = 0; i < nMax; ++i ) + { + double fDeltaX = aValues.first[i] - fAverageX; + double fDeltaY = yVector[i] - fAverageY; + + fQx += fDeltaX * fDeltaX; + fQy += fDeltaY * fDeltaY; + fQxy += fDeltaX * fDeltaY; + } + + m_fLogSlope = fQxy / fQx; + m_fLogIntercept = mForceIntercept ? fLogIntercept : fAverageY - m_fLogSlope * fAverageX; + m_fCorrelationCoefficient = fQxy / sqrt( fQx * fQy ); +} + +double SAL_CALL ExponentialRegressionCurveCalculator::getCurveValue( double x ) +{ + if( ! ( std::isnan( m_fLogSlope ) || + std::isnan( m_fLogIntercept ))) + { + return m_fSign * exp(m_fLogIntercept + x * m_fLogSlope); + } + + return std::numeric_limits::quiet_NaN(); +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL ExponentialRegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) +{ + if( bMaySkipPointsInCalculation && + isLinearScaling( xScalingX ) && + isLogarithmicScaling( xScalingY )) + { + // optimize result + uno::Sequence< geometry::RealPoint2D > aResult{ { min, getCurveValue( min ) }, + { max, getCurveValue( max ) } }; + + return aResult; + } + + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +OUString ExponentialRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth /* = nullptr */ ) const +{ + double fIntercept = exp(m_fLogIntercept); + bool bHasSlope = !rtl::math::approxEqual( exp(m_fLogSlope), 1.0 ); + bool bHasLogSlope = !rtl::math::approxEqual( fabs(m_fLogSlope), 1.0 ); + bool bHasIntercept = !rtl::math::approxEqual( fIntercept, 1.0 ) && fIntercept != 0.0; + + OUStringBuffer aBuf( mYName + " = " ); + sal_Int32 nLineLength = aBuf.getLength(); + sal_Int32 nValueLength=0; + if ( pFormulaMaxWidth && *pFormulaMaxWidth > 0 ) + { // count characters different from coefficients + sal_Int32 nCharMin = nLineLength + 10 + mXName.getLength(); // 10 = "exp( ", " x )" + 2 extra characters + if ( m_fSign < 0.0 ) + nCharMin += 2; + if ( fIntercept == 0.0 || ( !bHasSlope && m_fLogIntercept != 0.0 ) ) + nCharMin += 3; // " + " special case where equation is written exp( a + b x ) + if ( ( bHasIntercept || fIntercept == 0.0 || ( !bHasSlope && m_fLogIntercept != 0.0 ) ) && + bHasLogSlope ) + nValueLength = ( *pFormulaMaxWidth - nCharMin ) / 2; + else + nValueLength = *pFormulaMaxWidth - nCharMin; + if ( nValueLength <= 0 ) + nValueLength = 1; + } + // temporary buffer + OUStringBuffer aTmpBuf(""); + // if nValueLength not calculated then nullptr + sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr; + if ( m_fSign < 0.0 ) + aTmpBuf.append( OUStringChar(aMinusSign) + " " ); + if ( bHasIntercept ) + { + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fIntercept, pValueLength ); + if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small + { + aTmpBuf.append( aValueString + " " ); + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + aTmpBuf.truncate(); + } + } + aTmpBuf.append( "exp( " ); + if ( !bHasIntercept ) + { + if ( fIntercept == 0.0 || // underflow, a true zero is impossible + ( !bHasSlope && m_fLogIntercept != 0.0 ) ) // show logarithmic output, if intercept and slope both are near one + { // otherwise drop output of intercept, which is 1 here + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogIntercept, pValueLength ); + if ( aValueString != "0" ) // aValueString may be rounded to 0 if nValueLength is small + { + aTmpBuf.append( aValueString ).append( (m_fLogSlope < 0.0) ? std::u16string_view(u" ") : std::u16string_view(u" + ") ); + } + } + } + if ( m_fLogSlope < 0.0 ) + aTmpBuf.append( OUStringChar(aMinusSign) + " " ); + if ( bHasLogSlope ) + { + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fLogSlope), pValueLength ); + if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small + { + aTmpBuf.append( aValueString + " " ); + } + } + aTmpBuf.append( mXName + " )"); + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/FillProperties.cxx b/chart2/source/tools/FillProperties.cxx new file mode 100644 index 000000000..d0c888d74 --- /dev/null +++ b/chart2/source/tools/FillProperties.cxx @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +namespace +{ + +void lcl_AddPropertiesToVector_without_BitmapProperties( std::vector< css::beans::Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "FillStyle", + FillProperties::PROP_FILL_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillColor", + FillProperties::PROP_FILL_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID // "maybe auto" + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillTransparence", + FillProperties::PROP_FILL_TRANSPARENCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillTransparenceGradientName", + FillProperties::PROP_FILL_TRANSPARENCE_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillGradientName", + FillProperties::PROP_FILL_GRADIENT_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillGradientStepCount", + FillProperties::PROP_FILL_GRADIENT_STEPCOUNT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "FillHatchName", + FillProperties::PROP_FILL_HATCH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + //bitmap properties see lcl_AddPropertiesToVector_only_BitmapProperties() + + rOutProperties.emplace_back( "FillBackground", + FillProperties::PROP_FILL_BACKGROUND, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void lcl_AddPropertiesToVector_only_BitmapProperties( std::vector< css::beans::Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "FillBitmapName", + FillProperties::PROP_FILL_BITMAP_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapOffsetX", + FillProperties::PROP_FILL_BITMAP_OFFSETX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapOffsetY", + FillProperties::PROP_FILL_BITMAP_OFFSETY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetX", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapPositionOffsetY", + FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapRectanglePoint", + FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapLogicalSize", + FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeX", + FillProperties::PROP_FILL_BITMAP_SIZEX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapSizeY", + FillProperties::PROP_FILL_BITMAP_SIZEY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "FillBitmapMode", + FillProperties::PROP_FILL_BITMAP_MODE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void lcl_AddDefaultsToMap_without_BitmapProperties( + ::chart::tPropertyValueMap & rOutMap ) +{ + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_STYLE, drawing::FillStyle_SOLID ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, FillProperties::PROP_FILL_COLOR, 0xd9d9d9 ); // gray85 + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_TRANSPARENCE, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BACKGROUND, false ); +} + +void lcl_AddDefaultsToMap_only_BitmapProperties( + ::chart::tPropertyValueMap & rOutMap ) +{ + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETX, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_OFFSETY, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETX, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, FillProperties::PROP_FILL_BITMAP_POSITION_OFFSETY, 0 ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_RECTANGLEPOINT, drawing::RectanglePoint_MIDDLE_MIDDLE ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_LOGICALSIZE, true ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEX, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, FillProperties::PROP_FILL_BITMAP_SIZEY, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, FillProperties::PROP_FILL_BITMAP_MODE, drawing::BitmapMode_REPEAT ); +} + +}//end anonymous namespace + +void FillProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // Fill Properties see service drawing::FillProperties + lcl_AddPropertiesToVector_without_BitmapProperties( rOutProperties ); + lcl_AddPropertiesToVector_only_BitmapProperties( rOutProperties ); +} + +void FillProperties::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + lcl_AddDefaultsToMap_without_BitmapProperties( rOutMap ); + lcl_AddDefaultsToMap_only_BitmapProperties( rOutMap ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/FormattedStringHelper.cxx b/chart2/source/tools/FormattedStringHelper.cxx new file mode 100644 index 000000000..755dd532b --- /dev/null +++ b/chart2/source/tools/FormattedStringHelper.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +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; + +Sequence< Reference< chart2::XFormattedString2 > > + FormattedStringHelper::createFormattedStringSequence( + const Reference< uno::XComponentContext > & xContext + , const OUString & rString + , const Reference< beans::XPropertySet > & xTextProperties ) noexcept +{ + Reference< XFormattedString2 > xFormStr; + try + { + if( xContext.is() ) + { + xFormStr = chart2::FormattedString::create(xContext); + + xFormStr->setString( rString ); + + // set character properties + comphelper::copyProperties( + xTextProperties, Reference< beans::XPropertySet >( xFormStr, uno::UNO_QUERY_THROW ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return Sequence< Reference< XFormattedString2 > >( & xFormStr, 1 ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/InternalData.cxx b/chart2/source/tools/InternalData.cxx new file mode 100644 index 000000000..b6fc1e090 --- /dev/null +++ b/chart2/source/tools/InternalData.cxx @@ -0,0 +1,557 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include + +#ifdef DEBUG_CHART2_TOOLS +#define DEBUG_INTERNAL_DATA 1 +#endif + +#ifdef DEBUG_INTERNAL_DATA +#include +#endif + +#include +#include +#include + +using ::com::sun::star::uno::Sequence; + +using namespace ::com::sun::star; +using namespace ::std; + +namespace chart +{ + +namespace +{ +struct lcl_NumberedStringGenerator +{ + lcl_NumberedStringGenerator( const OUString & rStub, const OUString & rWildcard ) : + m_aStub( rStub ), + m_nCounter( 0 ), + m_nStubStartIndex( rStub.indexOf( rWildcard )), + m_nWildcardLength( rWildcard.getLength()) + { + } + vector< uno::Any > operator()() + { + return { uno::Any(m_aStub.replaceAt( m_nStubStartIndex, m_nWildcardLength, OUString::number( ++m_nCounter ))) }; + } +private: + OUString m_aStub; + sal_Int32 m_nCounter; + const sal_Int32 m_nStubStartIndex; + const sal_Int32 m_nWildcardLength; +}; + +template< typename T > + Sequence< T > lcl_ValarrayToSequence( const std::valarray< T > & rValarray ) +{ +#if defined __GLIBCXX__ && (!defined _GLIBCXX_RELEASE || _GLIBCXX_RELEASE < 12) + // workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103022 + if (!size(rValarray)) + return Sequence(); +#endif + + return comphelper::containerToSequence(rValarray); +} + +} // anonymous namespace + +InternalData::InternalData() + : m_nColumnCount( 0 ) + , m_nRowCount( 0 ) + , m_aRowLabels( 0 ) + , m_aColumnLabels( 0 ) +{} + +const double fDefaultData[] = { + 9.10, 3.20, 4.54, + 2.40, 8.80, 9.65, + 3.10, 1.50, 3.70, + 4.30, 9.02, 6.20 +}; + +void InternalData::createDefaultData() +{ + const sal_Int32 nRowCount = 4; + const sal_Int32 nColumnCount = 3; + + m_nRowCount = nRowCount; + m_nColumnCount = nColumnCount; + const sal_Int32 nSize = nColumnCount * nRowCount; + // @todo: localize this! + const OUString aRowName(SchResId(STR_ROW_LABEL)); + const OUString aColName(SchResId(STR_COLUMN_LABEL)); + + m_aData.resize( nSize ); + for( sal_Int32 i=0; i >& rDataInRows ) +{ + m_nRowCount = rDataInRows.getLength(); + m_nColumnCount = (m_nRowCount ? rDataInRows[0].getLength() : 0); + + if( m_aRowLabels.size() != static_cast< sal_uInt32 >( m_nRowCount )) + m_aRowLabels.resize( m_nRowCount ); + if( m_aColumnLabels.size() != static_cast< sal_uInt32 >( m_nColumnCount )) + m_aColumnLabels.resize( m_nColumnCount ); + + m_aData.resize( m_nRowCount * m_nColumnCount ); + // set all values to Nan + m_aData = std::numeric_limits::quiet_NaN(); + + for( sal_Int32 nRow=0; nRow > InternalData::getData() const +{ + Sequence< Sequence< double > > aResult( m_nRowCount ); + auto aResultRange = asNonConstRange(aResult); + + for( sal_Int32 i=0; i( + m_aData[ std::slice( i*m_nColumnCount, m_nColumnCount, 1 ) ] ); + + return aResult; +} + +Sequence< double > InternalData::getColumnValues( sal_Int32 nColumnIndex ) const +{ + if( nColumnIndex >= 0 && nColumnIndex < m_nColumnCount ) + return lcl_ValarrayToSequence< tDataType::value_type >( + m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ] ); + return Sequence< double >(); +} +Sequence< double > InternalData::getRowValues( sal_Int32 nRowIndex ) const +{ + if( nRowIndex >= 0 && nRowIndex < m_nRowCount ) + return lcl_ValarrayToSequence< tDataType::value_type >( + m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ] ); + return Sequence< double >(); +} + +void InternalData::setColumnValues( sal_Int32 nColumnIndex, const vector< double > & rNewData ) +{ + if( nColumnIndex < 0 ) + return; + enlargeData( nColumnIndex + 1, rNewData.size() ); + + tDataType aSlice = m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ]; + for( vector< double >::size_type i = 0; i < rNewData.size(); ++i ) + aSlice[i] = rNewData[i]; + m_aData[ std::slice( nColumnIndex, m_nRowCount, m_nColumnCount ) ] = aSlice; +} + +void InternalData::setRowValues( sal_Int32 nRowIndex, const vector< double > & rNewData ) +{ + if( nRowIndex < 0 ) + return; + enlargeData( rNewData.size(), nRowIndex+1 ); + + tDataType aSlice = m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ]; + for( vector< double >::size_type i = 0; i < rNewData.size(); ++i ) + aSlice[i] = rNewData[i]; + m_aData[ std::slice( nRowIndex*m_nColumnCount, m_nColumnCount, 1 ) ]= aSlice; +} + +void InternalData::setComplexColumnLabel( sal_Int32 nColumnIndex, vector< uno::Any >&& rComplexLabel ) +{ + if( nColumnIndex < 0 ) + return; + if( o3tl::make_unsigned(nColumnIndex) >= m_aColumnLabels.size() ) + { + m_aColumnLabels.resize(nColumnIndex+1); + enlargeData( nColumnIndex+1, 0 ); + } + m_aColumnLabels[nColumnIndex] = std::move(rComplexLabel); + + dump(); +} + +void InternalData::setComplexRowLabel( sal_Int32 nRowIndex, vector< uno::Any >&& rComplexLabel ) +{ + if( nRowIndex < 0 ) + return; + if( o3tl::make_unsigned(nRowIndex) >= m_aRowLabels.size() ) + { + m_aRowLabels.resize(nRowIndex+1); + enlargeData( 0, nRowIndex+1 ); + } + sal_Int32 nSize = static_cast( m_aRowLabels[nRowIndex].size() ); + if( nSize >= 1 && !rComplexLabel.empty() ) + { + m_aRowLabels[nRowIndex].resize(nSize+1); + m_aRowLabels[nRowIndex][nSize] = rComplexLabel[0]; + } + else + { + m_aRowLabels[nRowIndex] = std::move(rComplexLabel); + } +} + +vector< uno::Any > InternalData::getComplexColumnLabel( sal_Int32 nColumnIndex ) const +{ + if( nColumnIndex < static_cast< sal_Int32 >( m_aColumnLabels.size() ) ) + return m_aColumnLabels[nColumnIndex]; + else + return vector< uno::Any >(); +} +vector< uno::Any > InternalData::getComplexRowLabel( sal_Int32 nRowIndex ) const +{ + if( nRowIndex < static_cast< sal_Int32 >( m_aRowLabels.size() ) ) + return m_aRowLabels[nRowIndex]; + else + return vector< uno::Any >(); +} + +void InternalData::swapRowWithNext( sal_Int32 nRowIndex ) +{ + if( nRowIndex >= m_nRowCount - 1 ) + return; + + const sal_Int32 nMax = m_nColumnCount; + for( sal_Int32 nColIdx=0; nColIdx aTemp( m_aRowLabels[nRowIndex] ); + m_aRowLabels[nRowIndex] = m_aRowLabels[nRowIndex + 1]; + m_aRowLabels[nRowIndex + 1] = aTemp; +} + +void InternalData::swapColumnWithNext( sal_Int32 nColumnIndex ) +{ + if( nColumnIndex >= m_nColumnCount - 1 ) + return; + + const sal_Int32 nMax = m_nRowCount; + for( sal_Int32 nRowIdx=0; nRowIdx aTemp( m_aColumnLabels[nColumnIndex] ); + m_aColumnLabels[nColumnIndex] = m_aColumnLabels[nColumnIndex + 1]; + m_aColumnLabels[nColumnIndex + 1] = aTemp; +} + +bool InternalData::enlargeData( sal_Int32 nColumnCount, sal_Int32 nRowCount ) +{ + sal_Int32 nNewColumnCount( std::max( m_nColumnCount, nColumnCount ) ); + sal_Int32 nNewRowCount( std::max( m_nRowCount, nRowCount ) ); + sal_Int32 nNewSize( nNewColumnCount*nNewRowCount ); + + bool bGrow = (nNewSize > m_nColumnCount*m_nRowCount); + + if( bGrow ) + { + tDataType aNewData( std::numeric_limits::quiet_NaN(), nNewSize ); + // copy old data + for( int nCol=0; nCol( + aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] ) = + m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ]; + + m_aData.resize( nNewSize ); + m_aData = aNewData; + } + m_nColumnCount = nNewColumnCount; + m_nRowCount = nNewRowCount; + return bGrow; +} + +void InternalData::insertColumn( sal_Int32 nAfterIndex ) +{ + // note: -1 is allowed, as we insert after the given index + OSL_ASSERT( nAfterIndex < m_nColumnCount && nAfterIndex >= -1 ); + if( nAfterIndex >= m_nColumnCount || nAfterIndex < -1 ) + return; + sal_Int32 nNewColumnCount = m_nColumnCount + 1; + sal_Int32 nNewSize( nNewColumnCount * m_nRowCount ); + + tDataType aNewData( std::numeric_limits::quiet_NaN(), nNewSize ); + + // copy old data + int nCol=0; + for( ; nCol<=nAfterIndex; ++nCol ) + aNewData[ std::slice( nCol, m_nRowCount, nNewColumnCount ) ] = + static_cast< tDataType >( + m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ] ); + for( ++nCol; nCol( + m_aData[ std::slice( nCol - 1, m_nRowCount, m_nColumnCount ) ] ); + + m_nColumnCount = nNewColumnCount; + m_aData.resize( nNewSize ); + m_aData = aNewData; + + // labels + if( nAfterIndex < static_cast< sal_Int32 >( m_aColumnLabels.size())) + m_aColumnLabels.insert( m_aColumnLabels.begin() + (nAfterIndex + 1), vector< uno::Any >(1) ); + + dump(); +} + +sal_Int32 InternalData::appendColumn() +{ + insertColumn( getColumnCount() - 1 ); + return getColumnCount() - 1; +} + +sal_Int32 InternalData::appendRow() +{ + insertRow( getRowCount() - 1 ); + return getRowCount() - 1; +} + +sal_Int32 InternalData::getRowCount() const +{ + return m_nRowCount; +} + +sal_Int32 InternalData::getColumnCount() const +{ + return m_nColumnCount; +} + +void InternalData::insertRow( sal_Int32 nAfterIndex ) +{ + // note: -1 is allowed, as we insert after the given index + OSL_ASSERT( nAfterIndex < m_nRowCount && nAfterIndex >= -1 ); + if( nAfterIndex >= m_nRowCount || nAfterIndex < -1 ) + return; + sal_Int32 nNewRowCount = m_nRowCount + 1; + sal_Int32 nNewSize( m_nColumnCount * nNewRowCount ); + + tDataType aNewData( std::numeric_limits::quiet_NaN(), nNewSize ); + + // copy old data + sal_Int32 nIndex = nAfterIndex + 1; + aNewData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] = + static_cast< tDataType >( + m_aData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] ); + + if( nIndex < m_nRowCount ) + { + sal_Int32 nRemainingCount = m_nColumnCount * (m_nRowCount - nIndex); + aNewData[ std::slice( (nIndex + 1) * m_nColumnCount, nRemainingCount, 1 ) ] = + static_cast< tDataType >( + m_aData[ std::slice( nIndex * m_nColumnCount, nRemainingCount, 1 ) ] ); + } + + m_nRowCount = nNewRowCount; + m_aData.resize( nNewSize ); + m_aData = aNewData; + + // labels + if( nAfterIndex < static_cast< sal_Int32 >( m_aRowLabels.size())) + m_aRowLabels.insert( m_aRowLabels.begin() + nIndex, vector< uno::Any > (1)); + + dump(); +} + +void InternalData::deleteColumn( sal_Int32 nAtIndex ) +{ + OSL_ASSERT( nAtIndex < m_nColumnCount && nAtIndex >= 0 ); + if( nAtIndex >= m_nColumnCount || m_nColumnCount < 1 || nAtIndex < 0 ) + return; + sal_Int32 nNewColumnCount = m_nColumnCount - 1; + sal_Int32 nNewSize( nNewColumnCount * m_nRowCount ); + + tDataType aNewData( std::numeric_limits::quiet_NaN(), nNewSize ); + + // copy old data + int nCol=0; + for( ; nCol( + m_aData[ std::slice( nCol, m_nRowCount, m_nColumnCount ) ] ); + for( ; nCol( + m_aData[ std::slice( nCol + 1, m_nRowCount, m_nColumnCount ) ] ); + + m_nColumnCount = nNewColumnCount; + m_aData.resize( nNewSize ); + m_aData = aNewData; + + // labels + if( nAtIndex < static_cast< sal_Int32 >( m_aColumnLabels.size())) + m_aColumnLabels.erase( m_aColumnLabels.begin() + nAtIndex ); + + dump(); +} + +void InternalData::deleteRow( sal_Int32 nAtIndex ) +{ + OSL_ASSERT( nAtIndex < m_nRowCount && nAtIndex >= 0 ); + if( nAtIndex >= m_nRowCount || m_nRowCount < 1 || nAtIndex < 0 ) + return; + sal_Int32 nNewRowCount = m_nRowCount - 1; + sal_Int32 nNewSize( m_nColumnCount * nNewRowCount ); + + tDataType aNewData( std::numeric_limits::quiet_NaN(), nNewSize ); + + // copy old data + sal_Int32 nIndex = nAtIndex; + if( nIndex ) + aNewData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] = + static_cast< tDataType >( + m_aData[ std::slice( 0, nIndex * m_nColumnCount, 1 ) ] ); + + if( nIndex < nNewRowCount ) + { + sal_Int32 nRemainingCount = m_nColumnCount * (nNewRowCount - nIndex); + aNewData[ std::slice( nIndex * m_nColumnCount, nRemainingCount, 1 ) ] = + static_cast< tDataType >( + m_aData[ std::slice( (nIndex + 1) * m_nColumnCount, nRemainingCount, 1 ) ] ); + } + + m_nRowCount = nNewRowCount; + m_aData.resize( nNewSize ); + m_aData = aNewData; + + // labels + if( nAtIndex < static_cast< sal_Int32 >( m_aRowLabels.size())) + m_aRowLabels.erase( m_aRowLabels.begin() + nAtIndex ); + + dump(); +} + +void InternalData::setComplexRowLabels( tVecVecAny&& rNewRowLabels ) +{ + m_aRowLabels = std::move(rNewRowLabels); + sal_Int32 nNewRowCount = static_cast< sal_Int32 >( m_aRowLabels.size() ); + if( nNewRowCount < m_nRowCount ) + m_aRowLabels.resize( m_nRowCount ); + else + enlargeData( 0, nNewRowCount ); +} + +const InternalData::tVecVecAny& InternalData::getComplexRowLabels() const +{ + return m_aRowLabels; +} + +void InternalData::setComplexColumnLabels( tVecVecAny&& rNewColumnLabels ) +{ + m_aColumnLabels = std::move(rNewColumnLabels); + sal_Int32 nNewColumnCount = static_cast< sal_Int32 >( m_aColumnLabels.size() ); + if( nNewColumnCount < m_nColumnCount ) + m_aColumnLabels.resize( m_nColumnCount ); + else + enlargeData( nNewColumnCount, 0 ); +} + +const InternalData::tVecVecAny& InternalData::getComplexColumnLabels() const +{ + return m_aColumnLabels; +} + +#ifdef DEBUG_INTERNAL_DATA +void InternalData::dump() const +{ + // Header + if (!m_aColumnLabels.empty()) + { + svl::GridPrinter aPrinter(m_aColumnLabels[0].size(), m_aColumnLabels.size(), true); + for (size_t nCol = 0; nCol < m_aColumnLabels.size(); ++nCol) + { + for (size_t nRow = 0; nRow < m_aColumnLabels[nCol].size(); ++nRow) + { + OUString aStr; + if (m_aColumnLabels[nCol].at(nRow) >>= aStr) + aPrinter.set(nRow, nCol, aStr); + } + } + aPrinter.print("Header"); + } + + if (!m_aRowLabels.empty()) + { + svl::GridPrinter aPrinter(m_aRowLabels.size(), m_aRowLabels[0].size(), true); + for (size_t nRow = 0; nRow < m_aRowLabels.size(); ++nRow) + { + for (size_t nCol = 0; nCol < m_aRowLabels[nRow].size(); ++nCol) + { + OUString aStr; + if (m_aRowLabels[nRow].at(nCol) >>= aStr) + aPrinter.set(nRow, nCol, aStr); + } + } + aPrinter.print("Row labels"); + } + + svl::GridPrinter aPrinter(m_nRowCount, m_nColumnCount, true); + + for (sal_Int32 nRow = 0; nRow < m_nRowCount; ++nRow) + { + tDataType aSlice( m_aData[ std::slice( nRow*m_nColumnCount, m_nColumnCount, 1 ) ] ); + for (sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol) + aPrinter.set(nRow, nCol, OUString::number(aSlice[nCol])); + } + + aPrinter.print("Column data"); +} +#else +void InternalData::dump() const {} +#endif + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/InternalDataProvider.cxx b/chart2/source/tools/InternalDataProvider.cxx new file mode 100644 index 000000000..0c95286e9 --- /dev/null +++ b/chart2/source/tools/InternalDataProvider.cxx @@ -0,0 +1,1553 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace com::sun::star::chart2 { class XChartDocument; } + +using namespace ::com::sun::star; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +namespace +{ + +constexpr OUStringLiteral lcl_aCategoriesRangeName = u"categories"; +const char lcl_aCategoriesLevelRangeNamePrefix[] = "categoriesL "; //L <-> level +const char lcl_aCategoriesPointRangeNamePrefix[] = "categoriesP "; //P <-> point +constexpr OUStringLiteral lcl_aCategoriesRoleName = u"categories"; +const char lcl_aLabelRangePrefix[] = "label "; +constexpr OUStringLiteral lcl_aCompleteRange = u"all"; + +typedef std::multimap< OUString, uno::WeakReference< chart2::data::XDataSequence > > + lcl_tSequenceMap; + +std::vector< OUString > lcl_AnyToStringSequence( const std::vector< uno::Any >& aAnySeq ) +{ + std::vector< OUString > aResult; + aResult.resize( aAnySeq.size() ); + int i = 0; + for (const uno::Any& aAny : aAnySeq) + aResult[i++] = CommonFunctors::AnyToString()(aAny); + return aResult; +} + +std::vector< uno::Any > lcl_StringToAnyVector( const css::uno::Sequence< OUString >& aStringSeq ) +{ + std::vector< uno::Any > aResult; + aResult.resize( aStringSeq.getLength() ); + int i = 0; + for (const OUString& aStr : aStringSeq) + aResult[i++] = CommonFunctors::makeAny()(aStr); + return aResult; +} + +struct lcl_setModified +{ + void operator() ( const lcl_tSequenceMap::value_type & rMapEntry ) + { + // convert weak reference to reference + Reference< chart2::data::XDataSequence > xSeq( rMapEntry.second ); + if( xSeq.is()) + { + Reference< util::XModifiable > xMod( xSeq, uno::UNO_QUERY ); + if( xMod.is()) + xMod->setModified( true ); + } + } +}; + +struct lcl_internalizeSeries +{ + lcl_internalizeSeries( InternalData & rInternalData, + InternalDataProvider & rProvider, + bool bConnectToModel, bool bDataInColumns ) : + m_rInternalData( rInternalData ), + m_rProvider( rProvider ), + m_bConnectToModel( bConnectToModel ), + m_bDataInColumns( bDataInColumns ) + {} + void operator() ( const rtl::Reference< DataSeries > & xSeries ) + { + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aOldSeriesData = xSeries->getDataSequences2(); + std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aNewSeriesData( aOldSeriesData.size() ); + for( std::size_t i=0; i xValues( aOldSeriesData[i]->getValues(), uno::UNO_QUERY ); + Reference< chart2::data::XTextualDataSequence > xLabel( aOldSeriesData[i]->getLabel(), uno::UNO_QUERY ); + Reference< chart2::data::XDataSequence > xNewValues; + + if( xValues.is() ) + { + auto aValues( comphelper::sequenceToContainer>( xValues->getNumericalData())); + if( m_bDataInColumns ) + m_rInternalData.setColumnValues( nNewIndex, aValues ); + else + m_rInternalData.setRowValues( nNewIndex, aValues ); + if( m_bConnectToModel ) + { + xNewValues.set( m_rProvider.createDataSequenceByRangeRepresentation( aIdentifier )); + comphelper::copyProperties( + Reference< beans::XPropertySet >( xValues, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewValues, uno::UNO_QUERY )); + } + } + + if( xLabel.is() ) + { + if( m_bDataInColumns ) + m_rInternalData.setComplexColumnLabel( nNewIndex, lcl_StringToAnyVector( xLabel->getTextualData() ) ); + else + m_rInternalData.setComplexRowLabel( nNewIndex, lcl_StringToAnyVector( xLabel->getTextualData() ) ); + if( m_bConnectToModel ) + { + Reference< chart2::data::XDataSequence > xNewLabel( + m_rProvider.createDataSequenceByRangeRepresentation( lcl_aLabelRangePrefix + aIdentifier )); + comphelper::copyProperties( + Reference< beans::XPropertySet >( xLabel, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewLabel, uno::UNO_QUERY )); + aNewSeriesData[i].set( new LabeledDataSequence( xNewValues, xNewLabel ) ); + } + } + else + { + if( m_bConnectToModel ) + aNewSeriesData[i].set( new LabeledDataSequence( xNewValues ) ); + } + } + if( m_bConnectToModel ) + xSeries->setData( aNewSeriesData ); + } + +private: + InternalData & m_rInternalData; + InternalDataProvider & m_rProvider; + bool m_bConnectToModel; + bool m_bDataInColumns; +}; + +struct lcl_copyFromLevel +{ +public: + + explicit lcl_copyFromLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + uno::Any operator() ( const vector< uno::Any >& rVector ) + { + uno::Any aRet; + if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) ) + aRet = rVector[m_nLevel]; + return aRet; + } + +private: + sal_Int32 m_nLevel; +}; + +struct lcl_getStringFromLevelVector +{ +public: + + explicit lcl_getStringFromLevelVector( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + OUString operator() ( const vector< uno::Any >& rVector ) + { + OUString aString; + if( m_nLevel < static_cast< sal_Int32 >(rVector.size()) ) + aString = CommonFunctors::AnyToString()(rVector[m_nLevel]); + return aString; + } + +private: + sal_Int32 m_nLevel; +}; + +struct lcl_setAnyAtLevel +{ +public: + + explicit lcl_setAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + vector< uno::Any > operator() ( const vector< uno::Any >& rVector, const uno::Any& rNewValue ) + { + vector< uno::Any > aRet( rVector ); + if( m_nLevel >= static_cast< sal_Int32 >(aRet.size()) ) + aRet.resize( m_nLevel+1 ); + aRet[ m_nLevel ]=rNewValue; + return aRet; + } + +private: + sal_Int32 m_nLevel; +}; + +struct lcl_setAnyAtLevelFromStringSequence +{ +public: + + explicit lcl_setAnyAtLevelFromStringSequence( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + vector< uno::Any > operator() ( const vector< uno::Any >& rVector, const OUString& rNewValue ) + { + vector< uno::Any > aRet( rVector ); + if( m_nLevel >= static_cast< sal_Int32 >(aRet.size()) ) + aRet.resize( m_nLevel+1 ); + aRet[ m_nLevel ] <<= rNewValue; + return aRet; + } + +private: + sal_Int32 m_nLevel; +}; + +struct lcl_insertAnyAtLevel +{ +public: + + explicit lcl_insertAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + void operator() ( vector< uno::Any >& rVector ) + { + if( m_nLevel >= static_cast< sal_Int32 >(rVector.size()) ) + { + rVector.resize( m_nLevel + 1 ); + } + else + { + rVector.insert( rVector.begin() + m_nLevel, uno::Any() ); + } + } + +private: + sal_Int32 m_nLevel; +}; + +struct lcl_removeAnyAtLevel +{ +public: + + explicit lcl_removeAnyAtLevel( sal_Int32 nLevel ) : m_nLevel( nLevel ) + {} + + void operator() ( vector< uno::Any >& rVector ) + { + if( m_nLevel < static_cast(rVector.size()) ) + { + rVector.erase(rVector.begin() + m_nLevel); + } + } + +private: + sal_Int32 m_nLevel; +}; + +} // anonymous namespace + +InternalDataProvider::InternalDataProvider() + : m_bDataInColumns( true ) +{} + +InternalDataProvider::InternalDataProvider( + const rtl::Reference< ChartModel > & xModel, + bool bConnectToModel, + bool bDefaultDataInColumns) +: m_bDataInColumns( bDefaultDataInColumns ) +{ + if (!xModel.is()) + return; + try + { + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xModel ) ); + if( xDiagram.is()) + { + //data in columns? + { + OUString aRangeString; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + const bool bSomethingDetected( + DataSourceHelper::detectRangeSegmentation( + xModel, aRangeString, aSequenceMapping, m_bDataInColumns, bFirstCellAsLabel, bHasCategories )); + + // #i120559# if no data was available, restore default + if(!bSomethingDetected && m_bDataInColumns != bDefaultDataInColumns) + { + m_bDataInColumns = bDefaultDataInColumns; + } + } + + // categories + { + vector< vector< uno::Any > > aNewCategories;//inner count is level + { + ExplicitCategoriesProvider aExplicitCategoriesProvider(ChartModelHelper::getFirstCoordinateSystem(xModel), *xModel); + + const std::vector< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList( aExplicitCategoriesProvider.getSplitCategoriesList() ); + sal_Int32 nLevelCount = rSplitCategoriesList.size(); + for( sal_Int32 nL = 0; nL xLDS( rSplitCategoriesList[nL] ); + if( !xLDS.is() ) + continue; + Sequence< uno::Any > aDataSeq; + Reference< chart2::data::XDataSequence > xSeq( xLDS->getValues() ); + if( xSeq.is() ) + aDataSeq = xSeq->getData(); + sal_Int32 nLength = aDataSeq.getLength(); + sal_Int32 nCatLength = static_cast< sal_Int32 >(aNewCategories.size()); + if( nCatLength < nLength ) + aNewCategories.resize( nLength ); + else if( nLength < nCatLength ) + aDataSeq.realloc( nCatLength ); + transform( aNewCategories.begin(), aNewCategories.end(), aDataSeq.getConstArray(), + aNewCategories.begin(), lcl_setAnyAtLevel(nL) ); + } + if( !nLevelCount ) + { + Sequence< OUString > aSimplecategories = aExplicitCategoriesProvider.getSimpleCategories(); + sal_Int32 nLength = aSimplecategories.getLength(); + aNewCategories.reserve( nLength ); + for( sal_Int32 nN=0; nN(new LabeledDataSequence( + createDataSequenceByRangeRepresentation( lcl_aCategoriesRangeName ))), + xDiagram ); + } + + // data series + std::vector< rtl::Reference< DataSeries > > aSeriesVector( ChartModelHelper::getDataSeries( xModel )); + lcl_internalizeSeries ftor( m_aInternalData, *this, bConnectToModel, m_bDataInColumns ); + for( const auto& rxScreen : aSeriesVector ) + ftor( rxScreen ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// copy-CTOR +InternalDataProvider::InternalDataProvider( const InternalDataProvider & rOther ) : + impl::InternalDataProvider_Base(rOther), + m_aSequenceMap( rOther.m_aSequenceMap ), + m_aInternalData( rOther.m_aInternalData ), + m_bDataInColumns( rOther.m_bDataInColumns ) +{} + +InternalDataProvider::~InternalDataProvider() +{} + +void InternalDataProvider::addDataSequenceToMap( + const OUString & rRangeRepresentation, + const Reference< chart2::data::XDataSequence > & xSequence ) +{ + m_aSequenceMap.emplace( + rRangeRepresentation, + uno::WeakReference< chart2::data::XDataSequence >( xSequence )); +} + +void InternalDataProvider::deleteMapReferences( const OUString & rRangeRepresentation ) +{ + // set sequence to deleted by setting its range to an empty string + tSequenceMapRange aRange( m_aSequenceMap.equal_range( rRangeRepresentation )); + for( tSequenceMap::iterator aIt( aRange.first ); aIt != aRange.second; ++aIt ) + { + Reference< chart2::data::XDataSequence > xSeq( aIt->second ); + if( xSeq.is()) + { + Reference< container::XNamed > xNamed( xSeq, uno::UNO_QUERY ); + if( xNamed.is()) + xNamed->setName( OUString()); + } + } + // remove from map + m_aSequenceMap.erase( aRange.first, aRange.second ); +} + +void InternalDataProvider::adaptMapReferences( + const OUString & rOldRangeRepresentation, + const OUString & rNewRangeRepresentation ) +{ + tSequenceMapRange aRange( m_aSequenceMap.equal_range( rOldRangeRepresentation )); + tSequenceMap aNewElements; + for( tSequenceMap::iterator aIt( aRange.first ); aIt != aRange.second; ++aIt ) + { + Reference< chart2::data::XDataSequence > xSeq( aIt->second ); + if( xSeq.is()) + { + Reference< container::XNamed > xNamed( xSeq, uno::UNO_QUERY ); + if( xNamed.is()) + xNamed->setName( rNewRangeRepresentation ); + } + aNewElements.emplace( rNewRangeRepresentation, aIt->second ); + } + // erase map values for old index + m_aSequenceMap.erase( aRange.first, aRange.second ); + // add new entries for values with new index + m_aSequenceMap.insert( aNewElements.begin(), aNewElements.end() ); +} + +void InternalDataProvider::increaseMapReferences( + sal_Int32 nBegin, sal_Int32 nEnd ) +{ + for( sal_Int32 nIndex = nEnd - 1; nIndex >= nBegin; --nIndex ) + { + adaptMapReferences( OUString::number( nIndex ), + OUString::number( nIndex + 1 )); + adaptMapReferences( lcl_aLabelRangePrefix + OUString::number( nIndex ), + lcl_aLabelRangePrefix + OUString::number( nIndex + 1 )); + } +} + +void InternalDataProvider::decreaseMapReferences( + sal_Int32 nBegin, sal_Int32 nEnd ) +{ + for( sal_Int32 nIndex = nBegin; nIndex < nEnd; ++nIndex ) + { + adaptMapReferences( OUString::number( nIndex ), + OUString::number( nIndex - 1 )); + adaptMapReferences( lcl_aLabelRangePrefix + OUString::number( nIndex ), + lcl_aLabelRangePrefix + OUString::number( nIndex - 1 )); + } +} + +rtl::Reference< UncachedDataSequence > InternalDataProvider::createDataSequenceAndAddToMap( + const OUString & rRangeRepresentation ) +{ + rtl::Reference xSeq = createDataSequenceFromArray(rRangeRepresentation, u"", u""); + if (xSeq.is()) + return nullptr; + + xSeq.set(new UncachedDataSequence(this, rRangeRepresentation)); + addDataSequenceToMap(rRangeRepresentation, xSeq); + return xSeq; +} + +rtl::Reference +InternalDataProvider::createDataSequenceFromArray( const OUString& rArrayStr, std::u16string_view rRole, std::u16string_view rRoleQualifier ) +{ + if (rArrayStr.indexOf('{') != 0 || rArrayStr[rArrayStr.getLength()-1] != '}') + { + // Not an array string. + return nullptr; + } + + bool bAllNumeric = true; + rtl::Reference xSeq; + + const sal_Unicode* p = rArrayStr.getStr(); + const sal_Unicode* pEnd = p + rArrayStr.getLength(); + const sal_Unicode* pElem = nullptr; + OUString aElem; + + std::vector aRawElems; + ++p; // Skip the first '{'. + --pEnd; // Skip the last '}'. + bool bInQuote = false; + for (; p != pEnd; ++p) + { + // Skip next "" within the title text: it's an escaped double quotation mark. + if (bInQuote && *p == '"' && *(p + 1) == '"') + { + if (!pElem) + pElem = p; + ++p; + } + else if (*p == '"') + { + bInQuote = !bInQuote; + if (bInQuote) + { + // Opening quote. + pElem = nullptr; + } + else + { + // Closing quote. + if (pElem) + aElem = OUString(pElem, p-pElem); + // Non empty string + if (!aElem.isEmpty()) + bAllNumeric = false; + // Restore also escaped double quotation marks + aRawElems.push_back(aElem.replaceAll("\"\"", "\"")); + pElem = nullptr; + aElem.clear(); + + ++p; // Skip '"'. + if (p == pEnd) + break; + } + } + else if (*p == ';' && !bInQuote) + { + // element separator. + if (pElem) + aElem = OUString(pElem, p-pElem); + aRawElems.push_back(aElem); + pElem = nullptr; + aElem.clear(); + } + else if (!pElem) + pElem = p; + } + + if (pElem) + { + aElem = OUString(pElem, p-pElem); + aRawElems.push_back(aElem); + } + + if (rRole == u"values-y" || rRole == u"values-first" || rRole == u"values-last" || + rRole == u"values-min" || rRole == u"values-max" || rRole == u"values-size" || + rRole == u"error-bars-y-positive" || rRole == u"error-bars-y-negative") + { + // Column values. Append a new data column and populate it. + + std::vector aValues; + aValues.reserve(aRawElems.size()); + for (const OUString & aRawElem : aRawElems) + { + if (aRawElem.isEmpty()) + aValues.push_back(NAN); + else + aValues.push_back(aRawElem.toDouble()); + } + sal_Int32 n = m_aInternalData.appendColumn(); + + m_aInternalData.setColumnValues(n, aValues); + + OUString aRangeRep = OUString::number(n); + xSeq.set(new UncachedDataSequence(this, aRangeRep)); + addDataSequenceToMap(aRangeRep, xSeq); + } + else if (rRole == u"values-x") + { + std::vector aValues; + aValues.reserve(aRawElems.size()); + if (bAllNumeric) + { + for (const OUString & aRawElem : aRawElems) + { + if (!aRawElem.isEmpty()) + aValues.push_back(aRawElem.toDouble()); + else + aValues.push_back(NAN); + } + } + else + { + for (size_t i = 0; i < aRawElems.size(); ++i) + aValues.push_back(i+1); + } + + sal_Int32 n = m_aInternalData.appendColumn(); + m_aInternalData.setColumnValues(n, aValues); + + OUString aRangeRep = OUString::number(n); + xSeq.set(new UncachedDataSequence(this, aRangeRep)); + addDataSequenceToMap(aRangeRep, xSeq); + } + else if (rRole == u"categories") + { + // Category labels. + + // Store date categories as numbers. + bool bStoreNumeric = rRoleQualifier == u"date"; + double fValue; + for (size_t i = 0; i < aRawElems.size(); ++i) + { + if (bStoreNumeric) + { + bool bGetDouble = bAllNumeric && !aRawElems[i].isEmpty(); + fValue = bGetDouble ? aRawElems[i].toDouble() : + std::numeric_limits::quiet_NaN(); + } + std::vector aLabels(1, + bStoreNumeric ? uno::Any(fValue) : uno::Any(aRawElems[i])); + m_aInternalData.setComplexRowLabel(i, std::move(aLabels)); + } + + xSeq.set(new UncachedDataSequence(this, lcl_aCategoriesRangeName)); + addDataSequenceToMap(lcl_aCategoriesRangeName, xSeq); + } + else if (rRole == u"label") + { + // Data series label. There should be only one element. This always + // goes to the last data column. + sal_Int32 nColSize = m_aInternalData.getColumnCount(); + if (!aRawElems.empty() && nColSize) + { + // Do not overwrite an existing label (attempted by series with no data values) + if (!m_aInternalData.getComplexColumnLabel(nColSize-1)[0].hasValue()) + { + std::vector aLabels(1, uno::Any(aRawElems[0])); + m_aInternalData.setComplexColumnLabel(nColSize-1, std::move(aLabels)); + } + + OUString aRangeRep = lcl_aLabelRangePrefix + OUString::number(nColSize-1); + xSeq.set(new UncachedDataSequence(this, aRangeRep)); + addDataSequenceToMap(aRangeRep, xSeq); + } + } + + return xSeq; +} + +Reference< chart2::data::XDataSequence > InternalDataProvider::createDataSequenceAndAddToMap( + const OUString & rRangeRepresentation, + const OUString & rRole ) +{ + rtl::Reference< UncachedDataSequence > xSeq = + new UncachedDataSequence( this, rRangeRepresentation, rRole ); + addDataSequenceToMap( rRangeRepresentation, xSeq ); + return xSeq; +} + +// ____ XDataProvider ____ +sal_Bool SAL_CALL InternalDataProvider::createDataSourcePossible( const Sequence< beans::PropertyValue >& /* aArguments */ ) +{ + return true; +} + +namespace +{ + +sal_Int32 lcl_getInnerLevelCount( const vector< vector< uno::Any > >& rLabels ) +{ + sal_Int32 nCount = 1;//minimum is 1! + for (auto const& elemLabel : rLabels) + { + nCount = std::max( elemLabel.size(), nCount ); + } + return nCount; +} + +}//end anonymous namespace + +Reference< chart2::data::XDataSource > SAL_CALL InternalDataProvider::createDataSource( + const Sequence< beans::PropertyValue >& aArguments ) +{ + OUString aRangeRepresentation; + bool bUseColumns = true; + bool bFirstCellAsLabel = true; + bool bHasCategories = true; + uno::Sequence< sal_Int32 > aSequenceMapping; + DataSourceHelper::readArguments( aArguments, aRangeRepresentation, aSequenceMapping, bUseColumns, bFirstCellAsLabel, bHasCategories ); + + if( aRangeRepresentation == lcl_aCategoriesRangeName ) + { + //return split complex categories if we have any: + std::vector< Reference< chart2::data::XLabeledDataSequence > > aComplexCategories; + const vector< vector< uno::Any > > & aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); + if( bUseColumns==m_bDataInColumns ) + { + sal_Int32 nLevelCount = lcl_getInnerLevelCount( aCategories ); + for( sal_Int32 nL=0; nL > aResultLSeqVec; + + // categories + if( bHasCategories ) + aResultLSeqVec.push_back( + new LabeledDataSequence( createDataSequenceAndAddToMap( lcl_aCategoriesRangeName, lcl_aCategoriesRoleName ) ) ); + + // data with labels + std::vector< Reference< chart2::data::XLabeledDataSequence > > aDataVec; + const sal_Int32 nCount = (bUseColumns ? m_aInternalData.getColumnCount() : m_aInternalData.getRowCount()); + aDataVec.reserve(nCount); + for (sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx) + { + aDataVec.push_back( + new LabeledDataSequence( + createDataSequenceAndAddToMap( OUString::number( nIdx )), + createDataSequenceAndAddToMap( lcl_aLabelRangePrefix + OUString::number( nIdx )))); + } + + // attention: this data provider has the limitation that it stores + // internally if data comes from columns or rows. It is intended for + // creating only one used data source. + // @todo: add this information in the range representation strings + m_bDataInColumns = bUseColumns; + + //reorder labeled sequences according to aSequenceMapping; ignore categories + for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ ) + { + std::vector< LabeledDataSequence* >::size_type nOldIndex = aSequenceMapping[nNewIndex]; + if( nOldIndex < aDataVec.size() ) + { + if( aDataVec[nOldIndex].is() ) + { + aResultLSeqVec.push_back( aDataVec[nOldIndex] ); + aDataVec[nOldIndex] = nullptr; + } + } + } + + //add left over data sequences to result + for (auto const& elem : aDataVec) + { + if( elem.is() ) + aResultLSeqVec.push_back(elem); + } + + return new DataSource( comphelper::containerToSequence(aResultLSeqVec) ); +} + +Sequence< beans::PropertyValue > SAL_CALL InternalDataProvider::detectArguments( + const Reference< chart2::data::XDataSource >& /* xDataSource */ ) +{ + Sequence< beans::PropertyValue > aArguments{ + beans::PropertyValue( + "CellRangeRepresentation", -1, uno::Any( OUString(lcl_aCompleteRange) ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "DataRowSource", -1, uno::Any( + m_bDataInColumns + ? css::chart::ChartDataRowSource_COLUMNS + : css::chart::ChartDataRowSource_ROWS ), + beans::PropertyState_DIRECT_VALUE ), + // internal data always contains labels and categories + beans::PropertyValue( + "FirstCellAsLabel", -1, uno::Any( true ), beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "HasCategories", -1, uno::Any( true ), beans::PropertyState_DIRECT_VALUE ) + }; + // #i85913# Sequence Mapping is not needed for internal data, as it is + // applied to the data when the data source is created. + + return aArguments; +} + +sal_Bool SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& /* aRangeRepresentation */ ) +{ + return true; +} + +Reference< chart2::data::XDataSequence > SAL_CALL InternalDataProvider::createDataSequenceByRangeRepresentation( + const OUString& aRangeRepresentation ) +{ + if( aRangeRepresentation.match( lcl_aCategoriesRangeName )) + { + OSL_ASSERT( aRangeRepresentation == lcl_aCategoriesRangeName );//it is not expected nor implemented that only parts of the categories are really requested + + // categories + return createDataSequenceAndAddToMap( lcl_aCategoriesRangeName, lcl_aCategoriesRoleName ); + } + else if( aRangeRepresentation.match( lcl_aLabelRangePrefix )) + { + // label + sal_Int32 nIndex = o3tl::toInt32(aRangeRepresentation.subView( strlen(lcl_aLabelRangePrefix))); + return createDataSequenceAndAddToMap( lcl_aLabelRangePrefix + OUString::number( nIndex )); + } + else if ( aRangeRepresentation == "last" ) + { + sal_Int32 nIndex = (m_bDataInColumns + ? m_aInternalData.getColumnCount() + : m_aInternalData.getRowCount()) - 1; + return createDataSequenceAndAddToMap( OUString::number( nIndex )); + } + else if( !aRangeRepresentation.isEmpty()) + { + // data + return createDataSequenceAndAddToMap( aRangeRepresentation ); + } + + return Reference< chart2::data::XDataSequence >(); +} + +Reference SAL_CALL +InternalDataProvider::createDataSequenceByValueArray( + const OUString& aRole, const OUString& aRangeRepresentation, const OUString& aRoleQualifier ) +{ + return createDataSequenceFromArray(aRangeRepresentation, aRole, aRoleQualifier); +} + +Reference< sheet::XRangeSelection > SAL_CALL InternalDataProvider::getRangeSelection() +{ + // there is no range selection component + return Reference< sheet::XRangeSelection >(); +} + +// ____ XInternalDataProvider ____ +sal_Bool SAL_CALL InternalDataProvider::hasDataByRangeRepresentation( const OUString& aRange ) +{ + bool bResult = false; + + if( aRange.match( lcl_aCategoriesRangeName )) + { + OSL_ASSERT( aRange == lcl_aCategoriesRangeName );//it is not expected nor implemented that only parts of the categories are really requested + bResult = true; + } + else if( aRange.match( lcl_aLabelRangePrefix )) + { + sal_Int32 nIndex = o3tl::toInt32(aRange.subView( strlen(lcl_aLabelRangePrefix))); + bResult = (nIndex < (m_bDataInColumns ? m_aInternalData.getColumnCount(): m_aInternalData.getRowCount())); + } + else + { + sal_Int32 nIndex = aRange.toInt32(); + bResult = (nIndex < (m_bDataInColumns ? m_aInternalData.getColumnCount(): m_aInternalData.getRowCount())); + } + + return bResult; +} + +Sequence< uno::Any > SAL_CALL InternalDataProvider::getDataByRangeRepresentation( const OUString& aRange ) +{ + Sequence< uno::Any > aResult; + + if( aRange.match( lcl_aLabelRangePrefix ) ) + { + auto nIndex = o3tl::toUInt32(aRange.subView( strlen(lcl_aLabelRangePrefix))); + vector< uno::Any > aComplexLabel = m_bDataInColumns + ? m_aInternalData.getComplexColumnLabel( nIndex ) + : m_aInternalData.getComplexRowLabel( nIndex ); + if( !aComplexLabel.empty() ) + aResult = comphelper::containerToSequence(aComplexLabel); + } + else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) ) + { + auto nPointIndex = o3tl::toUInt32(aRange.subView( strlen(lcl_aCategoriesPointRangeNamePrefix) )); + vector< uno::Any > aComplexCategory = m_bDataInColumns + ? m_aInternalData.getComplexRowLabel( nPointIndex ) + : m_aInternalData.getComplexColumnLabel( nPointIndex ); + if( !aComplexCategory.empty() ) + aResult = comphelper::containerToSequence(aComplexCategory); + } + else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) ) + { + sal_Int32 nLevel = o3tl::toInt32(aRange.subView( strlen(lcl_aCategoriesLevelRangeNamePrefix) )); + const vector< vector< uno::Any > > & aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); + if( nLevel < lcl_getInnerLevelCount( aCategories ) ) + { + aResult.realloc( aCategories.size() ); + transform( aCategories.begin(), aCategories.end(), + aResult.getArray(), lcl_copyFromLevel(nLevel) ); + } + } + else if( aRange == lcl_aCategoriesRangeName ) + { + const vector< vector< uno::Any > > & aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); + sal_Int32 nLevelCount = lcl_getInnerLevelCount( aCategories ); + if( nLevelCount == 1 ) + { + aResult = getDataByRangeRepresentation( lcl_aCategoriesLevelRangeNamePrefix + OUString::number( 0 ) ); + } + else + { + // Maybe this 'else' part and the functions is not necessary anymore. + const Sequence< OUString > aLabels = m_bDataInColumns ? getRowDescriptions() : getColumnDescriptions(); + aResult.realloc( aLabels.getLength() ); + transform( aLabels.begin(), aLabels.end(), + aResult.getArray(), CommonFunctors::makeAny< OUString >() ); + } + } + else + { + sal_Int32 nIndex = aRange.toInt32(); + if( nIndex >= 0 ) + { + const Sequence< double > aData = m_bDataInColumns + ? m_aInternalData.getColumnValues(nIndex) + : m_aInternalData.getRowValues(nIndex); + if( aData.hasElements() ) + { + aResult.realloc( aData.getLength()); + transform( aData.begin(), aData.end(), + aResult.getArray(), CommonFunctors::makeAny< double >()); + } + } + } + + return aResult; +} + +void SAL_CALL InternalDataProvider::setDataByRangeRepresentation( + const OUString& aRange, const Sequence< uno::Any >& aNewData ) +{ + auto aNewVector( comphelper::sequenceToContainer>(aNewData) ); + if( aRange.match( lcl_aLabelRangePrefix ) ) + { + sal_uInt32 nIndex = o3tl::toInt32(aRange.subView( strlen(lcl_aLabelRangePrefix))); + if( m_bDataInColumns ) + m_aInternalData.setComplexColumnLabel( nIndex, std::move(aNewVector) ); + else + m_aInternalData.setComplexRowLabel( nIndex, std::move(aNewVector) ); + } + else if( aRange.match( lcl_aCategoriesPointRangeNamePrefix ) ) + { + sal_Int32 nPointIndex = o3tl::toInt32(aRange.subView( strlen(lcl_aCategoriesLevelRangeNamePrefix))); + if( m_bDataInColumns ) + m_aInternalData.setComplexRowLabel( nPointIndex, std::move(aNewVector) ); + else + m_aInternalData.setComplexColumnLabel( nPointIndex, std::move(aNewVector) ); + } + else if( aRange.match( lcl_aCategoriesLevelRangeNamePrefix ) ) + { + sal_Int32 nLevel = o3tl::toInt32(aRange.subView( strlen(lcl_aCategoriesLevelRangeNamePrefix))); + vector< vector< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); + + //ensure equal length + if( aNewVector.size() > aComplexCategories.size() ) + aComplexCategories.resize( aNewVector.size() ); + else if( aNewVector.size() < aComplexCategories.size() ) + aNewVector.resize( aComplexCategories.size() ); + + transform( aComplexCategories.begin(), aComplexCategories.end(), aNewVector.begin(), + aComplexCategories.begin(), lcl_setAnyAtLevel(nLevel) ); + + if( m_bDataInColumns ) + m_aInternalData.setComplexRowLabels( std::move(aComplexCategories) ); + else + m_aInternalData.setComplexColumnLabels( std::move(aComplexCategories) ); + } + else if( aRange == lcl_aCategoriesRangeName ) + { + vector< vector< uno::Any > > aComplexCategories; + aComplexCategories.resize( aNewVector.size() ); + transform( aComplexCategories.begin(), aComplexCategories.end(), aNewVector.begin(), + aComplexCategories.begin(), lcl_setAnyAtLevel(0) ); + if( m_bDataInColumns ) + m_aInternalData.setComplexRowLabels( std::move(aComplexCategories) ); + else + m_aInternalData.setComplexColumnLabels( std::move(aComplexCategories) ); + } + else + { + sal_Int32 nIndex = aRange.toInt32(); + if( nIndex>=0 ) + { + vector< double > aNewDataVec; + transform( aNewData.begin(), aNewData.end(), + back_inserter( aNewDataVec ), CommonFunctors::AnyToDouble()); + if( m_bDataInColumns ) + m_aInternalData.setColumnValues( nIndex, aNewDataVec ); + else + m_aInternalData.setRowValues( nIndex, aNewDataVec ); + } + } +} + +void SAL_CALL InternalDataProvider::insertSequence( ::sal_Int32 nAfterIndex ) +{ + if( m_bDataInColumns ) + { + increaseMapReferences( nAfterIndex + 1, m_aInternalData.getColumnCount()); + m_aInternalData.insertColumn( nAfterIndex ); + } + else + { + increaseMapReferences( nAfterIndex + 1, m_aInternalData.getRowCount()); + m_aInternalData.insertRow( nAfterIndex ); + } +} + +void SAL_CALL InternalDataProvider::deleteSequence( ::sal_Int32 nAtIndex ) +{ + deleteMapReferences( OUString::number( nAtIndex )); + deleteMapReferences( lcl_aLabelRangePrefix + OUString::number( nAtIndex )); + if( m_bDataInColumns ) + { + decreaseMapReferences( nAtIndex + 1, m_aInternalData.getColumnCount()); + m_aInternalData.deleteColumn( nAtIndex ); + } + else + { + decreaseMapReferences( nAtIndex + 1, m_aInternalData.getRowCount()); + m_aInternalData.deleteRow( nAtIndex ); + } +} + +void SAL_CALL InternalDataProvider::appendSequence() +{ + if( m_bDataInColumns ) + m_aInternalData.appendColumn(); + else + m_aInternalData.appendRow(); +} + +void SAL_CALL InternalDataProvider::insertComplexCategoryLevel( sal_Int32 nLevel ) +{ + OSL_ENSURE( nLevel> 0, "you can only insert category levels > 0" );//the first categories level cannot be deleted, check the calling code for error + if( nLevel>0 ) + { + vector< vector< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); + std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_insertAnyAtLevel(nLevel) ); + if( m_bDataInColumns ) + m_aInternalData.setComplexRowLabels( std::move(aComplexCategories) ); + else + m_aInternalData.setComplexColumnLabels( std::move(aComplexCategories) ); + + tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); + std::for_each( aRange.first, aRange.second, lcl_setModified()); + } +} +void SAL_CALL InternalDataProvider::deleteComplexCategoryLevel( sal_Int32 nLevel ) +{ + OSL_ENSURE( nLevel>0, "you can only delete category levels > 0" );//the first categories level cannot be deleted, check the calling code for error + if( nLevel>0 ) + { + vector< vector< uno::Any > > aComplexCategories = m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels(); + std::for_each( aComplexCategories.begin(), aComplexCategories.end(), lcl_removeAnyAtLevel(nLevel) ); + if( m_bDataInColumns ) + m_aInternalData.setComplexRowLabels( std::move(aComplexCategories) ); + else + m_aInternalData.setComplexColumnLabels( std::move(aComplexCategories) ); + + tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); + std::for_each( aRange.first, aRange.second, lcl_setModified()); + } +} + +void SAL_CALL InternalDataProvider::insertDataPointForAllSequences( ::sal_Int32 nAfterIndex ) +{ + sal_Int32 nMaxRep = 0; + if( m_bDataInColumns ) + { + m_aInternalData.insertRow( nAfterIndex ); + nMaxRep = m_aInternalData.getColumnCount(); + } + else + { + m_aInternalData.insertColumn( nAfterIndex ); + nMaxRep = m_aInternalData.getRowCount(); + } + + // notify change to all affected ranges + tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( "0")); + tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( nMaxRep ))); + std::for_each( aBegin, aEnd, lcl_setModified()); + + tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); + std::for_each( aRange.first, aRange.second, lcl_setModified()); +} + +void SAL_CALL InternalDataProvider::deleteDataPointForAllSequences( ::sal_Int32 nAtIndex ) +{ + sal_Int32 nMaxRep = 0; + if( m_bDataInColumns ) + { + m_aInternalData.deleteRow( nAtIndex ); + nMaxRep = m_aInternalData.getColumnCount(); + } + else + { + m_aInternalData.deleteColumn( nAtIndex ); + nMaxRep = m_aInternalData.getRowCount(); + } + + // notify change to all affected ranges + tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( "0")); + tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( nMaxRep ))); + std::for_each( aBegin, aEnd, lcl_setModified()); + + tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); + std::for_each( aRange.first, aRange.second, lcl_setModified()); +} + +void SAL_CALL InternalDataProvider::swapDataPointWithNextOneForAllSequences( ::sal_Int32 nAtIndex ) +{ + if( m_bDataInColumns ) + m_aInternalData.swapRowWithNext( nAtIndex ); + else + m_aInternalData.swapColumnWithNext( nAtIndex ); + sal_Int32 nMaxRep = (m_bDataInColumns + ? m_aInternalData.getColumnCount() + : m_aInternalData.getRowCount()); + + // notify change to all affected ranges + tSequenceMap::const_iterator aBegin( m_aSequenceMap.lower_bound( "0")); + tSequenceMap::const_iterator aEnd( m_aSequenceMap.upper_bound( OUString::number( nMaxRep ))); + std::for_each( aBegin, aEnd, lcl_setModified()); + + tSequenceMapRange aRange( m_aSequenceMap.equal_range( lcl_aCategoriesRangeName )); + std::for_each( aRange.first, aRange.second, lcl_setModified()); +} + +void SAL_CALL InternalDataProvider::registerDataSequenceForChanges( const Reference< chart2::data::XDataSequence >& xSeq ) +{ + if( xSeq.is()) + addDataSequenceToMap( xSeq->getSourceRangeRepresentation(), xSeq ); +} + +// ____ XRangeXMLConversion ____ +OUString SAL_CALL InternalDataProvider::convertRangeToXML( const OUString& aRangeRepresentation ) +{ + XMLRangeHelper::CellRange aRange; + aRange.aTableName = "local-table"; + + // attention: this data provider has the limitation that it stores + // internally if data comes from columns or rows. It is intended for + // creating only one used data source. + // @todo: add this information in the range representation strings + if( aRangeRepresentation.match( lcl_aCategoriesRangeName )) + { + OSL_ASSERT( aRangeRepresentation == lcl_aCategoriesRangeName );//it is not expected nor implemented that only parts of the categories are really requested + aRange.aUpperLeft.bIsEmpty = false; + if( m_bDataInColumns ) + { + aRange.aUpperLeft.nColumn = 0; + aRange.aUpperLeft.nRow = 1; + aRange.aLowerRight = aRange.aUpperLeft; + aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); + } + else + { + aRange.aUpperLeft.nColumn = 1; + aRange.aUpperLeft.nRow = 0; + aRange.aLowerRight = aRange.aUpperLeft; + aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); + } + } + else if( aRangeRepresentation.match( lcl_aLabelRangePrefix )) + { + sal_Int32 nIndex = o3tl::toInt32(aRangeRepresentation.subView( strlen(lcl_aLabelRangePrefix))); + aRange.aUpperLeft.bIsEmpty = false; + aRange.aLowerRight.bIsEmpty = true; + if( m_bDataInColumns ) + { + aRange.aUpperLeft.nColumn = nIndex + 1; + aRange.aUpperLeft.nRow = 0; + } + else + { + aRange.aUpperLeft.nColumn = 0; + aRange.aUpperLeft.nRow = nIndex + 1; + } + } + else if( aRangeRepresentation == lcl_aCompleteRange ) + { + aRange.aUpperLeft.bIsEmpty = false; + aRange.aLowerRight.bIsEmpty = false; + aRange.aUpperLeft.nColumn = 0; + aRange.aUpperLeft.nRow = 0; + aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); + aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); + } + else + { + sal_Int32 nIndex = aRangeRepresentation.toInt32(); + aRange.aUpperLeft.bIsEmpty = false; + if( m_bDataInColumns ) + { + aRange.aUpperLeft.nColumn = nIndex + 1; + aRange.aUpperLeft.nRow = 1; + aRange.aLowerRight = aRange.aUpperLeft; + aRange.aLowerRight.nRow = m_aInternalData.getRowCount(); + } + else + { + aRange.aUpperLeft.nColumn = 1; + aRange.aUpperLeft.nRow = nIndex + 1; + aRange.aLowerRight = aRange.aUpperLeft; + aRange.aLowerRight.nColumn = m_aInternalData.getColumnCount(); + } + } + + return XMLRangeHelper::getXMLStringFromCellRange( aRange ); +} + +OUString SAL_CALL InternalDataProvider::convertRangeFromXML( const OUString& aXMLRange ) +{ + // Handle non-standards-conforming table:cell-range-address="PivotChart", see + // "PIVOT CHARTS: Save produces + // invalid file because of invalid cell address": + if (aXMLRange == "PivotChart") { + return ""; + } + + static const OUStringLiteral aPivotTableID(u"PT@"); + if (aXMLRange.startsWith(aPivotTableID)) + return aXMLRange.copy(aPivotTableID.getLength()); + + XMLRangeHelper::CellRange aRange( XMLRangeHelper::getCellRangeFromXMLString( aXMLRange )); + if( aRange.aUpperLeft.bIsEmpty ) + { + OSL_ENSURE( aRange.aLowerRight.bIsEmpty, "Weird Range" ); + return OUString(); + } + + // "all" + if( !aRange.aLowerRight.bIsEmpty && + ( aRange.aUpperLeft.nColumn != aRange.aLowerRight.nColumn ) && + ( aRange.aUpperLeft.nRow != aRange.aLowerRight.nRow ) ) + return lcl_aCompleteRange; + + // attention: this data provider has the limitation that it stores + // internally if data comes from columns or rows. It is intended for + // creating only one used data source. + // @todo: add this information in the range representation strings + + // data in columns + if( m_bDataInColumns ) + { + if( aRange.aUpperLeft.nColumn == 0 ) + return lcl_aCategoriesRangeName; + if( aRange.aUpperLeft.nRow == 0 ) + return lcl_aLabelRangePrefix + OUString::number( aRange.aUpperLeft.nColumn - 1 ); + + return OUString::number( aRange.aUpperLeft.nColumn - 1 ); + } + + // data in rows + if( aRange.aUpperLeft.nRow == 0 ) + return lcl_aCategoriesRangeName; + if( aRange.aUpperLeft.nColumn == 0 ) + return lcl_aLabelRangePrefix + OUString::number( aRange.aUpperLeft.nRow - 1 ); + + return OUString::number( aRange.aUpperLeft.nRow - 1 ); +} + +namespace +{ + +template< class Type > +Sequence< Sequence< Type > > lcl_convertVectorVectorToSequenceSequence( const vector< vector< Type > >& rIn ) +{ + Sequence< Sequence< Type > > aRet; + sal_Int32 nOuterCount = rIn.size(); + if( nOuterCount ) + { + aRet.realloc(nOuterCount); + auto pRet = aRet.getArray(); + for( sal_Int32 nN=0; nN +vector< vector< Type > > lcl_convertSequenceSequenceToVectorVector( const Sequence< Sequence< Type > >& rIn ) +{ + vector< vector< Type > > aRet; + sal_Int32 nOuterCount = rIn.getLength(); + if( nOuterCount ) + { + aRet.resize(nOuterCount); + for( sal_Int32 nN=0; nN>( rIn[nN] ); + } + return aRet; +} + +std::vector< Sequence< OUString > > lcl_convertComplexAnyVectorToStringSequence( const vector< vector< uno::Any > >& rIn ) +{ + std::vector< Sequence< OUString > > aRet; + sal_Int32 nOuterCount = rIn.size(); + if( nOuterCount ) + { + aRet.resize(nOuterCount); + for( sal_Int32 nN=0; nN > lcl_convertComplexStringSequenceToAnyVector( const Sequence< Sequence< OUString > >& rIn ) +{ + vector< vector< uno::Any > > aRet; + sal_Int32 nOuterCount = rIn.getLength(); + aRet.reserve(nOuterCount); + for (sal_Int32 nN = 0; nN < nOuterCount; nN++) + aRet.push_back( lcl_StringToAnyVector( rIn[nN] ) ); + return aRet; +} + +class SplitCategoriesProvider_ForComplexDescriptions : public SplitCategoriesProvider +{ +public: + + explicit SplitCategoriesProvider_ForComplexDescriptions( const std::vector< std::vector< uno::Any > >& rComplexDescriptions ) + : m_rComplexDescriptions( rComplexDescriptions ) + {} + + virtual sal_Int32 getLevelCount() const override; + virtual uno::Sequence< OUString > getStringsForLevel( sal_Int32 nIndex ) const override; + +private: + const std::vector< std::vector< uno::Any > >& m_rComplexDescriptions; +}; + +sal_Int32 SplitCategoriesProvider_ForComplexDescriptions::getLevelCount() const +{ + return lcl_getInnerLevelCount( m_rComplexDescriptions ); +} +uno::Sequence< OUString > SplitCategoriesProvider_ForComplexDescriptions::getStringsForLevel( sal_Int32 nLevel ) const +{ + uno::Sequence< OUString > aResult; + if( nLevel < lcl_getInnerLevelCount( m_rComplexDescriptions ) ) + { + aResult.realloc( m_rComplexDescriptions.size() ); + transform( m_rComplexDescriptions.begin(), m_rComplexDescriptions.end(), + aResult.getArray(), lcl_getStringFromLevelVector(nLevel) ); + } + return aResult; +} + +}//anonymous namespace + +// ____ XDateCategories ____ +Sequence< double > SAL_CALL InternalDataProvider::getDateCategories() +{ + const vector< vector< uno::Any > > & aCategories( m_bDataInColumns ? m_aInternalData.getComplexRowLabels() : m_aInternalData.getComplexColumnLabels()); + sal_Int32 nCount = aCategories.size(); + Sequence< double > aDoubles( nCount ); + auto aDoublesRange = asNonConstRange(aDoubles); + sal_Int32 nN=0; + for (auto const& category : aCategories) + { + double fValue; + if( category.empty() || !(category[0]>>=fValue) ) + fValue = std::numeric_limits::quiet_NaN(); + aDoublesRange[nN++]=fValue; + } + return aDoubles; +} + +void SAL_CALL InternalDataProvider::setDateCategories( const Sequence< double >& rDates ) +{ + sal_Int32 nCount = rDates.getLength(); + vector< vector< uno::Any > > aNewCategories; + aNewCategories.reserve(nCount); + vector< uno::Any > aSingleLabel(1); + + for(sal_Int32 nN=0; nN > SAL_CALL InternalDataProvider::getAnyRowDescriptions() +{ + return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexRowLabels() ); +} +void SAL_CALL InternalDataProvider::setAnyRowDescriptions( const Sequence< Sequence< uno::Any > >& aRowDescriptions ) +{ + m_aInternalData.setComplexRowLabels( lcl_convertSequenceSequenceToVectorVector( aRowDescriptions ) ); +} +Sequence< Sequence< uno::Any > > SAL_CALL InternalDataProvider::getAnyColumnDescriptions() +{ + return lcl_convertVectorVectorToSequenceSequence( m_aInternalData.getComplexColumnLabels() ); +} +void SAL_CALL InternalDataProvider::setAnyColumnDescriptions( const Sequence< Sequence< uno::Any > >& aColumnDescriptions ) +{ + m_aInternalData.setComplexColumnLabels( lcl_convertSequenceSequenceToVectorVector( aColumnDescriptions ) ); +} + +// ____ XComplexDescriptionAccess ____ +Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexRowDescriptions() +{ + return comphelper::containerToSequence(lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexRowLabels() )); +} +void SAL_CALL InternalDataProvider::setComplexRowDescriptions( const Sequence< Sequence< OUString > >& aRowDescriptions ) +{ + m_aInternalData.setComplexRowLabels( lcl_convertComplexStringSequenceToAnyVector(aRowDescriptions) ); +} +Sequence< Sequence< OUString > > SAL_CALL InternalDataProvider::getComplexColumnDescriptions() +{ + return comphelper::containerToSequence(lcl_convertComplexAnyVectorToStringSequence( m_aInternalData.getComplexColumnLabels() )); +} +void SAL_CALL InternalDataProvider::setComplexColumnDescriptions( const Sequence< Sequence< OUString > >& aColumnDescriptions ) +{ + m_aInternalData.setComplexColumnLabels( lcl_convertComplexStringSequenceToAnyVector(aColumnDescriptions) ); +} + +// ____ XChartDataArray ____ +Sequence< Sequence< double > > SAL_CALL InternalDataProvider::getData() +{ + return m_aInternalData.getData(); +} + +void SAL_CALL InternalDataProvider::setData( const Sequence< Sequence< double > >& rDataInRows ) +{ + return m_aInternalData.setData( rDataInRows ); +} + +void SAL_CALL InternalDataProvider::setRowDescriptions( const Sequence< OUString >& aRowDescriptions ) +{ + vector< vector< uno::Any > > aComplexDescriptions( aRowDescriptions.getLength() ); + transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aRowDescriptions.getConstArray(), + aComplexDescriptions.begin(), lcl_setAnyAtLevelFromStringSequence(0) ); + m_aInternalData.setComplexRowLabels( std::move(aComplexDescriptions) ); +} + +void SAL_CALL InternalDataProvider::setColumnDescriptions( const Sequence< OUString >& aColumnDescriptions ) +{ + vector< vector< uno::Any > > aComplexDescriptions( aColumnDescriptions.getLength() ); + transform( aComplexDescriptions.begin(), aComplexDescriptions.end(), aColumnDescriptions.getConstArray(), + aComplexDescriptions.begin(), lcl_setAnyAtLevelFromStringSequence(0) ); + m_aInternalData.setComplexColumnLabels( std::move(aComplexDescriptions) ); +} + +Sequence< OUString > SAL_CALL InternalDataProvider::getRowDescriptions() +{ + const vector< vector< uno::Any > > & aComplexLabels( m_aInternalData.getComplexRowLabels() ); + SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels ); + return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider ); +} + +Sequence< OUString > SAL_CALL InternalDataProvider::getColumnDescriptions() +{ + const vector< vector< uno::Any > > & aComplexLabels( m_aInternalData.getComplexColumnLabels() ); + SplitCategoriesProvider_ForComplexDescriptions aProvider( aComplexLabels ); + return ExplicitCategoriesProvider::getExplicitSimpleCategories( aProvider ); +} + +// ____ XChartData (base of XChartDataArray) ____ +void SAL_CALL InternalDataProvider::addChartDataChangeEventListener( + const Reference< css::chart::XChartDataChangeEventListener >& ) +{ +} + +void SAL_CALL InternalDataProvider::removeChartDataChangeEventListener( + const Reference< css::chart::XChartDataChangeEventListener >& ) +{ +} + +double SAL_CALL InternalDataProvider::getNotANumber() +{ + return std::numeric_limits::quiet_NaN(); +} + +sal_Bool SAL_CALL InternalDataProvider::isNotANumber( double nNumber ) +{ + return std::isnan( nNumber ) + || std::isinf( nNumber ); +} +// lang::XInitialization: +void SAL_CALL InternalDataProvider::initialize(const uno::Sequence< uno::Any > & _aArguments) +{ + comphelper::SequenceAsHashMap aArgs(_aArguments); + if ( aArgs.getUnpackedValueOrDefault( "CreateDefaultData", false ) ) + m_aInternalData.createDefaultData(); +} + +// ____ XCloneable ____ +Reference< util::XCloneable > SAL_CALL InternalDataProvider::createClone() +{ + return Reference< util::XCloneable >( new InternalDataProvider( *this )); +} + +OUString SAL_CALL InternalDataProvider::getImplementationName() +{ + // note: in xmloff this name is used to indicate usage of own data + return "com.sun.star.comp.chart.InternalDataProvider"; +} + +sal_Bool SAL_CALL InternalDataProvider::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL InternalDataProvider::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.data.DataProvider" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_InternalDataProvider_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::InternalDataProvider); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LabeledDataSequence.cxx b/chart2/source/tools/LabeledDataSequence.cxx new file mode 100644 index 000000000..9557f05ae --- /dev/null +++ b/chart2/source/tools/LabeledDataSequence.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +LabeledDataSequence::LabeledDataSequence() : + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{} + +LabeledDataSequence::LabeledDataSequence( + const uno::Reference< chart2::data::XDataSequence > & rValues ) : + m_xData( rValues ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + ModifyListenerHelper::addListener( m_xData, m_xModifyEventForwarder ); +} + +LabeledDataSequence::LabeledDataSequence( + const uno::Reference< chart2::data::XDataSequence > & rValues, + const uno::Reference< chart2::data::XDataSequence > & rLabel ) : + m_xData( rValues ), + m_xLabel( rLabel ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + ModifyListenerHelper::addListener( m_xData, m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xLabel, m_xModifyEventForwarder ); +} + +LabeledDataSequence::LabeledDataSequence( const LabeledDataSequence& rSource ) : + impl::LabeledDataSequence_Base(), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + uno::Reference< chart2::data::XDataSequence > xNewValues( rSource.m_xData ); + uno::Reference< chart2::data::XDataSequence > xNewLabel( rSource.m_xLabel ); + + uno::Reference< util::XCloneable > xLabelCloneable( rSource.m_xLabel, uno::UNO_QUERY ); + if( xLabelCloneable.is()) + xNewLabel.set( xLabelCloneable->createClone(), uno::UNO_QUERY ); + + uno::Reference< util::XCloneable > xValuesCloneable( rSource.m_xData, uno::UNO_QUERY ); + if( xValuesCloneable.is()) + xNewValues.set( xValuesCloneable->createClone(), uno::UNO_QUERY ); + + m_xData = xNewValues; + m_xLabel = xNewLabel; + + ModifyListenerHelper::addListener( m_xData, m_xModifyEventForwarder ); + ModifyListenerHelper::addListener( m_xLabel, m_xModifyEventForwarder ); +} + +LabeledDataSequence::~LabeledDataSequence() +{ + if( m_xModifyEventForwarder.is()) + { + if( m_xData.is()) + ModifyListenerHelper::removeListener( m_xData, m_xModifyEventForwarder ); + if( m_xLabel.is()) + ModifyListenerHelper::removeListener( m_xLabel, m_xModifyEventForwarder ); + } +} + +// ____ XLabeledDataSequence ____ +uno::Reference< chart2::data::XDataSequence > SAL_CALL LabeledDataSequence::getValues() +{ + return m_xData; +} + +void SAL_CALL LabeledDataSequence::setValues( + const uno::Reference< chart2::data::XDataSequence >& xSequence ) +{ + if( m_xData != xSequence ) + { + ModifyListenerHelper::removeListener( m_xData, m_xModifyEventForwarder ); + m_xData = xSequence; + ModifyListenerHelper::addListener( m_xData, m_xModifyEventForwarder ); + } +} + +uno::Reference< chart2::data::XDataSequence > SAL_CALL LabeledDataSequence::getLabel() +{ + return m_xLabel; +} + +void SAL_CALL LabeledDataSequence::setLabel( + const uno::Reference< chart2::data::XDataSequence >& xSequence ) +{ + if( m_xLabel != xSequence ) + { + ModifyListenerHelper::removeListener( m_xLabel, m_xModifyEventForwarder ); + m_xLabel = xSequence; + ModifyListenerHelper::addListener( m_xLabel, m_xModifyEventForwarder ); + } +} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL LabeledDataSequence::createClone() +{ + uno::Reference< chart2::data::XDataSequence > xNewValues( m_xData ); + uno::Reference< chart2::data::XDataSequence > xNewLabel( m_xLabel ); + + uno::Reference< util::XCloneable > xLabelCloneable( m_xLabel, uno::UNO_QUERY ); + if( xLabelCloneable.is()) + xNewLabel.set( xLabelCloneable->createClone(), uno::UNO_QUERY ); + + uno::Reference< util::XCloneable > xValuesCloneable( m_xData, uno::UNO_QUERY ); + if( xValuesCloneable.is()) + xNewValues.set( xValuesCloneable->createClone(), uno::UNO_QUERY ); + + return uno::Reference< util::XCloneable >( + new LabeledDataSequence( xNewValues, xNewLabel ) ); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL LabeledDataSequence::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL LabeledDataSequence::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +OUString SAL_CALL LabeledDataSequence::getImplementationName() +{ + return "com.sun.star.comp.chart2.LabeledDataSequence"; +} + +sal_Bool SAL_CALL LabeledDataSequence::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LabeledDataSequence::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.data.LabeledDataSequence" }; +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_LabeledDataSequence_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::LabeledDataSequence ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LegendHelper.cxx b/chart2/source/tools/LegendHelper.cxx new file mode 100644 index 000000000..5bb48f752 --- /dev/null +++ b/chart2/source/tools/LegendHelper.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +rtl::Reference< Legend > LegendHelper::showLegend( ChartModel& rModel + , const uno::Reference< uno::XComponentContext >& xContext ) +{ + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( rModel, xContext, true ); + if( xLegend.is()) + { + xLegend->setPropertyValue( "Show", uno::Any(true) ); + + chart2::RelativePosition aRelativePosition; + if( !(xLegend->getPropertyValue( "RelativePosition") >>= aRelativePosition) ) + { + chart2::LegendPosition ePos = chart2::LegendPosition_LINE_END; + if( !(xLegend->getPropertyValue( "AnchorPosition") >>= ePos ) ) + xLegend->setPropertyValue( "AnchorPosition", uno::Any( ePos )); + + css::chart::ChartLegendExpansion eExpansion = + ( ePos == chart2::LegendPosition_LINE_END || + ePos == chart2::LegendPosition_LINE_START ) + ? css::chart::ChartLegendExpansion_HIGH + : css::chart::ChartLegendExpansion_WIDE; + if( !(xLegend->getPropertyValue( "Expansion") >>= eExpansion ) ) + xLegend->setPropertyValue( "Expansion", uno::Any( eExpansion )); + + xLegend->setPropertyValue( "RelativePosition", uno::Any()); + } + + } + return xLegend; +} + +void LegendHelper::hideLegend( ChartModel& rModel ) +{ + rtl::Reference< Legend > xLegend = LegendHelper::getLegend( rModel, nullptr ); + if( xLegend.is()) + { + xLegend->setPropertyValue( "Show", uno::Any(false) ); + } +} + +rtl::Reference< Legend > LegendHelper::getLegend( + ChartModel& rModel + , const uno::Reference< uno::XComponentContext >& xContext + , bool bCreate ) +{ + rtl::Reference< Legend > xResult; + + try + { + rtl::Reference< Diagram > xDia( rModel.getFirstChartDiagram()); + if( xDia.is() ) + { + xResult = xDia->getLegend2(); + if( bCreate && !xResult.is() && xContext.is() ) + { + xResult = new Legend(); + xDia->setLegend( xResult ); + } + } + else if(bCreate) + { + OSL_FAIL("need diagram for creation of legend"); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +bool LegendHelper::hasLegend( const rtl::Reference< Diagram > & xDiagram ) +{ + bool bReturn = false; + if( xDiagram.is()) + { + uno::Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendProp.is()) + xLegendProp->getPropertyValue( "Show") >>= bReturn; + } + + return bReturn; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LifeTime.cxx b/chart2/source/tools/LifeTime.cxx new file mode 100644 index 000000000..7a84f4f64 --- /dev/null +++ b/chart2/source/tools/LifeTime.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace apphelper +{ + +LifeTimeManager::LifeTimeManager( lang::XComponent* pComponent ) + : m_aListenerContainer( m_aAccessMutex ) + , m_pComponent(pComponent) +{ + m_bDisposed = false; + m_bInDispose = false; + m_nAccessCount = 0; + m_nLongLastingCallCount = 0; + m_aNoAccessCountCondition.set(); + m_aNoLongLastingCallCountCondition.set(); +} + +LifeTimeManager::~LifeTimeManager() +{ +} + +bool LifeTimeManager::impl_isDisposed( bool bAssert ) +{ + if( m_bDisposed || m_bInDispose ) + { + if( bAssert ) + { + OSL_FAIL( "This component is already disposed " ); + } + return true; + } + return false; +} + +bool LifeTimeManager::impl_canStartApiCall() +{ + if( impl_isDisposed() ) + return false; //behave passive if already disposed + + //mutex is acquired + return true; +} + +void LifeTimeManager::impl_registerApiCall(bool bLongLastingCall) +{ + //only allowed if not disposed + //do not acquire the mutex here because it will be acquired already + m_nAccessCount++; + if(m_nAccessCount==1) + //@todo? is it ok to wake some threads here while we have acquired the mutex? + m_aNoAccessCountCondition.reset(); + + if(bLongLastingCall) + m_nLongLastingCallCount++; + if(m_nLongLastingCallCount==1) + m_aNoLongLastingCallCountCondition.reset(); +} + +void LifeTimeManager::impl_unregisterApiCall(bool bLongLastingCall) +{ + //Mutex needs to be acquired exactly once + //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() + + OSL_ENSURE( m_nAccessCount>0, "access count mismatch" ); + m_nAccessCount--; + if(bLongLastingCall) + m_nLongLastingCallCount--; + if( m_nLongLastingCallCount==0 ) + { + m_aNoLongLastingCallCountCondition.set(); + } + if( m_nAccessCount== 0) + { + m_aNoAccessCountCondition.set(); + impl_apiCallCountReachedNull(); + + } +} + +bool LifeTimeManager::dispose() +{ + //hold no mutex + { + osl::MutexGuard aGuard( m_aAccessMutex ); + + if( m_bDisposed || m_bInDispose ) + { + SAL_WARN("chart2", "This component is already disposed " ); + return false; //behave passive if already disposed + } + + m_bInDispose = true; + //adding any listener is not allowed anymore + //new calls will not be accepted + //still running calls have the freedom to finish their work without crash + } + //no mutex is acquired + + //--do the disposing of listeners after calling this method + { + uno::Reference< lang::XComponent > xComponent(m_pComponent); + if(xComponent.is()) + { + // notify XCLoseListeners + lang::EventObject aEvent( xComponent ); + m_aListenerContainer.disposeAndClear( aEvent ); + } + } + + //no mutex is acquired + { + osl::MutexGuard aGuard( m_aAccessMutex ); + OSL_ENSURE( !m_bDisposed, "dispose was called already" ); + m_bDisposed = true; + } + //no mutex is acquired + + //wait until all still running calls have finished + //the accessCount cannot grow anymore, because all calls will return after checking m_bDisposed + m_aNoAccessCountCondition.wait(); + + //we are the only ones working on our data now + + return true; + //--release all resources and references after calling this method successful +} + +CloseableLifeTimeManager::CloseableLifeTimeManager( css::util::XCloseable* pCloseable + , css::lang::XComponent* pComponent ) + : LifeTimeManager( pComponent ) + , m_pCloseable(pCloseable) +{ + m_bClosed = false; + m_bInTryClose = false; + m_bOwnership = false; + m_aEndTryClosingCondition.set(); +} + +CloseableLifeTimeManager::~CloseableLifeTimeManager() +{ +} + +bool CloseableLifeTimeManager::impl_isDisposedOrClosed( bool bAssert ) +{ + if( impl_isDisposed( bAssert ) ) + return true; + + if( m_bClosed ) + { + if( bAssert ) + { + OSL_FAIL( "This object is already closed" ); + } + return true; + } + return false; +} + +bool CloseableLifeTimeManager::g_close_startTryClose(bool bDeliverOwnership) +{ + //no mutex is allowed to be acquired + { + osl::MutexGuard aGuard( m_aAccessMutex ); + if( impl_isDisposedOrClosed(false) ) + return false; + + //Mutex needs to be acquired exactly once; will be released inbetween + if( !impl_canStartApiCall() ) + return false; + //mutex is acquired + + //not closed already -> we try to close again + m_bInTryClose = true; + m_aEndTryClosingCondition.reset(); + + impl_registerApiCall(false); + } + + //no mutex is acquired + + //only remove listener calls will be worked on until end of tryclose + //all other new calls will wait till end of try close // @todo? is that really ok + + //?? still running calls have the freedom to finish their work without crash + + try + { + uno::Reference< util::XCloseable > xCloseable(m_pCloseable); + if(xCloseable.is()) + { + //--call queryClosing on all registered close listeners + ::comphelper::OInterfaceContainerHelper2* pIC = m_aListenerContainer.getContainer( + cppu::UnoType::get()); + if( pIC ) + { + lang::EventObject aEvent( xCloseable ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< util::XCloseListener* >( aIt.next() ) + ->queryClosing( aEvent, bDeliverOwnership ); + } + } + } + } + catch( const uno::Exception& ) + { + //no mutex is acquired + g_close_endTryClose(bDeliverOwnership); + throw; + } + return true; +} + +void CloseableLifeTimeManager::g_close_endTryClose(bool bDeliverOwnership ) +{ + //this method is called, if the try to close was not successful + osl::MutexGuard aGuard( m_aAccessMutex ); + impl_setOwnership( bDeliverOwnership, false ); + + m_bInTryClose = false; + m_aEndTryClosingCondition.set(); + + //Mutex needs to be acquired exactly once + //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() + impl_unregisterApiCall(false); +} + +void CloseableLifeTimeManager::g_close_isNeedToCancelLongLastingCalls( bool bDeliverOwnership, util::CloseVetoException const & ex ) +{ + //this method is called when no closelistener has had a veto during queryclosing + //the method returns false, if nothing stands against closing anymore + //it returns true, if some longlasting calls are running, which might be cancelled + //it throws the given exception, if long calls are running but not cancelable + + osl::MutexGuard aGuard( m_aAccessMutex ); + //this count cannot grow after try of close has started, because we wait in all those methods for end of try closing + if( !m_nLongLastingCallCount ) + return; + + impl_setOwnership( bDeliverOwnership, true ); + + m_bInTryClose = false; + m_aEndTryClosingCondition.set(); + + //Mutex needs to be acquired exactly once + //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() + impl_unregisterApiCall(false); + + throw ex; +} + +void CloseableLifeTimeManager::g_close_endTryClose_doClose() +{ + //this method is called, if the try to close was successful + osl::MutexGuard aGuard( m_aAccessMutex ); + + m_bInTryClose = false; + m_aEndTryClosingCondition.set(); + + //Mutex needs to be acquired exactly once + //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() + impl_unregisterApiCall(false); + impl_doClose(); +} + +void CloseableLifeTimeManager::impl_setOwnership( bool bDeliverOwnership, bool bMyVeto ) +{ + m_bOwnership = bDeliverOwnership && bMyVeto; +} + +void CloseableLifeTimeManager::impl_apiCallCountReachedNull() +{ + //Mutex needs to be acquired exactly once + //mutex will be released inbetween in impl_doClose() + if( m_pCloseable && m_bOwnership ) + impl_doClose(); +} + +void CloseableLifeTimeManager::impl_doClose() +{ + //Mutex needs to be acquired exactly once before calling impl_doClose() + + if(m_bClosed) + return; //behave as passive as possible, if disposed or closed already + if( m_bDisposed || m_bInDispose ) + return; //behave as passive as possible, if disposed or closed already + + m_bClosed = true; + + NegativeGuard< osl::Mutex > aNegativeGuard( m_aAccessMutex ); + //mutex is not acquired, mutex will be reacquired at the end of this method automatically + + uno::Reference< util::XCloseable > xCloseable; + try + { + xCloseable.set(m_pCloseable); + if(xCloseable.is()) + { + //--call notifyClosing on all registered close listeners + ::comphelper::OInterfaceContainerHelper2* pIC = m_aListenerContainer.getContainer( + cppu::UnoType::get()); + if( pIC ) + { + lang::EventObject aEvent( xCloseable ); + ::comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< util::XCloseListener* >( aIt.next() )->notifyClosing( aEvent ); + } + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if(xCloseable.is()) + { + uno::Reference< lang::XComponent > xComponent( xCloseable, uno::UNO_QUERY ); + if(xComponent.is()) + { + OSL_ENSURE( m_bClosed, "a not closed component will be disposed " ); + xComponent->dispose(); + } + } + //mutex will be reacquired in destructor of aNegativeGuard +} + +void CloseableLifeTimeManager::g_addCloseListener( const uno::Reference< util::XCloseListener > & xListener ) +{ + osl::MutexGuard aGuard( m_aAccessMutex ); + //Mutex needs to be acquired exactly once; will be released inbetween + if( !impl_canStartApiCall() ) + return; + //mutex is acquired + + m_aListenerContainer.addInterface( cppu::UnoType::get(),xListener ); + m_bOwnership = false; +} + +bool CloseableLifeTimeManager::impl_canStartApiCall() +{ + //Mutex needs to be acquired exactly once before calling this method + //the mutex will be released inbetween and reacquired + + if( impl_isDisposed() ) + return false; //behave passive if already disposed + if( m_bClosed ) + return false; //behave passive if closing is already done + + //during try-close most calls need to wait for the decision + while( m_bInTryClose ) + { + //if someone tries to close this object at the moment + //we need to wait for his end because the result of the preceding call + //is relevant for our behaviour here + + m_aAccessMutex.release(); + m_aEndTryClosingCondition.wait(); //@todo??? this may block??? try closing + m_aAccessMutex.acquire(); + if( m_bDisposed || m_bInDispose || m_bClosed ) + return false; //return if closed already + } + //mutex is acquired + return true; +} + +bool LifeTimeGuard::startApiCall(bool bLongLastingCall) +{ + //Mutex needs to be acquired exactly once; will be released inbetween + //mutex is required due to constructor of LifeTimeGuard + + OSL_ENSURE( !m_bCallRegistered, "this method is only allowed ones" ); + if(m_bCallRegistered) + return false; + + //Mutex needs to be acquired exactly once; will be released inbetween + if( !m_rManager.impl_canStartApiCall() ) + return false; + //mutex is acquired + + m_bCallRegistered = true; + m_bLongLastingCallRegistered = bLongLastingCall; + m_rManager.impl_registerApiCall(bLongLastingCall); + return true; +} + +LifeTimeGuard::~LifeTimeGuard() +{ + try + { + //do acquire the mutex if it was cleared before + osl::MutexGuard g(m_rManager.m_aAccessMutex); + if(m_bCallRegistered) + { + //Mutex needs to be acquired exactly once + //mutex may be released inbetween in special case of impl_apiCallCountReachedNull() + m_rManager.impl_unregisterApiCall(m_bLongLastingCallRegistered); + } + } + catch( uno::Exception& ex ) + { + //@todo ? allow a uno::RuntimeException from dispose to travel through?? + ex.Context.is(); //to avoid compilation warnings + } +} + +}//end namespace apphelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LinePropertiesHelper.cxx b/chart2/source/tools/LinePropertiesHelper.cxx new file mode 100644 index 000000000..7e6d28860 --- /dev/null +++ b/chart2/source/tools/LinePropertiesHelper.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void LinePropertiesHelper::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // Line Properties see service drawing::LineProperties + rOutProperties.emplace_back( "LineStyle", + PROP_LINE_STYLE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineDash", + PROP_LINE_DASH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + +//not in service description + rOutProperties.emplace_back( "LineDashName", + PROP_LINE_DASH_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "LineColor", + PROP_LINE_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineTransparence", + PROP_LINE_TRANSPARENCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineWidth", + PROP_LINE_WIDTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineJoint", + PROP_LINE_JOINT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "LineCap", + PROP_LINE_CAP, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void LinePropertiesHelper::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LINE_STYLE, drawing::LineStyle_SOLID ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_LINE_WIDTH, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_LINE_COLOR, 0x000000 ); // black + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int16 >( rOutMap, PROP_LINE_TRANSPARENCE, 0 ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LINE_JOINT, drawing::LineJoint_ROUND ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_LINE_CAP, drawing::LineCap_BUTT ); +} + +bool LinePropertiesHelper::IsLineVisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ) +{ + bool bRet = false; + try + { + if( xLineProperties.is() ) + { + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + xLineProperties->getPropertyValue( "LineStyle" ) >>= aLineStyle; + if( aLineStyle != drawing::LineStyle_NONE ) + { + sal_Int16 nLineTransparence=0; + xLineProperties->getPropertyValue( "LineTransparence" ) >>= nLineTransparence; + if(nLineTransparence!=100) + { + bRet = true; + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bRet; +} + +void LinePropertiesHelper::SetLineVisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ) +{ + try + { + if( xLineProperties.is() ) + { + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + xLineProperties->getPropertyValue( "LineStyle" ) >>= aLineStyle; + if( aLineStyle == drawing::LineStyle_NONE ) + xLineProperties->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ); + + sal_Int16 nLineTransparence=0; + xLineProperties->getPropertyValue( "LineTransparence" ) >>= nLineTransparence; + if(nLineTransparence==100) + xLineProperties->setPropertyValue( "LineTransparence", uno::Any( sal_Int16(0) ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void LinePropertiesHelper::SetLineInvisible( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties ) +{ + try + { + if( xLineProperties.is() ) + { + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + xLineProperties->getPropertyValue( "LineStyle" ) >>= aLineStyle; + if( aLineStyle != drawing::LineStyle_NONE ) + xLineProperties->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void LinePropertiesHelper::SetLineColor( const css::uno::Reference< + css::beans::XPropertySet >& xLineProperties, sal_Int32 nColor ) +{ + try + { + if( xLineProperties.is() ) + { + xLineProperties->setPropertyValue( "LineColor", uno::Any( nColor ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LinearRegressionCurveCalculator.cxx b/chart2/source/tools/LinearRegressionCurveCalculator.cxx new file mode 100644 index 000000000..ee836555b --- /dev/null +++ b/chart2/source/tools/LinearRegressionCurveCalculator.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +LinearRegressionCurveCalculator::LinearRegressionCurveCalculator() +{} + +LinearRegressionCurveCalculator::~LinearRegressionCurveCalculator() +{} + +void LinearRegressionCurveCalculator::setRegressionProperties( + sal_Int32 /*aDegree*/, + sal_Bool aForceIntercept, + double aInterceptValue, + sal_Int32 aPeriod, + sal_Int32 /*nMovingType*/) +{ + PolynomialRegressionCurveCalculator::setRegressionProperties( + 1, + aForceIntercept, + aInterceptValue, + aPeriod, + 0); +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL LinearRegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) +{ + if( bMaySkipPointsInCalculation && + isLinearScaling( xScalingX ) && + isLinearScaling( xScalingY )) + { + // optimize result + uno::Sequence< geometry::RealPoint2D > aResult{ { min, getCurveValue( min ) }, + { max, getCurveValue( max ) } }; + + return aResult; + } + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx b/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx new file mode 100644 index 000000000..ffd1808df --- /dev/null +++ b/chart2/source/tools/LogarithmicRegressionCurveCalculator.cxx @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +LogarithmicRegressionCurveCalculator::LogarithmicRegressionCurveCalculator() : + m_fSlope( std::numeric_limits::quiet_NaN() ), + m_fIntercept( std::numeric_limits::quiet_NaN() ) +{ +} + +LogarithmicRegressionCurveCalculator::~LogarithmicRegressionCurveCalculator() +{} + +// ____ XRegressionCurve ____ +void SAL_CALL LogarithmicRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) +{ + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValidAndXPositive())); + + const size_t nMax = aValues.first.size(); + if( nMax <= 1 ) // at least 2 points + { + m_fSlope = std::numeric_limits::quiet_NaN(); + m_fIntercept = std::numeric_limits::quiet_NaN(); + m_fCorrelationCoefficient = std::numeric_limits::quiet_NaN(); + return; + } + + double fAverageX = 0.0, fAverageY = 0.0; + size_t i = 0; + for( i = 0; i < nMax; ++i ) + { + fAverageX += log( aValues.first[i] ); + fAverageY += aValues.second[i]; + } + + const double fN = static_cast< double >( nMax ); + fAverageX /= fN; + fAverageY /= fN; + + double fQx = 0.0, fQy = 0.0, fQxy = 0.0; + for( i = 0; i < nMax; ++i ) + { + double fDeltaX = log( aValues.first[i] ) - fAverageX; + double fDeltaY = aValues.second[i] - fAverageY; + + fQx += fDeltaX * fDeltaX; + fQy += fDeltaY * fDeltaY; + fQxy += fDeltaX * fDeltaY; + } + + m_fSlope = fQxy / fQx; + m_fIntercept = fAverageY - m_fSlope * fAverageX; + m_fCorrelationCoefficient = fQxy / sqrt( fQx * fQy ); +} + +double SAL_CALL LogarithmicRegressionCurveCalculator::getCurveValue( double x ) +{ + if( ! ( std::isnan( m_fSlope ) || + std::isnan( m_fIntercept ))) + { + return m_fSlope * log( x ) + m_fIntercept; + } + + return std::numeric_limits::quiet_NaN(); +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL LogarithmicRegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) +{ + if( bMaySkipPointsInCalculation && + isLogarithmicScaling( xScalingX ) && + isLinearScaling( xScalingY )) + { + // optimize result + uno::Sequence< geometry::RealPoint2D > aResult{ { min, getCurveValue( min ) }, + { max, getCurveValue( max ) } }; + + return aResult; + } + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +OUString LogarithmicRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth /* = nullptr */ ) const +{ + bool bHasSlope = !rtl::math::approxEqual( fabs( m_fSlope ), 1.0 ); + OUStringBuffer aBuf( mYName + " = " ); + sal_Int32 nLineLength = aBuf.getLength(); + sal_Int32 nValueLength=0; + if ( pFormulaMaxWidth && *pFormulaMaxWidth > 0 ) // count nValueLength + { + sal_Int32 nCharMin = nLineLength + 6 + mXName.getLength(); // 6 = "ln(x)" + 2 extra characters + if( m_fSlope < 0.0 ) + nCharMin += 2; // "- " + if( m_fSlope != 0.0 && m_fIntercept != 0.0 ) + { + nCharMin += 3; // " + " + if ( bHasSlope ) + nValueLength = (*pFormulaMaxWidth - nCharMin) / 2; + } + if ( nValueLength == 0 ) // not yet calculated + nValueLength = *pFormulaMaxWidth - nCharMin; + if ( nValueLength <= 0 ) + nValueLength = 1; + } + + // temporary buffer + OUStringBuffer aTmpBuf(""); + // if nValueLength not calculated then nullptr + sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr; + if( m_fSlope != 0.0 ) // add slope value + { + if( m_fSlope < 0.0 ) + { + aTmpBuf.append( OUStringChar(aMinusSign) + " " ); + } + if( bHasSlope ) + { + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fSlope), pValueLength ); + if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small + { + aTmpBuf.append( aValueString + " " ); + } + } + aTmpBuf.append( "ln(" + mXName + ") " ); + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + aTmpBuf.truncate(); + + if( m_fIntercept > 0.0 ) + aTmpBuf.append( "+ " ); + } + // add intercept value + if( m_fIntercept < 0.0 ) + aTmpBuf.append( OUStringChar(aMinusSign) + " " ); + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fIntercept), pValueLength ); + if ( aValueString != "0" ) // aValueString may be rounded to 0 if nValueLength is small + { + aTmpBuf.append( aValueString ); + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + } + + if ( std::u16string_view(aBuf) == OUStringConcatenation(mYName + " = ") ) + aBuf.append( "0" ); + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/MeanValueRegressionCurveCalculator.cxx b/chart2/source/tools/MeanValueRegressionCurveCalculator.cxx new file mode 100644 index 000000000..aefd3f8f0 --- /dev/null +++ b/chart2/source/tools/MeanValueRegressionCurveCalculator.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +MeanValueRegressionCurveCalculator::MeanValueRegressionCurveCalculator() : + m_fMeanValue( std::numeric_limits::quiet_NaN() ) +{ +} + +MeanValueRegressionCurveCalculator::~MeanValueRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL MeanValueRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& /*aXValues*/, + const uno::Sequence< double >& aYValues ) +{ + const sal_Int32 nDataLength = aYValues.getLength(); + sal_Int32 nMax = nDataLength; + double fSumY = 0.0; + const double * pY = aYValues.getConstArray(); + + for( sal_Int32 i = 0; i < nDataLength; ++i ) + { + if( std::isnan( pY[i] ) || + std::isinf( pY[i] )) + --nMax; + else + fSumY += pY[i]; + } + + m_fCorrelationCoefficient = 0.0; + + if( nMax == 0 ) + { + m_fMeanValue = std::numeric_limits::quiet_NaN(); + } + else + { + m_fMeanValue = fSumY / static_cast< double >( nMax ); + + // correlation coefficient: standard deviation + if( nMax > 1 ) + { + double fErrorSum = 0.0; + for( sal_Int32 i = 0; i < nDataLength; ++i ) + { + if( !std::isnan( pY[i] ) && + !std::isinf( pY[i] )) + { + double v = m_fMeanValue - pY[i]; + fErrorSum += (v*v); + } + } + OSL_ASSERT( fErrorSum >= 0.0 ); + m_fCorrelationCoefficient = sqrt( fErrorSum / (nMax - 1 )); + } + } +} + +double SAL_CALL MeanValueRegressionCurveCalculator::getCurveValue( double /*x*/ ) +{ + return m_fMeanValue; +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL MeanValueRegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) +{ + if( bMaySkipPointsInCalculation ) + { + // optimize result + uno::Sequence< geometry::RealPoint2D > aResult{ { min, m_fMeanValue }, + { max, m_fMeanValue } }; + + return aResult; + } + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +OUString MeanValueRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaLength /* = nullptr */ ) const +{ + OUString aBuf(mYName + " = "); + if ( pFormulaLength ) + { + *pFormulaLength -= aBuf.getLength(); + if ( *pFormulaLength <= 0 ) + return "###"; + } + return ( aBuf + getFormattedString( xNumFormatter, nNumberFormatKey, m_fMeanValue, pFormulaLength ) ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/MediaDescriptorHelper.cxx b/chart2/source/tools/MediaDescriptorHelper.cxx new file mode 100644 index 000000000..bd217b0fb --- /dev/null +++ b/chart2/source/tools/MediaDescriptorHelper.cxx @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace apphelper +{ + +MediaDescriptorHelper::MediaDescriptorHelper( const uno::Sequence< + beans::PropertyValue > & rMediaDescriptor ) + : m_aModelProperties(rMediaDescriptor.getLength()) +{ + auto aModelPropertiesRange = asNonConstRange(m_aModelProperties); + css::uno::Sequence< css::beans::PropertyValue > + aRegularProperties(rMediaDescriptor.getLength()); //these are the properties which are described in service com.sun.star.document.MediaDescriptor and not marked as deprecated + auto aRegularPropertiesRange = asNonConstRange(aRegularProperties); + impl_init(); + sal_Int32 nRegularCount = 0; + sal_Int32 nModelCount = 0; + + auto addRegularProp = [&aRegularPropertiesRange, &nRegularCount](const beans::PropertyValue& rRegularProp) + { + aRegularPropertiesRange[nRegularCount] = rRegularProp; + ++nRegularCount; + }; + auto addModelProp = [&aModelPropertiesRange, &nModelCount, &addRegularProp](const beans::PropertyValue& rModelProp) + { + addRegularProp(rModelProp); + aModelPropertiesRange[nModelCount] = rModelProp; + ++nModelCount; + }; + + //read given rMediaDescriptor and store in internal structures: + for( const beans::PropertyValue& rProp : rMediaDescriptor) + { + if (rProp.Name == "AsTemplate") + { + addModelProp(rProp); + } + else if (rProp.Name == "Author") + { + addModelProp(rProp); + } + else if (rProp.Name == "CharacterSet") + { + addModelProp(rProp); + } + else if (rProp.Name == "Comment") + { + addModelProp(rProp); + } + else if (rProp.Name == "ComponentData") + { + addModelProp(rProp); + } + else if (rProp.Name == "FilterData") + { + addModelProp(rProp); + } + else if (rProp.Name == "FilterName") + { + ISSET_FilterName = rProp.Value >>= FilterName; + addModelProp(rProp); + } + else if (rProp.Name == "FilterOptions") + { + addModelProp(rProp); + } + else if (rProp.Name == "FrameName") + { + addModelProp(rProp); + } + else if (rProp.Name == "Hidden") + { + addModelProp(rProp); + } + else if (rProp.Name == "HierarchicalDocumentName") + { + rProp.Value >>= HierarchicalDocumentName; + addModelProp(rProp); + } + else if (rProp.Name == "OutputStream") + { + ISSET_OutputStream = rProp.Value >>= OutputStream; + addRegularProp(rProp); + } + else if (rProp.Name == "InputStream") + { + ISSET_InputStream = rProp.Value >>= InputStream; + addRegularProp(rProp); + } + else if (rProp.Name == "InteractionHandler") + { + addRegularProp(rProp); + } + else if (rProp.Name == "JumpMark") + { + addRegularProp(rProp); + } + else if (rProp.Name == "MediaType") + { + addModelProp(rProp); + } + else if (rProp.Name == "OpenNewView") + { + addRegularProp(rProp); + } + else if (rProp.Name == "Overwrite") + { + addModelProp(rProp); + } + else if (rProp.Name == "Password") + { + addModelProp(rProp); + } + else if (rProp.Name == "PosSize") + { + addRegularProp(rProp); + } + else if (rProp.Name == "PostData") + { + addRegularProp(rProp); + } + else if (rProp.Name == "Preview") + { + addModelProp(rProp); + } + else if (rProp.Name == "ReadOnly") + { + rProp.Value >>= ReadOnly; + addRegularProp(rProp); + } + else if (rProp.Name == "Referer") + { + addModelProp(rProp); + } + else if (rProp.Name == "SetEmbedded") + { + addRegularProp(rProp); + } + else if (rProp.Name == "Silent") + { + addRegularProp(rProp); + } + else if (rProp.Name == "StatusIndicator") + { + addRegularProp(rProp); + } + else if (rProp.Name == "Storage") + { + ISSET_Storage = rProp.Value >>= Storage; + addModelProp(rProp); + } + else if (rProp.Name == "Stream") + { + ISSET_Stream = rProp.Value >>= Stream; + addModelProp(rProp); + } + else if (rProp.Name == "Unpacked") + { + addModelProp(rProp); + } + else if (rProp.Name == "URL") + { + ISSET_URL = rProp.Value >>= URL; + addModelProp(rProp); + } + else if (rProp.Name == "Version") + { + addModelProp(rProp); + } + else if (rProp.Name == "ViewData") + { + addModelProp(rProp); + } + else if (rProp.Name == "ViewId") + { + addModelProp(rProp); + } + } + + aRegularProperties.realloc(nRegularCount); + m_aModelProperties.realloc(nModelCount); +} + +void MediaDescriptorHelper::impl_init() +{ + ISSET_FilterName = false; + + ISSET_OutputStream = false; + ISSET_InputStream = false; + + ReadOnly = false; + ISSET_URL = false; + + ISSET_Storage = false; + ISSET_Stream = false; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ModifyListenerCallBack.cxx b/chart2/source/tools/ModifyListenerCallBack.cxx new file mode 100644 index 000000000..037ee7a78 --- /dev/null +++ b/chart2/source/tools/ModifyListenerCallBack.cxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace chart { + +typedef comphelper::WeakComponentImplHelper< css::util::XModifyListener > + ModifyListenerCallBack_Base; + +class ModifyListenerCallBack_impl + : public ModifyListenerCallBack_Base +{ +public: + explicit ModifyListenerCallBack_impl( const Link& rCallBack ); + + void startListening( const Reference< util::XModifyBroadcaster >& xBroadcaster ); + void stopListening(); + + //XModifyListener + virtual void SAL_CALL modified( const lang::EventObject& aEvent ) override; + + //XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; + + using ::comphelper::WeakComponentImplHelperBase::disposing; + +private: + Link m_aLink;//will be called on modify + Reference< util::XModifyBroadcaster > m_xBroadcaster;//broadcaster to listen at +}; + +ModifyListenerCallBack_impl::ModifyListenerCallBack_impl( const Link& rCallBack ) + : m_aLink( rCallBack ) +{ +} + +//XModifyListener +void SAL_CALL ModifyListenerCallBack_impl::modified( const lang::EventObject& /*aEvent*/ ) +{ + m_aLink.Call(nullptr); +} + +//XEventListener +void SAL_CALL ModifyListenerCallBack_impl::disposing( const lang::EventObject& /*Source*/ ) +{ + m_xBroadcaster.clear(); +} + +void ModifyListenerCallBack_impl::startListening( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyBroadcaster >& xBroadcaster ) +{ + if( m_xBroadcaster == xBroadcaster ) + return; + + stopListening(); + m_xBroadcaster = xBroadcaster; + if( m_xBroadcaster.is() ) + m_xBroadcaster->addModifyListener( this ); +} +void ModifyListenerCallBack_impl::stopListening() +{ + if( m_xBroadcaster.is() ) + { + m_xBroadcaster->removeModifyListener( this ); + m_xBroadcaster.clear(); + } +} + +ModifyListenerCallBack::ModifyListenerCallBack( const Link& rCallBack ) + : pModifyListener_impl( new ModifyListenerCallBack_impl(rCallBack) ) + , m_xModifyListener( pModifyListener_impl ) +{ +} + +ModifyListenerCallBack::~ModifyListenerCallBack() +{ + stopListening(); +} + +void ModifyListenerCallBack::startListening( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyBroadcaster >& xBroadcaster ) +{ + pModifyListener_impl->startListening( xBroadcaster ); +} +void ModifyListenerCallBack::stopListening() +{ + pModifyListener_impl->stopListening(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ModifyListenerHelper.cxx b/chart2/source/tools/ModifyListenerHelper.cxx new file mode 100644 index 000000000..507e79fa3 --- /dev/null +++ b/chart2/source/tools/ModifyListenerHelper.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +ModifyEventForwarder::ModifyEventForwarder() +{ +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL ModifyEventForwarder::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + std::unique_lock aGuard(m_aMutex); + + m_aModifyListeners.addInterface( aGuard, aListener ); +} + +void SAL_CALL ModifyEventForwarder::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + std::unique_lock aGuard(m_aMutex); + + m_aModifyListeners.removeInterface( aGuard, aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL ModifyEventForwarder::modified( const lang::EventObject& aEvent ) +{ + std::unique_lock aGuard(m_aMutex); + + if( m_aModifyListeners.getLength(aGuard) == 0 ) + return; + + m_aModifyListeners.notifyEach( aGuard, &util::XModifyListener::modified, aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL ModifyEventForwarder::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ WeakComponentImplHelperBase ____ +void ModifyEventForwarder::disposing(std::unique_lock& rGuard) +{ + // dispose was called at this + m_aModifyListeners.disposeAndClear( rGuard, lang::EventObject( static_cast(this) ) ); +} + +} // namespace chart::ModifyListenerHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx b/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx new file mode 100644 index 000000000..6726d9d78 --- /dev/null +++ b/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart +{ + +MovingAverageRegressionCurveCalculator::MovingAverageRegressionCurveCalculator() +{} + +MovingAverageRegressionCurveCalculator::~MovingAverageRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL MovingAverageRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) +{ + m_fCorrelationCoefficient = std::numeric_limits::quiet_NaN(); + + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValid())); + + aYList.clear(); + aXList.clear(); + + // For formulas, see + // https://docs.oasis-open.org/office/OpenDocument/v1.3/cs02/part3-schema/OpenDocument-v1.3-cs02-part3-schema.html#property-chart_regression-moving-type + + switch (mnMovingType) + { + case MovingAverageType::Central: + { + + calculateValuesCentral(std::move(aValues)); + break; + } + + case MovingAverageType::AveragedAbscissa: + { + calculateValues(std::move(aValues), true); + break; + } + case MovingAverageType::Prior: + default: + { + calculateValues(std::move(aValues), false); + break; + } + } +} + +void MovingAverageRegressionCurveCalculator::calculateValuesCentral( + RegressionCalculationHelper::tDoubleVectorPair aValues) +{ + const size_t aSize = aValues.first.size(); + if (aSize == 0) + return; + for (size_t i = mPeriod - 1; i < aSize; ++i) + { + double yAvg = 0.0; + + for (sal_Int32 j = 0; j < mPeriod; j++) + { + yAvg += aValues.second[i - j]; + } + yAvg /= mPeriod; + aYList.push_back(yAvg); + } + sal_Int32 nPeriodLocal = (mPeriod % 2 == 0) ? (mPeriod / 2) : ((mPeriod - 1) / 2); + for (size_t i = nPeriodLocal; i < aSize - 1; ++i) + { + double x = aValues.first[i]; + aXList.push_back(x); + } +} + +void MovingAverageRegressionCurveCalculator::calculateValues( + RegressionCalculationHelper::tDoubleVectorPair aValues, bool bUseXAvg) +{ + const size_t aSize = aValues.first.size(); + for (size_t i = mPeriod - 1; i < aSize; ++i) + { + double xAvg = 0.0; + double yAvg = 0.0; + + for (sal_Int32 j = 0; j < mPeriod; j++) + { + xAvg += aValues.first[i - j]; + yAvg += aValues.second[i - j]; + } + yAvg /= mPeriod; + xAvg /= mPeriod; + + aYList.push_back(yAvg); + if (bUseXAvg) + { + aXList.push_back(xAvg); + } + else + { + double x = aValues.first[i]; + aXList.push_back(x); + } + } +} + +double SAL_CALL MovingAverageRegressionCurveCalculator::getCurveValue( double /*x*/ ) +{ + return std::numeric_limits::quiet_NaN(); +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL MovingAverageRegressionCurveCalculator::getCurveValues( + double /*min*/, double /*max*/, sal_Int32 /*nPointCount*/, + const uno::Reference< chart2::XScaling >& /*xScalingX*/, + const uno::Reference< chart2::XScaling >& /*xScalingY*/, + sal_Bool /*bMaySkipPointsInCalculation*/ ) +{ + size_t nSize = std::min(aXList.size(), aYList.size()); + uno::Sequence< geometry::RealPoint2D > aResult( nSize ); + std::transform(aXList.begin(), aXList.begin() + nSize, aYList.begin(), aResult.getArray(), + [](const auto& x, const auto& y) { return geometry::RealPoint2D(x, y); }); + return aResult; +} + +OUString MovingAverageRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& /*xNumFormatter*/, + sal_Int32 /*nNumberFormatKey*/, sal_Int32* /*pFormulaLength = nullptr */ ) const +{ + return SchResId( STR_OBJECT_MOVING_AVERAGE_WITH_PARAMETERS ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/NameContainer.cxx b/chart2/source/tools/NameContainer.cxx new file mode 100644 index 000000000..23e0a2821 --- /dev/null +++ b/chart2/source/tools/NameContainer.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +namespace chart +{ + + +NameContainer::NameContainer() +{ +} + +NameContainer::NameContainer( const NameContainer & rOther ) + : impl::NameContainer_Base(rOther) + , m_aMap( rOther.m_aMap ) +{ +} + +NameContainer::~NameContainer() +{ +} + +//XServiceInfo +OUString SAL_CALL NameContainer::getImplementationName() +{ + return "com.sun.star.comp.chart.XMLNameSpaceMap"; +} + +sal_Bool SAL_CALL NameContainer::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL NameContainer::getSupportedServiceNames() +{ + return { "com.sun.star.xml.NamespaceMap" }; +} + +// XNameContainer +void SAL_CALL NameContainer::insertByName( const OUString& rName, const Any& rElement ) +{ + if( m_aMap.find( rName ) != m_aMap.end() ) + throw container::ElementExistException(); + m_aMap.emplace( rName, rElement ); +} + +void SAL_CALL NameContainer::removeByName( const OUString& Name ) +{ + tContentMap::iterator aIt( m_aMap.find( Name )); + if( aIt == m_aMap.end()) + throw container::NoSuchElementException(); + m_aMap.erase( aIt ); +} + +// XNameReplace +void SAL_CALL NameContainer::replaceByName( const OUString& rName, const Any& rElement ) +{ + tContentMap::iterator aIt( m_aMap.find( rName )); + if( aIt == m_aMap.end() ) + throw container::NoSuchElementException(); + aIt->second = rElement; +} + +// XNameAccess +Any SAL_CALL NameContainer::getByName( const OUString& rName ) +{ + tContentMap::iterator aIter( m_aMap.find( rName ) ); + if( aIter == m_aMap.end() ) + throw container::NoSuchElementException(); + return aIter->second; +} + +Sequence< OUString > SAL_CALL NameContainer::getElementNames() +{ + return comphelper::mapKeysToSequence(m_aMap); +} + +sal_Bool SAL_CALL NameContainer::hasByName( const OUString& rName ) +{ + return ( m_aMap.find( rName ) != m_aMap.end() ); +} + +// XElementAccess +sal_Bool SAL_CALL NameContainer::hasElements() +{ + return ! m_aMap.empty(); +} + +uno::Type SAL_CALL NameContainer::getElementType() +{ + return ::cppu::UnoType::get(); +} + +// XCloneable +uno::Reference< util::XCloneable > SAL_CALL NameContainer::createClone() +{ + return uno::Reference< util::XCloneable >( new NameContainer( *this )); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/NumberFormatterWrapper.cxx b/chart2/source/tools/NumberFormatterWrapper.cxx new file mode 100644 index 000000000..e00df1fae --- /dev/null +++ b/chart2/source/tools/NumberFormatterWrapper.cxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +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() +{ +} + +OUString FixedNumberFormatter::getFormattedString( double fValue, Color& 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(nullptr) + +{ + uno::Reference xProp(m_xNumberFormatsSupplier,uno::UNO_QUERY); + OUString sNullDate( "NullDate" ); + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(sNullDate) ) + m_aNullDate = xProp->getPropertyValue(sNullDate); + SvNumberFormatsSupplierObj* pSupplierObj = comphelper::getFromUnoTunnel( xSupplier ); + if( pSupplierObj ) + m_pNumberFormatter = pSupplierObj->GetNumberFormatter(); + SAL_WARN_IF(!m_pNumberFormatter,"chart2.tools","need a numberformatter"); +} + +NumberFormatterWrapper::~NumberFormatterWrapper() +{ +} + +namespace +{ + bool getDate(const css::uno::Any& rAny, util::Date& rDate) + { + if (rAny >>= rDate) + return true; + util::DateTime aUtilDateTime; + if (rAny >>= aUtilDateTime) + { + rDate.Day = aUtilDateTime.Day; + rDate.Month = aUtilDateTime.Month; + rDate.Year = aUtilDateTime.Year; + return true; + } + SAL_WARN("chart2.tools", "neither a util::Date nor a util::DateTime"); + return false; + } +} + +Date NumberFormatterWrapper::getNullDate() const +{ + Date aRet(30,12,1899); + + util::Date aUtilDate; + if (m_aNullDate.hasValue() && getDate(m_aNullDate, aUtilDate)) + { + aRet = Date(aUtilDate.Day,aUtilDate.Month,aUtilDate.Year); + } + else if( m_pNumberFormatter ) + { + aRet = m_pNumberFormatter->GetNullDate(); + } + return aRet; +} + +OUString NumberFormatterWrapper::getFormattedString( sal_Int32 nNumberFormatKey, double fValue, + Color& rLabelColor, bool& rbColorChanged ) const +{ + OUString aText; + const Color* pTextColor = nullptr; + if( !m_pNumberFormatter ) + { + OSL_FAIL("Need a NumberFormatter"); + return aText; + } + // i99104 handle null date correctly + sal_Int16 nYear = 1899; + sal_uInt16 nDay = 30,nMonth = 12; + if ( m_aNullDate.hasValue() ) + { + const Date& rDate = m_pNumberFormatter->GetNullDate(); + nYear = rDate.GetYear(); + nMonth = rDate.GetMonth(); + nDay = rDate.GetDay(); + util::Date aNewNullDate; + if (getDate(m_aNullDate, aNewNullDate)) + m_pNumberFormatter->ChangeNullDate(aNewNullDate.Day,aNewNullDate.Month,aNewNullDate.Year); + } + // tdf#130969: use UNLIMITED_PRECISION in case of GENERAL Number Format + if( m_pNumberFormatter->GetStandardPrec() != SvNumberFormatter::UNLIMITED_PRECISION ) + m_pNumberFormatter->ChangeStandardPrec(SvNumberFormatter::UNLIMITED_PRECISION); + m_pNumberFormatter->GetOutputString(fValue, nNumberFormatKey, aText, &pTextColor); + if ( m_aNullDate.hasValue() ) + { + m_pNumberFormatter->ChangeNullDate(nDay,nMonth,nYear); + } + + if(pTextColor) + { + rbColorChanged = true; + rLabelColor = *pTextColor; + } + else + rbColorChanged = false; + + return aText; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/OPropertySet.cxx b/chart2/source/tools/OPropertySet.cxx new file mode 100644 index 000000000..bcf92741f --- /dev/null +++ b/chart2/source/tools/OPropertySet.cxx @@ -0,0 +1,464 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +// needed for MS compiler +using ::cppu::OBroadcastHelper; +using ::cppu::OPropertySetHelper; + +namespace property +{ + +OPropertySet::OPropertySet( ::osl::Mutex & par_rMutex ) : + OBroadcastHelper( par_rMutex ), + // the following causes a warning; there seems to be no way to avoid it + OPropertySetHelper( static_cast< OBroadcastHelper & >( *this )), + m_rMutex( par_rMutex ), + m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault(false) +{ +} + +OPropertySet::OPropertySet( const OPropertySet & rOther, ::osl::Mutex & par_rMutex ) : + OBroadcastHelper( par_rMutex ), + // the following causes a warning; there seems to be no way to avoid it + OPropertySetHelper( static_cast< OBroadcastHelper & >( *this )), + m_rMutex( par_rMutex ), + m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault(false) +{ + MutexGuard aGuard( m_rMutex ); + + m_aProperties = rOther.m_aProperties; + + // clone interface properties + for(auto& rProp : m_aProperties) + { + if( rProp.second.hasValue() && + rProp.second.getValueType().getTypeClass() == uno::TypeClass_INTERFACE ) + { + Reference< util::XCloneable > xCloneable; + if( rProp.second >>= xCloneable ) + rProp.second <<= xCloneable->createClone(); + } + } + + m_xStyle.set( ::chart::CloneHelper::CreateRefClone< style::XStyle >()( rOther.m_xStyle )); +} + +void OPropertySet::SetNewValuesExplicitlyEvenIfTheyEqualDefault() +{ + m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault = true; +} + +OPropertySet::~OPropertySet() +{} + +Any SAL_CALL OPropertySet::queryInterface( const uno::Type& aType ) +{ + return ::cppu::queryInterface( + aType, + static_cast< lang::XTypeProvider * >( this ), + static_cast< beans::XPropertySet * >( this ), + static_cast< beans::XMultiPropertySet * >( this ), + static_cast< beans::XFastPropertySet * >( this ), + static_cast< beans::XPropertyState * >( this ), + static_cast< beans::XMultiPropertyStates * >( this ), + static_cast< style::XStyleSupplier * >( this ) ); +} + +// ____ XTypeProvider ____ +Sequence< uno::Type > SAL_CALL + OPropertySet::getTypes() +{ + static const Sequence< uno::Type > aTypeList{ + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get() }; + + return aTypeList; +} + +Sequence< sal_Int8 > SAL_CALL + OPropertySet::getImplementationId() +{ + return css::uno::Sequence(); +} + +// ____ XPropertyState ____ +beans::PropertyState SAL_CALL + OPropertySet::getPropertyState( const OUString& PropertyName ) +{ + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + + return GetPropertyStateByHandle( + rPH.getHandleByName( PropertyName )); +} + +Sequence< beans::PropertyState > SAL_CALL + OPropertySet::getPropertyStates( const Sequence< OUString >& aPropertyName ) +{ + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + + std::unique_ptr pHandles(new sal_Int32[ aPropertyName.getLength() ]); + rPH.fillHandles( pHandles.get(), aPropertyName ); + + std::vector< sal_Int32 > aHandles( pHandles.get(), pHandles.get() + aPropertyName.getLength()); + pHandles.reset(); + + return GetPropertyStatesByHandle( aHandles ); +} + +void SAL_CALL + OPropertySet::setPropertyToDefault( const OUString& PropertyName ) +{ + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + + SetPropertyToDefault( rPH.getHandleByName( PropertyName )); + firePropertyChangeEvent(); +} + +Any SAL_CALL + OPropertySet::getPropertyDefault( const OUString& aPropertyName ) +{ + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + + Any any; + GetDefaultValue( rPH.getHandleByName( aPropertyName ), any ); + return any; +} + +// ____ XMultiPropertyStates ____ + +// Note: getPropertyStates() is already implemented in XPropertyState with the +// same signature + +void SAL_CALL + OPropertySet::setAllPropertiesToDefault() +{ + SetAllPropertiesToDefault(); + firePropertyChangeEvent(); +} + +void SAL_CALL + OPropertySet::setPropertiesToDefault( const Sequence< OUString >& aPropertyNames ) +{ + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + + std::unique_ptr pHandles(new sal_Int32[ aPropertyNames.getLength() ]); + rPH.fillHandles( pHandles.get(), aPropertyNames ); + + std::vector< sal_Int32 > aHandles( pHandles.get(), pHandles.get() + aPropertyNames.getLength()); + pHandles.reset(); + + SetPropertiesToDefault( aHandles ); +} + +Sequence< Any > SAL_CALL + OPropertySet::getPropertyDefaults( const Sequence< OUString >& aPropertyNames ) +{ + ::cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + const sal_Int32 nElements = aPropertyNames.getLength(); + + Sequence< Any > aResult( nElements ); + Any * pResultArray = aResult.getArray(); + sal_Int32 nI = 0; + + for( ; nI < nElements; ++nI ) + { + GetDefaultValue( + rPH.getHandleByName( aPropertyNames[ nI ] ), + pResultArray[ nI ]); + } + + return aResult; +} + +sal_Bool SAL_CALL OPropertySet::convertFastPropertyValue + ( Any & rConvertedValue, + Any & rOldValue, + sal_Int32 nHandle, + const Any& rValue ) +{ + getFastPropertyValue( rOldValue, nHandle ); + //accept longs also for short values + { + sal_Int16 nValue; + if( (rOldValue>>=nValue) && !(rValue>>=nValue) ) + { + sal_Int32 n32Value = 0; + if( rValue>>=n32Value ) + { + rConvertedValue <<= static_cast(n32Value); + return true; + } + + sal_Int64 n64Value = 0; + if( rValue>>=n64Value ) + { + rConvertedValue <<= static_cast(n64Value); + return true; + } + } + } + rConvertedValue = rValue; + if( !m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault && rOldValue == rConvertedValue ) + return false;//no change necessary + return true; +} + +void SAL_CALL OPropertySet::setFastPropertyValue_NoBroadcast + ( sal_Int32 nHandle, + const Any& rValue ) +{ +#if OSL_DEBUG_LEVEL > 0 + if( rValue.hasValue()) + { + cppu::IPropertyArrayHelper & rPH = getInfoHelper(); + OUString aName; + rPH.fillPropertyMembersByHandle( &aName, nullptr, nHandle ); + OSL_ENSURE( rValue.isExtractableTo( rPH.getPropertyByName( aName ).Type ), + "Property type is wrong" ); + } +#endif + + Any aDefault; + try + { + GetDefaultValue( nHandle, aDefault ); + } + catch( const beans::UnknownPropertyException& ) + { + aDefault.clear(); + } + SetPropertyValueByHandle( nHandle, rValue ); + if( !m_bSetNewValuesExplicitlyEvenIfTheyEqualDefault && aDefault.hasValue() && aDefault == rValue ) //#i98893# don't export defaults to file + SetPropertyToDefault( nHandle ); + else + SetPropertyValueByHandle( nHandle, rValue ); +} + +void SAL_CALL OPropertySet::getFastPropertyValue + ( Any& rValue, + sal_Int32 nHandle ) const +{ + if( GetPropertyValueByHandle( rValue, nHandle )) + return; + + // property was not set -> try style + uno::Reference< beans::XFastPropertySet > xStylePropSet( m_xStyle, uno::UNO_QUERY ); + if( xStylePropSet.is() ) + { +#ifdef DBG_UTIL + { + // check if the handle of the style points to the same property + // name as the handle in this property set + uno::Reference< beans::XPropertySet > xPropSet( xStylePropSet, uno::UNO_QUERY ); + if( xPropSet.is()) + { + uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo(); + if( xInfo.is() ) + { + // for some reason the virtual method getInfoHelper() is + // not const + ::cppu::IPropertyArrayHelper & rPH = + const_cast< OPropertySet * >( this )->getInfoHelper(); + + // find the Property with Handle nHandle in Style + Sequence< beans::Property > aProps( xInfo->getProperties() ); + sal_Int32 nI = aProps.getLength() - 1; + while( ( nI >= 0 ) && nHandle != aProps[ nI ].Handle ) + --nI; + + if( nI >= 0 ) // => nHandle == aProps[nI].Handle + { + // check whether the handle in this property set is + // the same as the one in the style + beans::Property aProp( rPH.getPropertyByName( aProps[ nI ].Name ) ); + OSL_ENSURE( nHandle == aProp.Handle, + "HandleCheck: Handles for same property differ!" ); + + if( nHandle == aProp.Handle ) + { + OSL_ENSURE( aProp.Type == aProps[nI].Type, + "HandleCheck: Types differ!" ); + OSL_ENSURE( aProp.Attributes == aProps[nI].Attributes, + "HandleCheck: Attributes differ!" ); + } + } + else + { + OSL_FAIL( "HandleCheck: Handle not found in Style" ); + } + } + else + OSL_FAIL( "HandleCheck: Invalid XPropertySetInfo returned" ); + } + else + OSL_FAIL( "HandleCheck: XPropertySet not supported" ); + } +#endif + rValue = xStylePropSet->getFastPropertyValue( nHandle ); + } + else + { + // there is no style (or the style does not support XFastPropertySet) + // => take the default value + try + { + GetDefaultValue( nHandle, rValue ); + } + catch( const beans::UnknownPropertyException& ) + { + rValue.clear(); + } + } +} + +void OPropertySet::firePropertyChangeEvent() +{ + // nothing in base class +} + +// ____ XStyleSupplier ____ +Reference< style::XStyle > SAL_CALL OPropertySet::getStyle() +{ + return m_xStyle; +} + +void SAL_CALL OPropertySet::setStyle( const Reference< style::XStyle >& xStyle ) +{ + if( ! SetStyle( xStyle )) + throw lang::IllegalArgumentException( + "Empty Style", + static_cast< beans::XPropertySet * >( this ), + 0 ); +} + +// ____ XMultiPropertySet ____ +void SAL_CALL OPropertySet::setPropertyValues( + const Sequence< OUString >& PropertyNames, const Sequence< Any >& Values ) +{ + ::cppu::OPropertySetHelper::setPropertyValues( PropertyNames, Values ); + + firePropertyChangeEvent(); +} + +// ____ XFastPropertySet ____ +void SAL_CALL OPropertySet::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) +{ + ::cppu::OPropertySetHelper::setFastPropertyValue( nHandle, rValue ); + + firePropertyChangeEvent(); +} + +beans::PropertyState OPropertySet::GetPropertyStateByHandle( sal_Int32 nHandle ) const +{ + if( m_aProperties.end() == m_aProperties.find( nHandle )) + return beans::PropertyState_DEFAULT_VALUE; + return beans::PropertyState_DIRECT_VALUE; +} + +Sequence< beans::PropertyState > OPropertySet::GetPropertyStatesByHandle( + const std::vector< sal_Int32 > & aHandles ) const +{ + Sequence< beans::PropertyState > aResult( aHandles.size()); + + std::transform( aHandles.begin(), aHandles.end(), + aResult.getArray(), + [this](sal_Int32 nHandle) { return GetPropertyStateByHandle(nHandle); }); + + return aResult; +} + +void OPropertySet::SetPropertyToDefault( sal_Int32 nHandle ) +{ + tPropertyMap::iterator aFoundIter( m_aProperties.find( nHandle ) ); + + if( m_aProperties.end() != aFoundIter ) + { + m_aProperties.erase( aFoundIter ); + } +} + +void OPropertySet::SetPropertiesToDefault( + const std::vector< sal_Int32 > & aHandles ) +{ + for(auto nHandle : aHandles) + m_aProperties.erase(nHandle); +} + +void OPropertySet::SetAllPropertiesToDefault() +{ + m_aProperties.clear(); +} + +bool OPropertySet::GetPropertyValueByHandle( + Any & rValue, + sal_Int32 nHandle ) const +{ + bool bResult = false; + + tPropertyMap::const_iterator aFoundIter( m_aProperties.find( nHandle ) ); + + if( m_aProperties.end() != aFoundIter ) + { + rValue = (*aFoundIter).second; + bResult = true; + } + + return bResult; +} + +void OPropertySet::SetPropertyValueByHandle( + sal_Int32 nHandle, const Any & rValue ) +{ + m_aProperties[ nHandle ] = rValue; +} + +bool OPropertySet::SetStyle( const Reference< style::XStyle > & xStyle ) +{ + if( ! xStyle.is()) + return false; + + m_xStyle = xStyle; + return true; +} + + +} // namespace property + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ObjectIdentifier.cxx b/chart2/source/tools/ObjectIdentifier.cxx new file mode 100644 index 000000000..8bc65422c --- /dev/null +++ b/chart2/source/tools/ObjectIdentifier.cxx @@ -0,0 +1,1379 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace com::sun::star::drawing { class XShape; } + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +const sal_Unicode m_aMultiClick[] = u"MultiClick"; +const sal_Unicode m_aDragMethodEquals[] = u"DragMethod="; +const sal_Unicode m_aDragParameterEquals[] = u"DragParameter="; +const sal_Unicode m_aProtocol[] = u"CID/"; +const OUString m_aPieSegmentDragMethodServiceName("PieSegmentDragging"); + +namespace +{ + +OUString lcl_createClassificationStringForType( ObjectType eObjectType + , std::u16string_view rDragMethodServiceName + , std::u16string_view rDragParameterString + ) +{ + OUStringBuffer aRet; + switch( eObjectType ) + { + //these object types are all selected only after their parents was selected before + case OBJECTTYPE_LEGEND_ENTRY: //parent is intended to be OBJECTTYPE_LEGEND + case OBJECTTYPE_DATA_POINT: //parent is intended to be OBJECTTYPE_DATA_SERIES + case OBJECTTYPE_DATA_LABEL: //parent is intended to be OBJECTTYPE_DATA_LABELS + case OBJECTTYPE_DATA_ERRORS_X: //parent is intended to be OBJECTTYPE_DATA_ERRORS + case OBJECTTYPE_DATA_ERRORS_Y: //parent is intended to be OBJECTTYPE_DATA_ERRORS + case OBJECTTYPE_DATA_ERRORS_Z: //parent is intended to be OBJECTTYPE_DATA_ERRORS + aRet=m_aMultiClick; + break; + default: + break;//empty string + } + if( !rDragMethodServiceName.empty() ) + { + if( !aRet.isEmpty() ) + aRet.append(":"); + aRet.append( m_aDragMethodEquals ); + aRet.append( rDragMethodServiceName ); + + if( !rDragParameterString.empty() ) + { + if( !aRet.isEmpty() ) + aRet.append(":"); + aRet.append( m_aDragParameterEquals ); + aRet.append( rDragParameterString ); + } + } + return aRet.makeStringAndClear(); +} + +typedef std::map< TitleHelper::eTitleType, OUString > tTitleMap; +const tTitleMap& lcl_getTitleMap() +{ + //maps the title type to the ParentParticle for that title + static tTitleMap s_aTitleMap{ + {TitleHelper::MAIN_TITLE, ""}, + {TitleHelper::SUB_TITLE, "D=0"}, + {TitleHelper::X_AXIS_TITLE, "D=0:CS=0:Axis=0,0"}, + {TitleHelper::Y_AXIS_TITLE, "D=0:CS=0:Axis=1,0"}, + {TitleHelper::Z_AXIS_TITLE, "D=0:CS=0:Axis=2,0"}, + {TitleHelper::SECONDARY_X_AXIS_TITLE, "D=0:CS=0:Axis=0,1"}, + {TitleHelper::SECONDARY_Y_AXIS_TITLE, "D=0:CS=0:Axis=1,1"}}; + return s_aTitleMap; +} + +OUString lcl_getTitleParentParticle( TitleHelper::eTitleType aTitleType ) +{ + OUString aRet; + + const tTitleMap& rMap = lcl_getTitleMap(); + tTitleMap::const_iterator aIt( rMap.find( aTitleType ) ); + if( aIt != rMap.end()) + aRet = (*aIt).second; + + return aRet; +} + +rtl::Reference lcl_getFirstStockChartType( const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if(!xDiagram.is()) + return nullptr; + + //iterate through all coordinate systems + + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); + for( rtl::Reference< BaseCoordinateSystem > const & coords : aCooSysList ) + { + //iterate through all chart types in the current coordinate system + for( rtl::Reference< ChartType > const & xChartType : coords->getChartTypes2() ) + { + OUString aChartType = xChartType->getChartType(); + if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + return xChartType; + } + } + return nullptr; +} + +OUString lcl_getIndexStringAfterString( const OUString& rString, const OUString& rSearchString ) +{ + OUStringBuffer aRet; + + sal_Int32 nIndexStart = rString.lastIndexOf( rSearchString ); + if( nIndexStart != -1 ) + { + nIndexStart += rSearchString.getLength(); + sal_Int32 nIndexEnd = rString.getLength(); + sal_Int32 nNextColon = rString.indexOf( ':', nIndexStart ); + if( nNextColon != -1 ) + nIndexEnd = nNextColon; + aRet = rString.subView(nIndexStart,nIndexEnd-nIndexStart); + } + + return aRet.makeStringAndClear(); +} + +sal_Int32 lcl_StringToIndex( std::u16string_view rIndexString ) +{ + sal_Int32 nRet = -1; + if( !rIndexString.empty() ) + { + nRet = o3tl::toInt32(rIndexString); + if( nRet < -1 ) + nRet = -1; + } + return nRet; +} + +void lcl_parseCooSysIndices( sal_Int32& rnDiagram, sal_Int32& rnCooSys, const OUString& rString ) +{ + rnDiagram = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "D=" ) ); + rnCooSys = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "CS=" ) ); +} + +void lcl_parseAxisIndices( sal_Int32& rnDimensionIndex, sal_Int32& rnAxisIndex, const OUString& rString ) +{ + OUString aAxisIndexString = lcl_getIndexStringAfterString( rString, ":Axis=" ); + sal_Int32 nCharacterIndex=0; + rnDimensionIndex = lcl_StringToIndex( o3tl::getToken(aAxisIndexString, 0, ',', nCharacterIndex ) ); + rnAxisIndex = lcl_StringToIndex( o3tl::getToken(aAxisIndexString, 0, ',', nCharacterIndex ) ); +} + +void lcl_parseGridIndices( sal_Int32& rnSubGridIndex, const OUString& rString ) +{ + rnSubGridIndex = -1; + rnSubGridIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, ":SubGrid=" ) ); +} + +void lcl_parseSeriesIndices( sal_Int32& rnChartTypeIndex, sal_Int32& rnSeriesIndex, sal_Int32& rnPointIndex, const OUString& rString ) +{ + rnChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "CT=" ) ); + rnSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "Series=" ) ); + rnPointIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rString, "Point=" ) ); +} + +void lcl_getDiagramAndCooSys( const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel + , rtl::Reference< Diagram >& xDiagram + , rtl::Reference< BaseCoordinateSystem >& xCooSys ) +{ + sal_Int32 nDiagramIndex = -1; + sal_Int32 nCooSysIndex = -1; + lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rObjectCID ); + xDiagram = ChartModelHelper::findDiagram( xChartModel );//todo use nDiagramIndex when more than one diagram is possible in future + if( !xDiagram.is() ) + return; + + if( nCooSysIndex > -1 ) + { + const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysList( xDiagram->getBaseCoordinateSystems() ); + if( o3tl::make_unsigned(nCooSysIndex) < aCooSysList.size() ) + xCooSys = aCooSysList[nCooSysIndex]; + } +} + +} //anonymous namespace + +ObjectIdentifier::ObjectIdentifier() +{ +} + +ObjectIdentifier::ObjectIdentifier( const OUString& rObjectCID ) + :m_aObjectCID( rObjectCID ) +{ +} + +ObjectIdentifier::ObjectIdentifier( const Reference< drawing::XShape >& rxShape ) + : m_xAdditionalShape( rxShape ) +{ +} + +ObjectIdentifier::ObjectIdentifier( const Any& rAny ) +{ + const uno::Type& rType = rAny.getValueType(); + if ( rType == cppu::UnoType::get() ) + { + rAny >>= m_aObjectCID; + } + else if ( rType == cppu::UnoType< drawing::XShape >::get() ) + { + rAny >>= m_xAdditionalShape; + } +} + +bool ObjectIdentifier::operator==( const ObjectIdentifier& rOID ) const +{ + return areIdenticalObjects( m_aObjectCID, rOID.m_aObjectCID ) && + ( m_xAdditionalShape == rOID.m_xAdditionalShape ); +} + +bool ObjectIdentifier::operator!=( const ObjectIdentifier& rOID ) const +{ + return !operator==( rOID ); +} + +bool ObjectIdentifier::operator<( const ObjectIdentifier& rOID ) const +{ + bool bReturn = false; + if ( !(m_aObjectCID.isEmpty() || rOID.m_aObjectCID.isEmpty()) ) + { + bReturn = ( m_aObjectCID.compareTo( rOID.m_aObjectCID ) < 0 ); + } + else if ( !m_aObjectCID.isEmpty() ) + { + bReturn = true; + } + else if ( !rOID.m_aObjectCID.isEmpty() ) + { + bReturn = false; + } + else if ( m_xAdditionalShape.is() && rOID.m_xAdditionalShape.is() ) + { + bReturn = ( m_xAdditionalShape < rOID.m_xAdditionalShape ); + } + return bReturn; +} + +OUString ObjectIdentifier::createClassifiedIdentifierForObject( + const Reference< uno::XInterface >& xObject + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + enum ObjectType eObjectType = OBJECTTYPE_UNKNOWN; + const std::u16string_view aObjectID; + OUString aParentParticle; + const std::u16string_view aDragMethodServiceName; + const std::u16string_view aDragParameterString; + + try + { + //title + Reference< XTitle > xTitle( xObject, uno::UNO_QUERY ); + if( xTitle.is() ) + { + TitleHelper::eTitleType aTitleType; + if( TitleHelper::getTitleType( aTitleType, xTitle, xChartModel ) ) + { + eObjectType = OBJECTTYPE_TITLE; + aParentParticle = lcl_getTitleParentParticle( aTitleType ); + aRet = ObjectIdentifier::createClassifiedIdentifierWithParent( + eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString ); + } + return aRet; + + } + + //axis + Reference< XAxis > xAxis( xObject, uno::UNO_QUERY ); + if( xAxis.is() ) + { + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) ) ); + OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, xChartModel ) ); + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) ); + return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle ); + } + + //legend + Reference< XLegend > xLegend( xObject, uno::UNO_QUERY ); + if( xLegend.is() ) + { + return createClassifiedIdentifierForParticle( createParticleForLegend( xChartModel ) ); + } + + //diagram + Reference< XDiagram > xDiagram( xObject, uno::UNO_QUERY ); + if( xDiagram.is() ) + { + return createClassifiedIdentifierForParticle( createParticleForDiagram() ); + } + + //todo + //XDataSeries + //CooSys + //charttype + //datapoint? + //Gridproperties + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( eObjectType != OBJECTTYPE_UNKNOWN ) + { + aRet = ObjectIdentifier::createClassifiedIdentifierWithParent( + eObjectType, aObjectID, aParentParticle, aDragMethodServiceName, aDragParameterString ); + } + else + { + OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); + } + + return aRet; +} + +OUString ObjectIdentifier::createClassifiedIdentifierForObject( + const rtl::Reference< Legend >& xLegend + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + try + { + if( xLegend.is() ) + { + return createClassifiedIdentifierForParticle( createParticleForLegend( xChartModel ) ); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); + + return OUString(); +} + +OUString ObjectIdentifier::createClassifiedIdentifierForObject( + const rtl::Reference<::chart::Axis>& xAxis + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + try + { + //axis + if( xAxis.is() ) + { + rtl::Reference< BaseCoordinateSystem > xCooSys( AxisHelper::getCoordinateSystemOfAxis( xAxis, ChartModelHelper::findDiagram( xChartModel ) ) ); + OUString aCooSysParticle( createParticleForCoordinateSystem( xCooSys, xChartModel ) ); + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ); + OUString aAxisParticle( createParticleForAxis( nDimensionIndex, nAxisIndex ) ); + return createClassifiedIdentifierForParticles( aCooSysParticle, aAxisParticle ); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + OSL_FAIL("give object could not be identified in createClassifiedIdentifierForObject"); + + return OUString(); +} + +OUString ObjectIdentifier::createClassifiedIdentifierForParticle( + std::u16string_view rParticle ) +{ + return ObjectIdentifier::createClassifiedIdentifierForParticles( rParticle, u"" ); +} + +OUString ObjectIdentifier::createClassifiedIdentifierForParticles( + std::u16string_view rParentParticle + , std::u16string_view rChildParticle + , std::u16string_view rDragMethodServiceName + , std::u16string_view rDragParameterString ) +{ + ObjectType eObjectType( ObjectIdentifier::getObjectType( rChildParticle ) ); + if( eObjectType == OBJECTTYPE_UNKNOWN ) + eObjectType = ObjectIdentifier::getObjectType( rParentParticle ); + + OUStringBuffer aRet( m_aProtocol ); + aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString )); + if(o3tl::make_unsigned(aRet.getLength()) >= std::size(m_aProtocol)) + aRet.append("/"); + + if(!rParentParticle.empty()) + { + aRet.append(rParentParticle); + if( !rChildParticle.empty() ) + aRet.append(":"); + } + aRet.append(rChildParticle); + + return aRet.makeStringAndClear(); +} + +OUString ObjectIdentifier::createParticleForDiagram() +{ + //TODO: if more than one diagram is implemented, add the correct diagram index here + return "D=0"; +} + +OUString ObjectIdentifier::createParticleForCoordinateSystem( + const rtl::Reference< BaseCoordinateSystem >& xCooSys + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + OUString aRet; + + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xChartModel ) ); + if( xDiagram.is() ) + { + std::size_t nCooSysIndex = 0; + const std::vector< rtl::Reference< BaseCoordinateSystem > > & aCooSysList( xDiagram->getBaseCoordinateSystems() ); + for( ; nCooSysIndex < aCooSysList.size(); ++nCooSysIndex ) + { + if( xCooSys == aCooSysList[nCooSysIndex] ) + { + aRet = ObjectIdentifier::createParticleForDiagram() + ":CS=" + OUString::number( nCooSysIndex ); + break; + } + } + } + + return aRet; +} + +OUString ObjectIdentifier::createParticleForAxis( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex ) +{ + return "Axis=" + + OUString::number( nDimensionIndex ) + + "," + + OUString::number( nAxisIndex ); +} + +OUString ObjectIdentifier::createParticleForGrid( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex ) +{ + OUString aRet = "Axis=" + OUString::number( nDimensionIndex ) + + "," + OUString::number( nAxisIndex ) + ":Grid=0"; + + return aRet; +} + +OUString ObjectIdentifier::createClassifiedIdentifierForGrid( + const Reference< XAxis >& xAxis + , const rtl::Reference<::chart::ChartModel>& xChartModel + , sal_Int32 nSubGridIndex ) +{ + //-1: main grid, 0: first subgrid etc + + OUString aAxisCID( createClassifiedIdentifierForObject( xAxis, xChartModel ) ); + OUString aGridCID( addChildParticle( aAxisCID + , createChildParticleWithIndex( OBJECTTYPE_GRID, 0 ) ) ); + if( nSubGridIndex >= 0 ) + { + aGridCID = addChildParticle( aGridCID + , createChildParticleWithIndex( OBJECTTYPE_SUBGRID, 0 ) ); + } + return aGridCID; +} + +OUString ObjectIdentifier::createParticleForSeries( + sal_Int32 nDiagramIndex, sal_Int32 nCooSysIndex + , sal_Int32 nChartTypeIndex, sal_Int32 nSeriesIndex ) +{ + return + "D=" + OUString::number( nDiagramIndex ) + + ":CS=" + OUString::number( nCooSysIndex ) + + ":CT=" + OUString::number( nChartTypeIndex ) + + ":" + getStringForType( OBJECTTYPE_DATA_SERIES ) + "=" + + OUString::number( nSeriesIndex ); +} + + +OUString ObjectIdentifier::createParticleForLegend( + const rtl::Reference<::chart::ChartModel>& ) +{ + //todo: if more than one diagram is implemented, find the correct diagram which is owner of the given legend + + return ObjectIdentifier::createParticleForDiagram() + ":" + getStringForType( OBJECTTYPE_LEGEND ) + "="; +} + +OUString ObjectIdentifier::createClassifiedIdentifier( + enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_SERIES + , std::u16string_view rParticleID )//e.g. SeriesID +{ + return createClassifiedIdentifierWithParent( + eObjectType, rParticleID, u"" ); +} + +OUString ObjectIdentifier::createClassifiedIdentifierWithParent( + enum ObjectType eObjectType //e.g. OBJECTTYPE_DATA_POINT or OBJECTTYPE_GRID + , std::u16string_view rParticleID //e.g. Point Index or SubGrid Index + , std::u16string_view rParentPartical //e.g. "Series=SeriesID" or "Grid=GridId" + , std::u16string_view rDragMethodServiceName + , std::u16string_view rDragParameterString + ) + //, bool bIsMultiClickObject ) //e.g. true +{ + //e.g. "MultiClick/Series=2:Point=34" + + OUStringBuffer aRet( m_aProtocol ); + aRet.append( lcl_createClassificationStringForType( eObjectType, rDragMethodServiceName, rDragParameterString )); + if(o3tl::make_unsigned(aRet.getLength()) >= std::size(m_aProtocol)) + aRet.append("/"); + aRet.append(rParentPartical); + if(!rParentPartical.empty()) + aRet.append(":"); + + aRet.append(getStringForType( eObjectType )); + aRet.append("="); + aRet.append(rParticleID); + + return aRet.makeStringAndClear(); +} + +const OUString& ObjectIdentifier::getPieSegmentDragMethodServiceName() +{ + return m_aPieSegmentDragMethodServiceName; +} + +OUString ObjectIdentifier::createPieSegmentDragParameterString( + sal_Int32 nOffsetPercent + , const awt::Point& rMinimumPosition + , const awt::Point& rMaximumPosition ) +{ + OUString aRet = OUString::number( nOffsetPercent ) + + "," + OUString::number( rMinimumPosition.X ) + + "," + OUString::number( rMinimumPosition.Y ) + + "," + OUString::number( rMaximumPosition.X ) + + "," + OUString::number( rMaximumPosition.Y ); + return aRet; +} + +bool ObjectIdentifier::parsePieSegmentDragParameterString( + std::u16string_view rDragParameterString + , sal_Int32& rOffsetPercent + , awt::Point& rMinimumPosition + , awt::Point& rMaximumPosition ) +{ + sal_Int32 nCharacterIndex = 0; + + std::u16string_view aValueString( o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ) ); + rOffsetPercent = o3tl::toInt32(aValueString); + if( nCharacterIndex < 0 ) + return false; + + aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); + rMinimumPosition.X = o3tl::toInt32(aValueString); + if( nCharacterIndex < 0 ) + return false; + + aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); + rMinimumPosition.Y = o3tl::toInt32(aValueString); + if( nCharacterIndex < 0 ) + return false; + + aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); + rMaximumPosition.X = o3tl::toInt32(aValueString); + if( nCharacterIndex < 0 ) + return false; + + aValueString = o3tl::getToken(rDragParameterString, 0, ',', nCharacterIndex ); + rMaximumPosition.Y = o3tl::toInt32(aValueString); + return nCharacterIndex >= 0; +} + +std::u16string_view ObjectIdentifier::getDragMethodServiceName( std::u16string_view rCID ) +{ + std::u16string_view aRet; + + size_t nIndexStart = rCID.find( m_aDragMethodEquals ); + if( nIndexStart != std::u16string_view::npos ) + { + nIndexStart = rCID.find( '=', nIndexStart ); + if( nIndexStart != std::u16string_view::npos ) + { + nIndexStart++; + size_t nNextSlash = rCID.find( '/', nIndexStart ); + if( nNextSlash != std::u16string_view::npos ) + { + sal_Int32 nIndexEnd = nNextSlash; + size_t nNextColon = rCID.find( ':', nIndexStart ); + if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash ) + nIndexEnd = nNextColon; + aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart); + } + } + } + return aRet; +} + +std::u16string_view ObjectIdentifier::getDragParameterString( std::u16string_view rCID ) +{ + std::u16string_view aRet; + + size_t nIndexStart = rCID.find( m_aDragParameterEquals ); + if( nIndexStart != std::u16string_view::npos ) + { + nIndexStart = rCID.find( '=', nIndexStart ); + if( nIndexStart != std::u16string_view::npos ) + { + nIndexStart++; + size_t nNextSlash = rCID.find( '/', nIndexStart ); + if( nNextSlash != std::u16string_view::npos ) + { + sal_Int32 nIndexEnd = nNextSlash; + size_t nNextColon = rCID.find( ':', nIndexStart ); + if( nNextColon == std::u16string_view::npos || nNextColon < nNextSlash ) + nIndexEnd = nNextColon; + aRet = rCID.substr(nIndexStart,nIndexEnd-nIndexStart); + } + } + } + return aRet; +} + +bool ObjectIdentifier::isDragableObject( std::u16string_view rClassifiedIdentifier ) +{ + bool bReturn = false; + ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier ); + switch( eObjectType ) + { + case OBJECTTYPE_TITLE: + case OBJECTTYPE_LEGEND: + case OBJECTTYPE_DIAGRAM: + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_CURVE_EQUATION: + //case OBJECTTYPE_DIAGRAM_WALL: + bReturn = true; + break; + default: + std::u16string_view aDragMethodServiceName( ObjectIdentifier::getDragMethodServiceName( rClassifiedIdentifier ) ); + bReturn = !aDragMethodServiceName.empty(); + break; + } + return bReturn; +} + +bool ObjectIdentifier::isDragableObject() const +{ + bool bReturn = false; + if ( isAutoGeneratedObject() ) + { + bReturn = isDragableObject( m_aObjectCID ); + } + else if ( isAdditionalShape() ) + { + bReturn = true; + } + return bReturn; +} + +bool ObjectIdentifier::isRotateableObject( std::u16string_view rClassifiedIdentifier ) +{ + bool bReturn = false; + ObjectType eObjectType = ObjectIdentifier::getObjectType( rClassifiedIdentifier ); + switch( eObjectType ) + { + case OBJECTTYPE_DIAGRAM: + //case OBJECTTYPE_DIAGRAM_WALL: + bReturn = true; + break; + default: + bReturn = false; + break; + } + return bReturn; +} + +bool ObjectIdentifier::isMultiClickObject( std::u16string_view rClassifiedIdentifier ) +{ + //the name of a shape is it's ClassifiedIdentifier + + //a MultiClickObject is an object that is selectable by more than one click only ; + //before a MultiClickObject can be selected it is necessary that a named parent group object + //was selected before; + + //!!!!! by definition the name of a MultiClickObject starts with "CID/MultiClick:" + bool bRet = o3tl::starts_with(rClassifiedIdentifier.substr( std::size(m_aProtocol)-1 ), m_aMultiClick); + return bRet; +} + +bool ObjectIdentifier::areSiblings( const OUString& rCID1, const OUString& rCID2 ) +{ + bool bRet=false; + sal_Int32 nLastSign1 = rCID1.lastIndexOf( '=' ); + sal_Int32 nLastSign2 = rCID2.lastIndexOf( '=' ); + if( nLastSign1 == rCID1.indexOf( '=' ) )//CID cannot be sibling if only one "=" occurs + bRet=false; + else if( nLastSign2 == rCID2.indexOf( '=' ) )//CID cannot be sibling if only one "=" occurs + bRet=false; + else if( ObjectIdentifier::areIdenticalObjects( rCID1, rCID2 ) ) + bRet=false; + else + { + std::u16string_view aParent1( ObjectIdentifier::getFullParentParticle( rCID1 ) ); + if( !aParent1.empty() ) + { + std::u16string_view aParent2( ObjectIdentifier::getFullParentParticle( rCID2 ) ); + bRet=aParent1 == aParent2; + } + //legend entries are special: + if(!bRet) + { + if( getObjectType(rCID1) == OBJECTTYPE_LEGEND_ENTRY + && getObjectType(rCID2) == OBJECTTYPE_LEGEND_ENTRY ) + bRet = true; + } + } + return bRet; +} + +bool ObjectIdentifier::areIdenticalObjects( const OUString& rCID1, const OUString& rCID2 ) +{ + if( rCID1 == rCID2 ) + return true; + //draggable pie or donut segments need special treatment, as their CIDs do change with offset + { + if( rCID1.indexOf( m_aPieSegmentDragMethodServiceName ) < 0 + || rCID2.indexOf( m_aPieSegmentDragMethodServiceName ) < 0 ) + return false; + + OUString aID1( ObjectIdentifier::getObjectID( rCID1 ) ); + OUString aID2( ObjectIdentifier::getObjectID( rCID2 ) ); + if( !aID1.isEmpty() && aID1 == aID2 ) + return true; + } + return false; +} + +OUString ObjectIdentifier::getStringForType( ObjectType eObjectType ) +{ + OUString aRet; + switch( eObjectType ) + { + case OBJECTTYPE_PAGE: + aRet="Page"; + break; + case OBJECTTYPE_TITLE: + aRet="Title"; + break; + case OBJECTTYPE_LEGEND: + aRet="Legend"; + break; + case OBJECTTYPE_LEGEND_ENTRY: + aRet="LegendEntry"; + break; + case OBJECTTYPE_DIAGRAM: + aRet="D"; + break; + case OBJECTTYPE_DIAGRAM_WALL: + aRet="DiagramWall"; + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + aRet="DiagramFloor"; + break; + case OBJECTTYPE_AXIS: + aRet="Axis"; + break; + case OBJECTTYPE_AXIS_UNITLABEL: + aRet="AxisUnitLabel"; + break; + case OBJECTTYPE_GRID: + aRet="Grid"; + break; + case OBJECTTYPE_SUBGRID: + aRet="SubGrid"; + break; + case OBJECTTYPE_DATA_SERIES: + aRet="Series"; + break; + case OBJECTTYPE_DATA_POINT: + aRet="Point"; + break; + case OBJECTTYPE_DATA_LABELS: + aRet="DataLabels"; + break; + case OBJECTTYPE_DATA_LABEL: + aRet="DataLabel"; + break; + case OBJECTTYPE_DATA_ERRORS_X: + aRet="ErrorsX"; + break; + case OBJECTTYPE_DATA_ERRORS_Y: + aRet="ErrorsY"; + break; + case OBJECTTYPE_DATA_ERRORS_Z: + aRet="ErrorsZ"; + break; + case OBJECTTYPE_DATA_CURVE: + aRet="Curve"; + break; + case OBJECTTYPE_DATA_CURVE_EQUATION: + aRet="Equation"; + break; + case OBJECTTYPE_DATA_AVERAGE_LINE: + aRet="Average"; + break; + case OBJECTTYPE_DATA_STOCK_RANGE: + aRet="StockRange"; + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + aRet="StockLoss"; + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + aRet="StockGain"; + break; + default: //OBJECTTYPE_UNKNOWN + ; + } + return aRet; +} + +ObjectType ObjectIdentifier::getObjectType( std::u16string_view aCID ) +{ + ObjectType eRet; + size_t nLastSign = aCID.rfind( ':' );//last sign before the type string + if(nLastSign == std::u16string_view::npos) + nLastSign = aCID.rfind( '/' ); + if(nLastSign == std::u16string_view::npos) + { + size_t nEndIndex = aCID.rfind( '=' ); + if(nEndIndex == std::u16string_view::npos) + return OBJECTTYPE_UNKNOWN; + nLastSign = 0; + } + if( nLastSign>0 ) + nLastSign++; + + aCID = aCID.substr(nLastSign); + if( o3tl::starts_with(aCID, u"Page") ) + eRet = OBJECTTYPE_PAGE; + else if( o3tl::starts_with(aCID, u"Title") ) + eRet = OBJECTTYPE_TITLE; + else if( o3tl::starts_with(aCID, u"LegendEntry") ) + eRet = OBJECTTYPE_LEGEND_ENTRY; + else if( o3tl::starts_with(aCID, u"Legend") ) + eRet = OBJECTTYPE_LEGEND; + else if( o3tl::starts_with(aCID, u"DiagramWall") ) + eRet = OBJECTTYPE_DIAGRAM_WALL; + else if( o3tl::starts_with(aCID, u"DiagramFloor") ) + eRet = OBJECTTYPE_DIAGRAM_FLOOR; + else if( o3tl::starts_with(aCID, u"D=") ) + eRet = OBJECTTYPE_DIAGRAM; + else if( o3tl::starts_with(aCID, u"AxisUnitLabel") ) + eRet = OBJECTTYPE_AXIS_UNITLABEL; + else if( o3tl::starts_with(aCID, u"Axis") ) + eRet = OBJECTTYPE_AXIS; + else if( o3tl::starts_with(aCID, u"Grid") ) + eRet = OBJECTTYPE_GRID; + else if( o3tl::starts_with(aCID, u"SubGrid") ) + eRet = OBJECTTYPE_SUBGRID; + else if( o3tl::starts_with(aCID, u"Series") ) + eRet = OBJECTTYPE_DATA_SERIES; + else if( o3tl::starts_with(aCID, u"Point") ) + eRet = OBJECTTYPE_DATA_POINT; + else if( o3tl::starts_with(aCID, u"DataLabels") ) + eRet = OBJECTTYPE_DATA_LABELS; + else if( o3tl::starts_with(aCID, u"DataLabel") ) + eRet = OBJECTTYPE_DATA_LABEL; + else if( o3tl::starts_with(aCID, u"ErrorsX") ) + eRet = OBJECTTYPE_DATA_ERRORS_X; + else if( o3tl::starts_with(aCID, u"ErrorsY") ) + eRet = OBJECTTYPE_DATA_ERRORS_Y; + else if( o3tl::starts_with(aCID, u"ErrorsZ") ) + eRet = OBJECTTYPE_DATA_ERRORS_Z; + else if( o3tl::starts_with(aCID, u"Curve") ) + eRet = OBJECTTYPE_DATA_CURVE; + else if( o3tl::starts_with(aCID, u"Equation") ) + eRet = OBJECTTYPE_DATA_CURVE_EQUATION; + else if( o3tl::starts_with(aCID, u"Average") ) + eRet = OBJECTTYPE_DATA_AVERAGE_LINE; + else if( o3tl::starts_with(aCID, u"StockRange") ) + eRet = OBJECTTYPE_DATA_STOCK_RANGE; + else if( o3tl::starts_with(aCID, u"StockLoss") ) + eRet = OBJECTTYPE_DATA_STOCK_LOSS; + else if( o3tl::starts_with(aCID, u"StockGain") ) + eRet = OBJECTTYPE_DATA_STOCK_GAIN; + else + eRet = OBJECTTYPE_UNKNOWN; + + return eRet; +} + +ObjectType ObjectIdentifier::getObjectType() const +{ + ObjectType eObjectType( OBJECTTYPE_UNKNOWN ); + if ( isAutoGeneratedObject() ) + { + eObjectType = getObjectType( m_aObjectCID ); + } + else if ( isAdditionalShape() ) + { + eObjectType = OBJECTTYPE_SHAPE; + } + return eObjectType; +} + +OUString ObjectIdentifier::createDataCurveCID( + std::u16string_view rSeriesParticle + , sal_Int32 nCurveIndex + , bool bAverageLine ) +{ + OUString aParticleID( OUString::number( nCurveIndex ) ); + ObjectType eType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE; + return createClassifiedIdentifierWithParent( eType, aParticleID, rSeriesParticle ); +} + +OUString ObjectIdentifier::createDataCurveEquationCID( + std::u16string_view rSeriesParticle + , sal_Int32 nCurveIndex ) +{ + OUString aParticleID( OUString::number( nCurveIndex ) ); + return createClassifiedIdentifierWithParent( OBJECTTYPE_DATA_CURVE_EQUATION, aParticleID, rSeriesParticle ); +} + +OUString ObjectIdentifier::addChildParticle( std::u16string_view rParticle, std::u16string_view rChildParticle ) +{ + OUStringBuffer aRet(rParticle); + + if( !aRet.isEmpty() && !rChildParticle.empty() ) + aRet.append(":"); + if( !rChildParticle.empty() ) + aRet.append(rChildParticle); + + return aRet.makeStringAndClear(); +} + +OUString ObjectIdentifier::createChildParticleWithIndex( ObjectType eObjectType, sal_Int32 nIndex ) +{ + OUStringBuffer aRet( getStringForType( eObjectType ) ); + if( !aRet.isEmpty() ) + { + aRet.append("="); + aRet.append(nIndex); + } + return aRet.makeStringAndClear(); +} + +sal_Int32 ObjectIdentifier::getIndexFromParticleOrCID( const OUString& rParticleOrCID ) +{ + const OUString aIndexString = lcl_getIndexStringAfterString( rParticleOrCID, "=" ); + return lcl_StringToIndex( o3tl::getToken(aIndexString, 0, ',' ) ); +} + +OUString ObjectIdentifier::createSeriesSubObjectStub( ObjectType eSubObjectType + , std::u16string_view rSeriesParticle + , std::u16string_view rDragMethodServiceName + , std::u16string_view rDragParameterString ) +{ + OUString aChildParticle = getStringForType( eSubObjectType ) + "="; + + return createClassifiedIdentifierForParticles( + rSeriesParticle, aChildParticle + , rDragMethodServiceName, rDragParameterString ); +} + +OUString ObjectIdentifier::createPointCID( std::u16string_view rPointCID_Stub, sal_Int32 nIndex ) +{ + return rPointCID_Stub + OUString::number( nIndex ); +} + +std::u16string_view ObjectIdentifier::getParticleID( std::u16string_view rCID ) +{ + std::u16string_view aRet; + size_t nLast = rCID.rfind('='); + if(nLast != std::u16string_view::npos) + aRet = rCID.substr(++nLast); + return aRet; +} + +std::u16string_view ObjectIdentifier::getFullParentParticle( std::u16string_view rCID ) +{ + std::u16string_view aRet; + + size_t nStartPos = rCID.rfind('/'); + if( nStartPos != std::u16string_view::npos ) + { + nStartPos++; + size_t nEndPos = rCID.rfind(':'); + if( nEndPos != std::u16string_view::npos && nStartPos < nEndPos ) + { + aRet = rCID.substr(nStartPos,nEndPos-nStartPos); + } + } + + return aRet; +} + +OUString ObjectIdentifier::getObjectID( const OUString& rCID ) +{ + OUString aRet; + + sal_Int32 nStartPos = rCID.lastIndexOf('/'); + if( nStartPos>=0 ) + { + nStartPos++; + sal_Int32 nEndPos = rCID.getLength(); + aRet = rCID.copy(nStartPos,nEndPos-nStartPos); + } + + return aRet; +} + +bool ObjectIdentifier::isCID( std::u16string_view rName ) +{ + return !rName.empty() && o3tl::starts_with( rName, m_aProtocol ); +} + +Reference< beans::XPropertySet > ObjectIdentifier::getObjectPropertySet( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + //return the model object that is indicated by rObjectCID + if(rObjectCID.isEmpty()) + return nullptr; + if(!xChartModel.is()) + return nullptr; + + Reference< beans::XPropertySet > xObjectProperties; + try + { + ObjectType eObjectType = ObjectIdentifier::getObjectType( rObjectCID ); + std::u16string_view aParticleID = ObjectIdentifier::getParticleID( rObjectCID ); + + rtl::Reference< Diagram > xDiagram; + rtl::Reference< BaseCoordinateSystem > xCooSys; + lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); + + switch(eObjectType) + { + case OBJECTTYPE_PAGE: + { + xObjectProperties.set( xChartModel->getPageBackground() ); + } + break; + case OBJECTTYPE_TITLE: + { + TitleHelper::eTitleType aTitleType = getTitleTypeForCID( rObjectCID ); + Reference< XTitle > xTitle( TitleHelper::getTitle( aTitleType, xChartModel ) ); + xObjectProperties.set( xTitle, uno::UNO_QUERY ); + } + break; + case OBJECTTYPE_LEGEND: + { + if( xDiagram.is() ) + xObjectProperties.set( xDiagram->getLegend(), uno::UNO_QUERY ); + } + break; + case OBJECTTYPE_LEGEND_ENTRY: + break; + case OBJECTTYPE_DIAGRAM: + { + xObjectProperties = xDiagram; + } + break; + case OBJECTTYPE_DIAGRAM_WALL: + { + if( xDiagram.is() ) + xObjectProperties.set( xDiagram->getWall() ); + } + break; + case OBJECTTYPE_DIAGRAM_FLOOR: + { + if( xDiagram.is() ) + xObjectProperties.set( xDiagram->getFloor() ); + } + break; + case OBJECTTYPE_AXIS: + { + sal_Int32 nDimensionIndex = -1; + sal_Int32 nAxisIndex = -1; + lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); + + rtl::Reference< Axis > xAxis = + AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ); + if( xAxis.is() ) + xObjectProperties = xAxis; + } + break; + case OBJECTTYPE_AXIS_UNITLABEL: + break; + case OBJECTTYPE_GRID: + case OBJECTTYPE_SUBGRID: + { + sal_Int32 nDimensionIndex = -1; + sal_Int32 nAxisIndex = -1; + lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); + + sal_Int32 nSubGridIndex = -1; + lcl_parseGridIndices( nSubGridIndex, rObjectCID ); + + xObjectProperties.set( AxisHelper::getGridProperties( xCooSys , nDimensionIndex, nAxisIndex, nSubGridIndex ) ); + } + break; + case OBJECTTYPE_DATA_LABELS: + case OBJECTTYPE_DATA_SERIES: + { + rtl::Reference< DataSeries > xSeries( ObjectIdentifier::getDataSeriesForCID( + rObjectCID, xChartModel ) ); + if( xSeries.is() ) + xObjectProperties = xSeries; + + break; + } + case OBJECTTYPE_DATA_LABEL: + case OBJECTTYPE_DATA_POINT: + { + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( + rObjectCID, xChartModel ); + if(xSeries.is()) + { + sal_Int32 nIndex = o3tl::toInt32(aParticleID); + xObjectProperties = xSeries->getDataPointByIndex( nIndex ); + } + break; + } + case OBJECTTYPE_DATA_ERRORS_X: + case OBJECTTYPE_DATA_ERRORS_Y: + case OBJECTTYPE_DATA_ERRORS_Z: + { + rtl::Reference< DataSeries > xSeries = ObjectIdentifier::getDataSeriesForCID( + rObjectCID, xChartModel ); + if(xSeries.is()) + { + Reference< beans::XPropertySet > xErrorBarProp; + OUString errorBar; + + if ( eObjectType == OBJECTTYPE_DATA_ERRORS_X) + errorBar = CHART_UNONAME_ERRORBAR_X; + else if (eObjectType == OBJECTTYPE_DATA_ERRORS_Y) + errorBar = CHART_UNONAME_ERRORBAR_Y; + else + errorBar = "ErrorBarZ"; + + xSeries->getPropertyValue( errorBar ) >>= xErrorBarProp; + xObjectProperties = xErrorBarProp; + } + break; + } + case OBJECTTYPE_DATA_AVERAGE_LINE: + case OBJECTTYPE_DATA_CURVE: + case OBJECTTYPE_DATA_CURVE_EQUATION: + { + rtl::Reference< DataSeries > xRegressionContainer = ObjectIdentifier::getDataSeriesForCID( + rObjectCID, xChartModel ); + if(xRegressionContainer.is()) + { + sal_Int32 nIndex = o3tl::toInt32(aParticleID); + const std::vector< rtl::Reference< RegressionCurveModel > > & aCurveList = + xRegressionContainer->getRegressionCurves2(); + if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < aCurveList.size() ) + { + if( eObjectType == OBJECTTYPE_DATA_CURVE_EQUATION ) + xObjectProperties = aCurveList[nIndex]->getEquationProperties(); + else + xObjectProperties = aCurveList[nIndex]; + } + } + break; + } + case OBJECTTYPE_DATA_STOCK_RANGE: + break; + case OBJECTTYPE_DATA_STOCK_LOSS: + { + rtl::Reference xChartType( lcl_getFirstStockChartType( xChartModel ) ); + if(xChartType.is()) + xChartType->getPropertyValue( "BlackDay" ) >>= xObjectProperties; + } + break; + case OBJECTTYPE_DATA_STOCK_GAIN: + { + rtl::Reference xChartType( lcl_getFirstStockChartType( xChartModel ) ); + if(xChartType.is()) + xChartType->getPropertyValue( "WhiteDay" ) >>= xObjectProperties; + } + break; + default: //OBJECTTYPE_UNKNOWN + break; + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return xObjectProperties; +} + +rtl::Reference< Axis > ObjectIdentifier::getAxisForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram; + rtl::Reference< BaseCoordinateSystem > xCooSys; + lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); + + sal_Int32 nDimensionIndex = -1; + sal_Int32 nAxisIndex = -1; + lcl_parseAxisIndices( nDimensionIndex, nAxisIndex, rObjectCID ); + + return AxisHelper::getAxis( nDimensionIndex, nAxisIndex, xCooSys ); +} + +rtl::Reference< DataSeries > ObjectIdentifier::getDataSeriesForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram; + rtl::Reference< BaseCoordinateSystem > xCooSys; + lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); + + sal_Int32 nChartTypeIndex = -1; + sal_Int32 nSeriesIndex = -1; + sal_Int32 nPointIndex = -1; + lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rObjectCID ); + + rtl::Reference< DataSeries > xSeries; + rtl::Reference< ChartType > xDataSeriesContainer( DiagramHelper::getChartTypeByIndex( xDiagram, nChartTypeIndex ) ); + if( xDataSeriesContainer.is() ) + { + const std::vector< rtl::Reference< DataSeries > > & aDataSeriesSeq( xDataSeriesContainer->getDataSeries2() ); + if( nSeriesIndex >= 0 && o3tl::make_unsigned(nSeriesIndex) < aDataSeriesSeq.size() ) + xSeries = aDataSeriesSeq[nSeriesIndex]; + } + + return xSeries; +} + +rtl::Reference< Diagram > ObjectIdentifier::getDiagramForCID( + const OUString& rObjectCID + , const rtl::Reference<::chart::ChartModel>& xChartModel ) +{ + rtl::Reference< Diagram > xDiagram; + rtl::Reference< BaseCoordinateSystem > xCooSys; + lcl_getDiagramAndCooSys( rObjectCID, xChartModel, xDiagram, xCooSys ); + + return xDiagram; +} + +TitleHelper::eTitleType ObjectIdentifier::getTitleTypeForCID( std::u16string_view rCID ) +{ + TitleHelper::eTitleType eRet( TitleHelper::MAIN_TITLE ); + + std::u16string_view aParentParticle = ObjectIdentifier::getFullParentParticle( rCID ); + const tTitleMap& rMap = lcl_getTitleMap(); + tTitleMap::const_iterator aIt = std::find_if(rMap.begin(), rMap.end(), + [&aParentParticle](tTitleMap::const_reference rEntry) { return aParentParticle == rEntry.second; }); + if (aIt != rMap.end()) + eRet = (*aIt).first; + + return eRet; +} + +OUString ObjectIdentifier::getSeriesParticleFromCID( const OUString& rCID ) +{ + sal_Int32 nDiagramIndex = -1; + sal_Int32 nCooSysIndex = -1; + lcl_parseCooSysIndices( nDiagramIndex, nCooSysIndex, rCID ); + + sal_Int32 nChartTypeIndex = -1; + sal_Int32 nSeriesIndex = -1; + sal_Int32 nPointIndex = -1; + lcl_parseSeriesIndices( nChartTypeIndex, nSeriesIndex, nPointIndex, rCID ); + + return ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex ); +} + +OUString ObjectIdentifier::getMovedSeriesCID( const OUString& rObjectCID, bool bForward ) +{ + sal_Int32 nDiagramIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CID/D=" ) ); + sal_Int32 nCooSysIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CS=" ) ); + sal_Int32 nChartTypeIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "CT=" ) ); + sal_Int32 nSeriesIndex = lcl_StringToIndex( lcl_getIndexStringAfterString( rObjectCID, "Series=" ) ); + + if( bForward ) + nSeriesIndex--; + else + nSeriesIndex++; + + OUString aRet = ObjectIdentifier::createParticleForSeries( nDiagramIndex, nCooSysIndex, nChartTypeIndex, nSeriesIndex ); + return ObjectIdentifier::createClassifiedIdentifierForParticle( aRet ); +} + +bool ObjectIdentifier::isValid() const +{ + return ( isAutoGeneratedObject() || isAdditionalShape() ); +} + +bool ObjectIdentifier::isAutoGeneratedObject() const +{ + return ( !m_aObjectCID.isEmpty() ); +} + +bool ObjectIdentifier::isAdditionalShape() const +{ + return m_xAdditionalShape.is(); +} + +Any ObjectIdentifier::getAny() const +{ + Any aAny; + if ( isAutoGeneratedObject() ) + { + aAny <<= getObjectCID(); + } + else if ( isAdditionalShape() ) + { + aAny <<= getAdditionalShape(); + } + return aAny; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx new file mode 100644 index 000000000..3d7f1c076 --- /dev/null +++ b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace com::sun::star; + +namespace chart +{ + +static double lcl_GetDotProduct(std::vector& aVec1, std::vector& aVec2) +{ + double fResult = 0.0; + assert(aVec1.size() == aVec2.size()); + for (size_t i = 0; i < aVec1.size(); ++i) + fResult += aVec1[i] * aVec2[i]; + return fResult; +} + +PolynomialRegressionCurveCalculator::PolynomialRegressionCurveCalculator() +{} + +PolynomialRegressionCurveCalculator::~PolynomialRegressionCurveCalculator() +{} + +void PolynomialRegressionCurveCalculator::computeCorrelationCoefficient( + RegressionCalculationHelper::tDoubleVectorPair& rValues, + const sal_Int32 aNoValues, + double yAverage ) +{ + double aSumError = 0.0; + double aSumTotal = 0.0; + double aSumYpred2 = 0.0; + + for( sal_Int32 i = 0; i < aNoValues; i++ ) + { + double xValue = rValues.first[i]; + double yActual = rValues.second[i]; + double yPredicted = getCurveValue( xValue ); + aSumTotal += (yActual - yAverage) * (yActual - yAverage); + aSumError += (yActual - yPredicted) * (yActual - yPredicted); + if(mForceIntercept) + aSumYpred2 += (yPredicted - mInterceptValue) * (yPredicted - mInterceptValue); + } + + double aRSquared = 0.0; + if(mForceIntercept) + { + if (auto const div = aSumError + aSumYpred2) + { + aRSquared = aSumYpred2 / div; + } + } + else if (aSumTotal != 0.0) + { + aRSquared = 1.0 - (aSumError / aSumTotal); + } + + if (aRSquared > 0.0) + m_fCorrelationCoefficient = std::sqrt(aRSquared); + else + m_fCorrelationCoefficient = 0.0; +} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL PolynomialRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) +{ + m_fCorrelationCoefficient = std::numeric_limits::quiet_NaN(); + + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( aXValues, aYValues, RegressionCalculationHelper::isValid())); + + const sal_Int32 aNoValues = aValues.first.size(); + + const sal_Int32 aNoPowers = mForceIntercept ? mDegree : mDegree + 1; + + mCoefficients.clear(); + mCoefficients.resize(aNoPowers, 0.0); + + double yAverage = 0.0; + + std::vector yVector; + yVector.resize(aNoValues, 0.0); + + for(sal_Int32 i = 0; i < aNoValues; i++) + { + double yValue = aValues.second[i]; + if (mForceIntercept) + yValue -= mInterceptValue; + yVector[i] = yValue; + yAverage += yValue; + } + if (aNoValues != 0) + { + yAverage /= aNoValues; + } + + // Special case for single variable regression like in LINEST + // implementation in Calc. + if (mDegree == 1) + { + std::vector xVector; + xVector.resize(aNoValues, 0.0); + double xAverage = 0.0; + + for(sal_Int32 i = 0; i < aNoValues; ++i) + { + double xValue = aValues.first[i]; + xVector[i] = xValue; + xAverage += xValue; + } + if (aNoValues != 0) + { + xAverage /= aNoValues; + } + + if (!mForceIntercept) + { + for (sal_Int32 i = 0; i < aNoValues; ++i) + { + xVector[i] -= xAverage; + yVector[i] -= yAverage; + } + } + double fSumXY = lcl_GetDotProduct(xVector, yVector); + double fSumX2 = lcl_GetDotProduct(xVector, xVector); + + double fSlope = fSumXY / fSumX2; + + if (!mForceIntercept) + { + mInterceptValue = ::rtl::math::approxSub(yAverage, fSlope * xAverage); + mCoefficients[0] = mInterceptValue; + mCoefficients[1] = fSlope; + } + else + { + mCoefficients[0] = fSlope; + mCoefficients.insert(mCoefficients.begin(), mInterceptValue); + } + + computeCorrelationCoefficient(aValues, aNoValues, yAverage); + return; + } + + std::vector aQRTransposed; + aQRTransposed.resize(aNoValues * aNoPowers, 0.0); + + for(sal_Int32 j = 0; j < aNoPowers; j++) + { + sal_Int32 aPower = mForceIntercept ? j+1 : j; + sal_Int32 aColumnIndex = j * aNoValues; + for(sal_Int32 i = 0; i < aNoValues; i++) + { + double xValue = aValues.first[i]; + aQRTransposed[i + aColumnIndex] = std::pow(xValue, static_cast(aPower)); + } + } + + // QR decomposition - based on org.apache.commons.math.linear.QRDecomposition from apache commons math (ASF) + sal_Int32 aMinorSize = std::min(aNoValues, aNoPowers); + + std::vector aDiagonal; + aDiagonal.resize(aMinorSize, 0.0); + + // Calculate Householder reflectors + for (sal_Int32 aMinor = 0; aMinor < aMinorSize; aMinor++) + { + double aNormSqr = 0.0; + for (sal_Int32 x = aMinor; x < aNoValues; x++) + { + double c = aQRTransposed[x + aMinor * aNoValues]; + aNormSqr += c * c; + } + + double a; + + if (aQRTransposed[aMinor + aMinor * aNoValues] > 0.0) + a = -std::sqrt(aNormSqr); + else + a = std::sqrt(aNormSqr); + + aDiagonal[aMinor] = a; + + if (a != 0.0) + { + aQRTransposed[aMinor + aMinor * aNoValues] -= a; + + for (sal_Int32 aColumn = aMinor + 1; aColumn < aNoPowers; aColumn++) + { + double alpha = 0.0; + for (sal_Int32 aRow = aMinor; aRow < aNoValues; aRow++) + { + alpha -= aQRTransposed[aRow + aColumn * aNoValues] * aQRTransposed[aRow + aMinor * aNoValues]; + } + alpha /= a * aQRTransposed[aMinor + aMinor * aNoValues]; + + for (sal_Int32 aRow = aMinor; aRow < aNoValues; aRow++) + { + aQRTransposed[aRow + aColumn * aNoValues] -= alpha * aQRTransposed[aRow + aMinor * aNoValues]; + } + } + } + } + + // Solve the linear equation + for (sal_Int32 aMinor = 0; aMinor < aMinorSize; aMinor++) + { + double aDotProduct = 0; + + for (sal_Int32 aRow = aMinor; aRow < aNoValues; aRow++) + { + aDotProduct += yVector[aRow] * aQRTransposed[aRow + aMinor * aNoValues]; + } + aDotProduct /= aDiagonal[aMinor] * aQRTransposed[aMinor + aMinor * aNoValues]; + + for (sal_Int32 aRow = aMinor; aRow < aNoValues; aRow++) + { + yVector[aRow] += aDotProduct * aQRTransposed[aRow + aMinor * aNoValues]; + } + + } + + for (sal_Int32 aRow = aDiagonal.size() - 1; aRow >= 0; aRow--) + { + yVector[aRow] /= aDiagonal[aRow]; + double yRow = yVector[aRow]; + mCoefficients[aRow] = yRow; + + for (sal_Int32 i = 0; i < aRow; i++) + { + yVector[i] -= yRow * aQRTransposed[i + aRow * aNoValues]; + } + } + + if(mForceIntercept) + { + mCoefficients.insert(mCoefficients.begin(), mInterceptValue); + } + + // Calculate correlation coefficient + computeCorrelationCoefficient(aValues, aNoValues, yAverage); +} + +double SAL_CALL PolynomialRegressionCurveCalculator::getCurveValue( double x ) +{ + if (mCoefficients.empty()) + return std::numeric_limits::quiet_NaN(); + + sal_Int32 aNoCoefficients = static_cast(mCoefficients.size()); + + // Horner's method + double fResult = 0.0; + for (sal_Int32 i = aNoCoefficients - 1; i >= 0; i--) + { + fResult = mCoefficients[i] + (x * fResult); + } + return fResult; +} + +OUString PolynomialRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth /* = nullptr */ ) const +{ + OUStringBuffer aBuf( mYName + " = " ); + + sal_Int32 nValueLength=0; + sal_Int32 aLastIndex = mCoefficients.size() - 1; + + if ( pFormulaMaxWidth && *pFormulaMaxWidth > 0 ) + { + sal_Int32 nCharMin = aBuf.getLength(); // count characters different from coefficients + double nCoefficients = aLastIndex + 1.0; // number of coefficients + for (sal_Int32 i = aLastIndex; i >= 0; i--) + { + double aValue = mCoefficients[i]; + if ( aValue == 0.0 ) + { // do not count coefficient if it is 0 + nCoefficients --; + continue; + } + if ( rtl::math::approxEqual( fabs( aValue ) , 1.0 ) ) + { // do not count coefficient if it is 1 + nCoefficients --; + if ( i == 0 ) // intercept = 1 + nCharMin ++; + } + if ( i != aLastIndex ) + nCharMin += 3; // " + " + if ( i > 0 ) + { + nCharMin += mXName.getLength() + 1; // " x" + if ( i > 1 ) + nCharMin +=1; // "^i" + if ( i >= 10 ) + nCharMin ++; // 2 digits for i + } + } + nValueLength = ( *pFormulaMaxWidth - nCharMin ) / nCoefficients; + if ( nValueLength <= 0 ) + nValueLength = 1; + } + + bool bFindValue = false; + sal_Int32 nLineLength = aBuf.getLength(); + for (sal_Int32 i = aLastIndex; i >= 0; i--) + { + double aValue = mCoefficients[i]; + OUStringBuffer aTmpBuf(""); // temporary buffer + if (aValue == 0.0) + { + continue; + } + else if (aValue < 0.0) + { + if ( bFindValue ) // if it is not the first aValue + aTmpBuf.append( " " ); + aTmpBuf.append( OUStringChar(aMinusSign) + " "); + aValue = - aValue; + } + else + { + if ( bFindValue ) // if it is not the first aValue + aTmpBuf.append( " + " ); + } + bFindValue = true; + + // if nValueLength not calculated then nullptr + sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr; + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, aValue, pValueLength ); + if ( i == 0 || aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small + { + aTmpBuf.append( aValueString ); + if ( i > 0 ) // insert blank between coefficient and x + aTmpBuf.append( " " ); + } + + if(i > 0) + { + aTmpBuf.append( mXName ); + if (i > 1) + { + if (i < 10) // simple case if only one digit + aTmpBuf.append( aSuperscriptFigures[ i ] ); + else + { + OUString aValueOfi = OUString::number( i ); + for ( sal_Int32 n = 0; n < aValueOfi.getLength() ; n++ ) + { + sal_Int32 nIndex = aValueOfi[n] - u'0'; + aTmpBuf.append( aSuperscriptFigures[ nIndex ] ); + } + } + } + } + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + } + if ( std::u16string_view(aBuf) == OUStringConcatenation( mYName + " = ") ) + aBuf.append( "0" ); + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/PopupRequest.cxx b/chart2/source/tools/PopupRequest.cxx new file mode 100644 index 000000000..70dd65b78 --- /dev/null +++ b/chart2/source/tools/PopupRequest.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +using namespace css; + +namespace chart +{ +PopupRequest::PopupRequest() {} + +PopupRequest::~PopupRequest() {} + +// ____ XRequestCallback ____ + +void SAL_CALL PopupRequest::addCallback(const uno::Reference& xCallback, + const uno::Any& /*aData*/) +{ + m_xCallback = xCallback; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/PotentialRegressionCurveCalculator.cxx b/chart2/source/tools/PotentialRegressionCurveCalculator.cxx new file mode 100644 index 000000000..01aa5b254 --- /dev/null +++ b/chart2/source/tools/PotentialRegressionCurveCalculator.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +PotentialRegressionCurveCalculator::PotentialRegressionCurveCalculator() + : m_fSlope(std::numeric_limits::quiet_NaN()) + , m_fIntercept(std::numeric_limits::quiet_NaN()) + , m_fSign(1.0) +{ +} + +PotentialRegressionCurveCalculator::~PotentialRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL PotentialRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) +{ + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValidAndBothPositive())); + m_fSign = 1.0; + + size_t nMax = aValues.first.size(); + if( nMax <= 1 ) // at least 2 points + { + aValues = RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValidAndXPositiveAndYNegative()); + nMax = aValues.first.size(); + if( nMax <= 1 ) + { + m_fSlope = std::numeric_limits::quiet_NaN(); + m_fIntercept = std::numeric_limits::quiet_NaN(); + m_fCorrelationCoefficient = std::numeric_limits::quiet_NaN(); + return; + } + m_fSign = -1.0; + } + + double fAverageX = 0.0, fAverageY = 0.0; + size_t i = 0; + for( i = 0; i < nMax; ++i ) + { + fAverageX += log( aValues.first[i] ); + fAverageY += log( m_fSign * aValues.second[i] ); + } + + const double fN = static_cast< double >( nMax ); + fAverageX /= fN; + fAverageY /= fN; + + double fQx = 0.0, fQy = 0.0, fQxy = 0.0; + for( i = 0; i < nMax; ++i ) + { + double fDeltaX = log( aValues.first[i] ) - fAverageX; + double fDeltaY = log( m_fSign * aValues.second[i] ) - fAverageY; + + fQx += fDeltaX * fDeltaX; + fQy += fDeltaY * fDeltaY; + fQxy += fDeltaX * fDeltaY; + } + + m_fSlope = fQxy / fQx; + m_fIntercept = fAverageY - m_fSlope * fAverageX; + m_fCorrelationCoefficient = fQxy / sqrt( fQx * fQy ); + + m_fIntercept = m_fSign * exp( m_fIntercept ); +} + +double SAL_CALL PotentialRegressionCurveCalculator::getCurveValue( double x ) +{ + if( ! ( std::isnan( m_fSlope ) || + std::isnan( m_fIntercept ))) + { + return m_fIntercept * pow( x, m_fSlope ); + } + + return std::numeric_limits::quiet_NaN(); +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL PotentialRegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) +{ + if( bMaySkipPointsInCalculation && + isLogarithmicScaling( xScalingX ) && + isLogarithmicScaling( xScalingY )) + { + // optimize result + uno::Sequence< geometry::RealPoint2D > aResult{ { min, getCurveValue( min ) }, + { max, getCurveValue( max ) } }; + + return aResult; + } + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +OUString PotentialRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth /* = nullptr */ ) const +{ + bool bHasIntercept = !rtl::math::approxEqual( fabs(m_fIntercept), 1.0 ); + OUStringBuffer aBuf( mYName + " = " ); + sal_Int32 nLineLength = aBuf.getLength(); + sal_Int32 nValueLength=0; + if ( pFormulaMaxWidth && *pFormulaMaxWidth > 0 ) // count nValueLength + { + sal_Int32 nCharMin = nLineLength + mXName.getLength() + 3; // 3 = "^" + 2 extra characters + if ( m_fIntercept != 0.0 && m_fSlope != 0.0 ) + { + if ( m_fIntercept < 0.0 ) + nCharMin += 2; // "- " + if ( bHasIntercept ) + nValueLength = (*pFormulaMaxWidth - nCharMin) / 2; + } + if ( nValueLength == 0 ) // not yet calculated + nValueLength = *pFormulaMaxWidth - nCharMin; + if ( nValueLength <= 0 ) + nValueLength = 1; + } + + if( m_fIntercept == 0.0 ) + { + aBuf.append( '0' ); + } + else + { + // temporary buffer + OUStringBuffer aTmpBuf(""); + // if nValueLength not calculated then nullptr + sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr; + if ( m_fIntercept < 0.0 ) // add intercept value + aTmpBuf.append( OUStringChar(aMinusSign) + " " ); + if( bHasIntercept ) + { + OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fIntercept), pValueLength ); + if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small + { + aTmpBuf.append( aValueString + " " ); + } + } + if( m_fSlope != 0.0 ) // add slope value + { + aTmpBuf.append( mXName + "^" ); + aTmpBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fSlope, pValueLength )); + } + addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth ); + } + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/PropertyHelper.cxx b/chart2/source/tools/PropertyHelper.cxx new file mode 100644 index 000000000..9f34ba1c2 --- /dev/null +++ b/chart2/source/tools/PropertyHelper.cxx @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace +{ +struct lcl_EqualsElement +{ + explicit lcl_EqualsElement( const Any & rValue, const Reference< container::XNameAccess > & xAccess ) + : m_aValue( rValue ), m_xAccess( xAccess ) + { + OSL_ASSERT( m_xAccess.is()); + } + + bool operator() ( const OUString & rName ) + { + try + { + return (m_xAccess->getByName( rName ) == m_aValue); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return false; + } + +private: + Any m_aValue; + Reference< container::XNameAccess > m_xAccess; +}; + +struct lcl_StringMatches +{ + explicit lcl_StringMatches( const OUString & rCmpStr ) : + m_aCmpStr( rCmpStr ) + {} + + bool operator() ( std::u16string_view rStr ) + { + return o3tl::starts_with( rStr, m_aCmpStr ); + } + +private: + OUString m_aCmpStr; +}; + +struct lcl_OUStringRestToInt32 +{ + explicit lcl_OUStringRestToInt32( sal_Int32 nPrefixLength ) : + m_nPrefixLength( nPrefixLength ) + {} + sal_Int32 operator() ( const OUString & rStr ) + { + if( m_nPrefixLength > rStr.getLength() ) + return 0; + return o3tl::toInt32(rStr.subView( m_nPrefixLength )); + } +private: + sal_Int32 m_nPrefixLength; +}; + +/** adds a fill gradient, fill hatch, fill bitmap, fill transparency gradient, + line dash or line marker to the corresponding name container with a unique + name. + + @param rPrefix + The prefix used for automated name generation. + + @param rPreferredName + If this string is not empty it is used as name if it is unique in the + table. Otherwise a new name is generated using pPrefix. + + @return the new name under which the property was stored in the table +*/ +OUString lcl_addNamedPropertyUniqueNameToTable( + const Any & rValue, + const Reference< container::XNameContainer > & xNameContainer, + const OUString & rPrefix, + const OUString & rPreferredName ) +{ + if( ! xNameContainer.is() || + ! rValue.hasValue() || + ( rValue.getValueType() != xNameContainer->getElementType())) + return rPreferredName; + + try + { + Reference< container::XNameAccess > xNameAccess( xNameContainer, uno::UNO_QUERY_THROW ); + const uno::Sequence aElementNames = xNameAccess->getElementNames(); + auto it = std::find_if( aElementNames.begin(), aElementNames.end(), lcl_EqualsElement( rValue, xNameAccess )); + + // element found => return name + if( it != aElementNames.end()) + return *it; + + // element not found in container + OUString aUniqueName; + + // check if preferred name is already used + if( !rPreferredName.isEmpty()) + { + auto aIt = std::find( aElementNames.begin(), aElementNames.end(), rPreferredName ); + if( aIt == aElementNames.end()) + aUniqueName = rPreferredName; + } + + if( aUniqueName.isEmpty()) + { + auto aNames( comphelper::sequenceToContainer>( aElementNames )); + // create a unique id using the prefix plus a number + std::vector< sal_Int32 > aNumbers; + std::vector< OUString >::iterator aNonConstIt( + std::partition( aNames.begin(), aNames.end(), lcl_StringMatches( rPrefix ))); + std::transform( aNames.begin(), aNonConstIt, + back_inserter( aNumbers ), + lcl_OUStringRestToInt32( rPrefix.getLength() )); + std::vector< sal_Int32 >::const_iterator aMaxIt( + std::max_element( aNumbers.begin(), aNumbers.end())); + + sal_Int32 nIndex = 1; + if( aMaxIt != aNumbers.end()) + nIndex = (*aMaxIt) + 1; + + aUniqueName = rPrefix + OUString::number( nIndex ); + } + + OSL_ASSERT( !aUniqueName.isEmpty()); + xNameContainer->insertByName( aUniqueName, rValue ); + return aUniqueName; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return rPreferredName; +} + +} // anonymous namespace + +namespace chart::PropertyHelper +{ + +OUString addLineDashUniqueNameToTable( + const Any & rValue, + const Reference< lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ) +{ + if( xFact.is()) + { + Reference< container::XNameContainer > xNameCnt( + xFact->createInstance( "com.sun.star.drawing.DashTable"), + uno::UNO_QUERY ); + if( xNameCnt.is()) + return lcl_addNamedPropertyUniqueNameToTable( + rValue, xNameCnt, "ChartDash ", rPreferredName ); + } + return OUString(); +} + +OUString addGradientUniqueNameToTable( + const Any & rValue, + const Reference< lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ) +{ + if( xFact.is()) + { + Reference< container::XNameContainer > xNameCnt( + xFact->createInstance( "com.sun.star.drawing.GradientTable"), + uno::UNO_QUERY ); + if( xNameCnt.is()) + return lcl_addNamedPropertyUniqueNameToTable( + rValue, xNameCnt, "ChartGradient ", rPreferredName ); + } + return OUString(); +} + +OUString addTransparencyGradientUniqueNameToTable( + const Any & rValue, + const Reference< lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ) +{ + if( xFact.is()) + { + Reference< container::XNameContainer > xNameCnt( + xFact->createInstance( "com.sun.star.drawing.TransparencyGradientTable"), + uno::UNO_QUERY ); + if( xNameCnt.is()) + return lcl_addNamedPropertyUniqueNameToTable( + rValue, xNameCnt, "ChartTransparencyGradient ", rPreferredName ); + } + return OUString(); +} + +OUString addHatchUniqueNameToTable( + const Any & rValue, + const Reference< lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ) +{ + if( xFact.is()) + { + Reference< container::XNameContainer > xNameCnt( + xFact->createInstance( "com.sun.star.drawing.HatchTable"), + uno::UNO_QUERY ); + if( xNameCnt.is()) + return lcl_addNamedPropertyUniqueNameToTable( + rValue, xNameCnt, "ChartHatch ", rPreferredName ); + } + return OUString(); +} + +OUString addBitmapUniqueNameToTable( + const Any & rValue, + const Reference< lang::XMultiServiceFactory > & xFact, + const OUString & rPreferredName ) +{ + if( xFact.is()) + { + Reference< container::XNameContainer > xNameCnt( + xFact->createInstance( "com.sun.star.drawing.BitmapTable"), + uno::UNO_QUERY ); + if( xNameCnt.is()) + return lcl_addNamedPropertyUniqueNameToTable( + rValue, xNameCnt, "ChartBitmap ", rPreferredName ); + } + return OUString(); +} + +void setPropertyValueAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const uno::Any & rAny ) +{ + tPropertyValueMap::iterator aIt( rOutMap.find( key )); + if( aIt == rOutMap.end()) + rOutMap.emplace( key, rAny ); + else + (*aIt).second = rAny; +} + +template<> + void setPropertyValue< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny ) +{ + setPropertyValueAny( rOutMap, key, rAny ); +} + +void setPropertyValueDefaultAny( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const uno::Any & rAny ) +{ + OSL_ENSURE( rOutMap.end() == rOutMap.find( key ), "Default already exists for property" ); + setPropertyValue( rOutMap, key, rAny ); +} + +template<> + void setPropertyValueDefault< css::uno::Any >( tPropertyValueMap & rOutMap, tPropertyValueMapKey key, const css::uno::Any & rAny ) +{ + setPropertyValueDefaultAny( rOutMap, key, rAny ); +} + +void setEmptyPropertyValueDefault( tPropertyValueMap & rOutMap, tPropertyValueMapKey key ) +{ + setPropertyValueDefault( rOutMap, key, uno::Any()); +} + +} // namespace chart::PropertyHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RangeHighlighter.cxx b/chart2/source/tools/RangeHighlighter.cxx new file mode 100644 index 000000000..d59400050 --- /dev/null +++ b/chart2/source/tools/RangeHighlighter.cxx @@ -0,0 +1,394 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +const Color defaultPreferredColor = COL_LIGHTBLUE; + +void lcl_fillRanges( + Sequence< chart2::data::HighlightedRange > & rOutRanges, + const Sequence< OUString >& aRangeStrings, + Color nPreferredColor, + sal_Int32 nIndex = -1 ) +{ + rOutRanges.realloc( aRangeStrings.getLength()); + auto pOutRanges = rOutRanges.getArray(); + for( sal_Int32 i=0; i & xChartModel ) : + m_xSelectionSupplier(xChartModel->getCurrentController(), uno::UNO_QUERY), + m_xChartModel( xChartModel ), + m_nAddedListenerCount( 0 ), + m_bIncludeHiddenCells(true) +{ +} + +RangeHighlighter::~RangeHighlighter() +{} + +// ____ XRangeHighlighter ____ +Sequence< chart2::data::HighlightedRange > SAL_CALL RangeHighlighter::getSelectedRanges() +{ + return m_aSelectedRanges; +} + +void RangeHighlighter::determineRanges() +{ + m_aSelectedRanges.realloc( 0 ); + if( !m_xChartModel.is()) + return; + if( !m_xSelectionSupplier.is()) + return; + + try + { + m_bIncludeHiddenCells = ChartModelHelper::isIncludeHiddenCells( m_xChartModel ); + + uno::Any aSelection( m_xSelectionSupplier->getSelection()); + const uno::Type& rType = aSelection.getValueType(); + + if ( rType == cppu::UnoType::get() ) + { + // @todo??: maybe getSelection() should return a model object rather than a CID + + OUString aCID; + aSelection >>= aCID; + if ( !aCID.isEmpty() ) + { + ObjectType eObjectType = ObjectIdentifier::getObjectType( aCID ); + sal_Int32 nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aCID ); + rtl::Reference< DataSeries > xDataSeries( ObjectIdentifier::getDataSeriesForCID( aCID, m_xChartModel ) ); + if( eObjectType == OBJECTTYPE_LEGEND_ENTRY ) + { + OUString aParentParticel( ObjectIdentifier::getFullParentParticle( aCID ) ); + ObjectType eParentObjectType = ObjectIdentifier::getObjectType( aParentParticel ); + eObjectType = eParentObjectType; + if( eObjectType == OBJECTTYPE_DATA_POINT ) + nIndex = ObjectIdentifier::getIndexFromParticleOrCID( aParentParticel ); + } + + if( eObjectType == OBJECTTYPE_DATA_POINT || eObjectType == OBJECTTYPE_DATA_LABEL ) + { + // Data Point + fillRangesForDataPoint( xDataSeries, nIndex ); + return; + } + else if( eObjectType == OBJECTTYPE_DATA_ERRORS_X || + eObjectType == OBJECTTYPE_DATA_ERRORS_Y || + eObjectType == OBJECTTYPE_DATA_ERRORS_Z ) + { + // select error bar ranges, or data series, if the style is + // not set to FROM_DATA + fillRangesForErrorBars( ObjectIdentifier::getObjectPropertySet( aCID, m_xChartModel ), xDataSeries ); + return; + } + else if( xDataSeries.is() ) + { + // Data Series + fillRangesForDataSeries( xDataSeries ); + return; + } + else if( eObjectType == OBJECTTYPE_AXIS ) + { + // Axis (Categories) + Reference< chart2::XAxis > xAxis( ObjectIdentifier::getObjectPropertySet( aCID, m_xChartModel ), uno::UNO_QUERY ); + if( xAxis.is()) + { + fillRangesForCategories( xAxis ); + return; + } + } + else if( eObjectType == OBJECTTYPE_PAGE + || eObjectType == OBJECTTYPE_DIAGRAM + || eObjectType == OBJECTTYPE_DIAGRAM_WALL + || eObjectType == OBJECTTYPE_DIAGRAM_FLOOR + ) + { + // Diagram + rtl::Reference< ::chart::Diagram > xDia( ObjectIdentifier::getDiagramForCID( aCID, m_xChartModel ) ); + if( xDia.is()) + { + fillRangesForDiagram( xDia ); + return; + } + } + } + } + else if ( rType == cppu::UnoType< drawing::XShape >::get() ) + { + // #i12587# support for shapes in chart + Reference< drawing::XShape > xShape; + aSelection >>= xShape; + if ( xShape.is() ) + { + return; + } + } + else + { + //if nothing is selected select all ranges + fillRangesForDiagram( m_xChartModel->getFirstChartDiagram() ); + return; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void RangeHighlighter::fillRangesForDiagram( const rtl::Reference< Diagram > & xDiagram ) +{ + Sequence< OUString > aSelectedRanges( DataSourceHelper::getUsedDataRanges( xDiagram )); + m_aSelectedRanges.realloc( aSelectedRanges.getLength()); + auto pSelectedRanges = m_aSelectedRanges.getArray(); + // @todo: merge ranges + for( sal_Int32 i=0; i & xSeries ) +{ + Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + lcl_fillRanges( m_aSelectedRanges, + ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), + defaultPreferredColor ); + } +} + +void RangeHighlighter::fillRangesForErrorBars( + const uno::Reference< beans::XPropertySet > & xErrorBar, + const uno::Reference< chart2::XDataSeries > & xSeries ) +{ + // only show error bar ranges, if the style is set to FROM_DATA + bool bUsesRangesAsErrorBars = false; + try + { + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + bUsesRangesAsErrorBars = + ( xErrorBar.is() && + (xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle) && + nStyle == css::chart::ErrorBarStyle::FROM_DATA ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( bUsesRangesAsErrorBars ) + { + Reference< chart2::data::XDataSource > xSource( xErrorBar, uno::UNO_QUERY ); + if( xSource.is()) + { + lcl_fillRanges( m_aSelectedRanges, + ::chart::DataSourceHelper::getRangesFromDataSource( xSource ), + defaultPreferredColor ); + } + } + else + { + fillRangesForDataSeries( xSeries ); + } +} + +void RangeHighlighter::fillRangesForCategories( const Reference< chart2::XAxis > & xAxis ) +{ + if( ! xAxis.is()) + return; + chart2::ScaleData aData( xAxis->getScaleData()); + lcl_fillRanges( m_aSelectedRanges, + DataSourceHelper::getRangesFromLabeledDataSequence( aData.Categories ), + defaultPreferredColor ); +} + +void RangeHighlighter::fillRangesForDataPoint( const rtl::Reference< DataSeries > & xDataSeries, sal_Int32 nIndex ) +{ + if( !xDataSeries.is()) + return; + + Color nPreferredColor = defaultPreferredColor; + std::vector< chart2::data::HighlightedRange > aHilightedRanges; + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aLSeqSeq( xDataSeries->getDataSequences2()); + for( uno::Reference< chart2::data::XLabeledDataSequence > const & labelDataSeq : aLSeqSeq ) + { + Reference< chart2::data::XDataSequence > xLabel( labelDataSeq->getLabel()); + Reference< chart2::data::XDataSequence > xValues( labelDataSeq->getValues()); + + if( xLabel.is()) + aHilightedRanges.emplace_back( + xLabel->getSourceRangeRepresentation(), + -1, + sal_Int32(nPreferredColor), + false ); + + sal_Int32 nUnhiddenIndex = DataSeriesHelper::translateIndexFromHiddenToFullSequence( nIndex, xValues, !m_bIncludeHiddenCells ); + if( xValues.is()) + aHilightedRanges.emplace_back( + xValues->getSourceRangeRepresentation(), + nUnhiddenIndex, + sal_Int32(nPreferredColor), + false ); + } + m_aSelectedRanges = comphelper::containerToSequence( aHilightedRanges ); +} + +void SAL_CALL RangeHighlighter::addSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) +{ + if(!xListener.is()) + return; + + if( m_nAddedListenerCount == 0 ) + startListening(); + std::unique_lock g(m_aMutex); + maSelectionChangeListeners.addInterface( g, xListener); + ++m_nAddedListenerCount; + + //bring the new listener up to the current state + lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); + xListener->selectionChanged( aEvent ); +} + +void SAL_CALL RangeHighlighter::removeSelectionChangeListener( const Reference< view::XSelectionChangeListener >& xListener ) +{ + std::unique_lock g(m_aMutex); + maSelectionChangeListeners.removeInterface( g, xListener ); + --m_nAddedListenerCount; + if( m_nAddedListenerCount == 0 ) + stopListening(); +} + +// ____ XSelectionChangeListener ____ +void SAL_CALL RangeHighlighter::selectionChanged( const lang::EventObject& /*aEvent*/ ) +{ + determineRanges(); + + // determine ranges of selected view objects + // if changed, fire an event + fireSelectionEvent(); +} + +void RangeHighlighter::fireSelectionEvent() +{ + std::unique_lock g(m_aMutex); + if( maSelectionChangeListeners.getLength(g) ) + { + lang::EventObject aEvent( static_cast< lang::XComponent* >( this ) ); + maSelectionChangeListeners.forEach(g, + [&aEvent](const css::uno::Reference& xListener) + { + xListener->selectionChanged(aEvent); + } + ); + } +} + +void SAL_CALL RangeHighlighter::disposing( const lang::EventObject& Source ) +{ + if( Source.Source == m_xSelectionSupplier ) + { + m_xSelectionSupplier.clear(); + m_aSelectedRanges.realloc( 0 ); + fireSelectionEvent(); + } +} + +void RangeHighlighter::startListening() +{ + if( m_xSelectionSupplier.is()) + { + if( ! m_xListener.is()) + { + m_xListener.set( new WeakSelectionChangeListenerAdapter( this )); + determineRanges(); + } + m_xSelectionSupplier->addSelectionChangeListener( m_xListener ); + } +} + +void RangeHighlighter::stopListening() +{ + if( m_xSelectionSupplier.is() && m_xListener.is()) + { + m_xSelectionSupplier->removeSelectionChangeListener( m_xListener ); + m_xListener.clear(); + } +} + +// ____ WeakComponentImplHelperBase ____ +// is called when dispose() is called at this component +void RangeHighlighter::disposing(std::unique_lock&) +{ + // @todo: remove listener. Currently the controller shows an assertion + // because it is already disposed +// stopListening(); + m_xListener.clear(); + m_xSelectionSupplier.clear(); + m_nAddedListenerCount = 0; + m_aSelectedRanges.realloc( 0 ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ReferenceSizeProvider.cxx b/chart2/source/tools/ReferenceSizeProvider.cxx new file mode 100644 index 000000000..dd099edcf --- /dev/null +++ b/chart2/source/tools/ReferenceSizeProvider.cxx @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +ReferenceSizeProvider::ReferenceSizeProvider( + awt::Size aPageSize, + const rtl::Reference<::chart::ChartModel> & xChartDoc ) : + m_aPageSize( aPageSize ), + m_xChartDoc( xChartDoc ), + m_bUseAutoScale( getAutoResizeState( xChartDoc ) == AUTO_RESIZE_YES ) +{} + +void ReferenceSizeProvider::impl_setValuesAtTitled( + const Reference< XTitled > & xTitled ) +{ + if( xTitled.is()) + { + Reference< XTitle > xTitle( xTitled->getTitleObject()); + if( xTitle.is()) + setValuesAtTitle( xTitle ); + } +} + +void ReferenceSizeProvider::setValuesAtTitle( + const Reference< XTitle > & xTitle ) +{ + try + { + Reference< beans::XPropertySet > xTitleProp( xTitle, uno::UNO_QUERY_THROW ); + awt::Size aOldRefSize; + bool bHasOldRefSize( + xTitleProp->getPropertyValue( "ReferencePageSize") >>= aOldRefSize ); + + // set from auto-resize on to off -> adapt font sizes at XFormattedStrings + if( bHasOldRefSize && ! useAutoScale()) + { + const uno::Sequence< uno::Reference< XFormattedString > > aStrSeq( + xTitle->getText()); + for( uno::Reference< XFormattedString > const & formattedStr : aStrSeq ) + { + RelativeSizeHelper::adaptFontSizes( + Reference< beans::XPropertySet >( formattedStr, uno::UNO_QUERY ), + aOldRefSize, getPageSize()); + } + } + + setValuesAtPropertySet( xTitleProp, /* bAdaptFontSizes = */ false ); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ReferenceSizeProvider::setValuesAtAllDataSeries() +{ + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDoc )); + + // DataSeries/Points + std::vector< rtl::Reference< DataSeries > > aSeries = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& elem : aSeries) + { + // data points + Sequence< sal_Int32 > aPointIndexes; + try + { + if( elem->getPropertyValue( "AttributedDataPoints") >>= aPointIndexes ) + { + for( sal_Int32 idx : std::as_const(aPointIndexes) ) + setValuesAtPropertySet( + elem->getDataPointByIndex( idx ) ); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + //it is important to correct the datapoint properties first as they do reference the series properties + setValuesAtPropertySet( elem ); + } +} + +void ReferenceSizeProvider::setValuesAtPropertySet( + const Reference< beans::XPropertySet > & xProp, + bool bAdaptFontSizes /* = true */ ) +{ + if( ! xProp.is()) + return; + + static constexpr OUStringLiteral aRefSizeName = u"ReferencePageSize"; + + try + { + awt::Size aRefSize( getPageSize() ); + awt::Size aOldRefSize; + bool bHasOldRefSize( xProp->getPropertyValue( aRefSizeName ) >>= aOldRefSize ); + + if( useAutoScale()) + { + if( ! bHasOldRefSize ) + xProp->setPropertyValue( aRefSizeName, uno::Any( aRefSize )); + } + else + { + if( bHasOldRefSize ) + { + xProp->setPropertyValue( aRefSizeName, uno::Any()); + + // adapt font sizes + if( bAdaptFontSizes ) + RelativeSizeHelper::adaptFontSizes( xProp, aOldRefSize, aRefSize ); + } + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ReferenceSizeProvider::getAutoResizeFromPropSet( + const Reference< beans::XPropertySet > & xProp, + ReferenceSizeProvider::AutoResizeState & rInOutState ) +{ + AutoResizeState eSingleState = AUTO_RESIZE_UNKNOWN; + + if( xProp.is()) + { + try + { + if( xProp->getPropertyValue( "ReferencePageSize" ).hasValue()) + eSingleState = AUTO_RESIZE_YES; + else + eSingleState = AUTO_RESIZE_NO; + } + catch (const uno::Exception&) + { + // unknown property -> state stays unknown + } + } + + // current state unknown => nothing changes. Otherwise if current state + // differs from state so far, we have an ambiguity + if( rInOutState == AUTO_RESIZE_UNKNOWN ) + { + rInOutState = eSingleState; + } + else if( eSingleState != AUTO_RESIZE_UNKNOWN && + eSingleState != rInOutState ) + { + rInOutState = AUTO_RESIZE_AMBIGUOUS; + } +} + +void ReferenceSizeProvider::impl_getAutoResizeFromTitled( + const Reference< XTitled > & xTitled, + ReferenceSizeProvider::AutoResizeState & rInOutState ) +{ + if( xTitled.is()) + { + Reference< beans::XPropertySet > xProp( xTitled->getTitleObject(), uno::UNO_QUERY ); + if( xProp.is()) + getAutoResizeFromPropSet( xProp, rInOutState ); + } +} + +/** Retrieves the state auto-resize from all objects that support this + feature. If all objects return the same state, AUTO_RESIZE_YES or + AUTO_RESIZE_NO is returned. + + If no object supporting the feature is found, AUTO_RESIZE_UNKNOWN is + returned. If there are multiple objects, some with state YES and some + with state NO, AUTO_RESIZE_AMBIGUOUS is returned. +*/ +ReferenceSizeProvider::AutoResizeState ReferenceSizeProvider::getAutoResizeState( + const rtl::Reference<::chart::ChartModel> & xChartDoc ) +{ + AutoResizeState eResult = AUTO_RESIZE_UNKNOWN; + + // Main Title + if( xChartDoc.is()) + impl_getAutoResizeFromTitled( xChartDoc, eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + + // diagram is needed by the rest of the objects + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( xChartDoc ); + if( ! xDiagram.is()) + return eResult; + + // Sub Title + if( xDiagram.is()) + impl_getAutoResizeFromTitled( xDiagram, eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + + // Legend + Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendProp.is()) + getAutoResizeFromPropSet( xLegendProp, eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + + // Axes (incl. Axis Titles) + const std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aAxes ) + { + getAutoResizeFromPropSet( axis, eResult ); + impl_getAutoResizeFromTitled( axis, eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + } + + // DataSeries/Points + std::vector< rtl::Reference< DataSeries > > aSeries = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + + for (auto const& elem : aSeries) + { + getAutoResizeFromPropSet( elem, eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + + // data points + Sequence< sal_Int32 > aPointIndexes; + try + { + if( elem->getPropertyValue( "AttributedDataPoints") >>= aPointIndexes ) + { + for( sal_Int32 idx : std::as_const(aPointIndexes) ) + { + getAutoResizeFromPropSet( + elem->getDataPointByIndex( idx ), eResult ); + if( eResult == AUTO_RESIZE_AMBIGUOUS ) + return eResult; + } + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return eResult; +} + +void ReferenceSizeProvider::toggleAutoResizeState() +{ + setAutoResizeState( m_bUseAutoScale ? AUTO_RESIZE_NO : AUTO_RESIZE_YES ); +} + +/** sets the auto-resize at all objects that support this feature for text. + eNewState must be either AUTO_RESIZE_YES or AUTO_RESIZE_NO +*/ +void ReferenceSizeProvider::setAutoResizeState( ReferenceSizeProvider::AutoResizeState eNewState ) +{ + m_bUseAutoScale = (eNewState == AUTO_RESIZE_YES); + + // Main Title + impl_setValuesAtTitled( m_xChartDoc ); + + // diagram is needed by the rest of the objects + rtl::Reference< Diagram > xDiagram = ChartModelHelper::findDiagram( m_xChartDoc ); + if( ! xDiagram.is()) + return; + + // Sub Title + impl_setValuesAtTitled( xDiagram ); + + // Legend + Reference< beans::XPropertySet > xLegendProp( xDiagram->getLegend(), uno::UNO_QUERY ); + if( xLegendProp.is()) + setValuesAtPropertySet( xLegendProp ); + + // Axes (incl. Axis Titles) + const std::vector< rtl::Reference< Axis > > aAxes = AxisHelper::getAllAxesOfDiagram( xDiagram ); + for( rtl::Reference< Axis > const & axis : aAxes ) + { + setValuesAtPropertySet( axis ); + impl_setValuesAtTitled( axis ); + } + + // DataSeries/Points + setValuesAtAllDataSeries(); + + // recalculate new state (in case it stays unknown or is ambiguous + m_bUseAutoScale = (getAutoResizeState( m_xChartDoc ) == AUTO_RESIZE_YES); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionCurveCalculator.cxx b/chart2/source/tools/RegressionCurveCalculator.cxx new file mode 100644 index 000000000..fd2ca4329 --- /dev/null +++ b/chart2/source/tools/RegressionCurveCalculator.cxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +RegressionCurveCalculator::RegressionCurveCalculator() + : m_fCorrelationCoefficient(std::numeric_limits::quiet_NaN()) + , mDegree(2) + , mForceIntercept(false) + , mInterceptValue(std::numeric_limits::quiet_NaN()) + , mPeriod(2) + , mXName("x") + , mYName("f(x)") + , mnMovingType(0) +{ +} + +RegressionCurveCalculator::~RegressionCurveCalculator() +{} + +bool RegressionCurveCalculator::isLinearScaling( + const Reference< chart2::XScaling > & xScaling ) +{ + // no scaling means linear + if( !xScaling.is()) + return true; + uno::Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY ); + return xServiceName.is() && xServiceName->getServiceName() == "com.sun.star.chart2.LinearScaling"; +} + +bool RegressionCurveCalculator::isLogarithmicScaling( + const Reference< chart2::XScaling > & xScaling ) +{ + uno::Reference< lang::XServiceName > xServiceName( xScaling, uno::UNO_QUERY ); + return xServiceName.is() && xServiceName->getServiceName() == "com.sun.star.chart2.LogarithmicScaling"; +} + +void RegressionCurveCalculator::setRegressionProperties( + sal_Int32 aDegree, + sal_Bool aForceIntercept, + double aInterceptValue, + sal_Int32 aPeriod, + sal_Int32 nMovingType ) +{ + mDegree = aDegree; + mForceIntercept = aForceIntercept; + mInterceptValue = aInterceptValue; + mPeriod = aPeriod; + mnMovingType = nMovingType; +} + +OUString RegressionCurveCalculator::getFormattedString( + const Reference< util::XNumberFormatter >& xNumFormatter, + sal_Int32 nNumberFormatKey, + double fNumber, const sal_Int32* pStringLength /* = nullptr */ ) +{ + if ( pStringLength && *pStringLength <= 0 ) + return "###"; + OUString aResult; + + if( xNumFormatter.is() ) + { + bool bStandard = ::cppu::any2bool( ::comphelper::getNumberFormatProperty( xNumFormatter, nNumberFormatKey, "StandardFormat" ) ); + if( pStringLength && bStandard ) + { // round fNumber to *pStringLength characters + const sal_Int32 nMinDigit = 6; // minimum significant digits for General format + sal_Int32 nSignificantDigit = ( *pStringLength <= nMinDigit ? nMinDigit : *pStringLength ); + aResult = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_G1, nSignificantDigit, '.', true ); + // count characters different from significant digits (decimal separator, scientific notation) + sal_Int32 nExtraChar = aResult.getLength() - *pStringLength; + if ( nExtraChar > 0 && *pStringLength > nMinDigit ) + { + nSignificantDigit = *pStringLength - nExtraChar; + if ( nSignificantDigit < nMinDigit ) + nSignificantDigit = nMinDigit; + aResult = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_G1, nSignificantDigit, '.', true ); + } + fNumber = ::rtl::math::stringToDouble( aResult, '.', ',' ); + } + aResult = xNumFormatter->convertNumberToString( nNumberFormatKey, fNumber ); + } + else + { + sal_Int32 nStringLength = 4; // default length + if ( pStringLength ) + nStringLength = *pStringLength; + aResult = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_G1, nStringLength, '.', true ); + } + return aResult; +} + +Sequence< geometry::RealPoint2D > SAL_CALL RegressionCurveCalculator::getCurveValues( + double min, double max, ::sal_Int32 nPointCount, + const Reference< chart2::XScaling >& xScalingX, + const Reference< chart2::XScaling >& /* xScalingY */, + sal_Bool /* bMaySkipPointsInCalculation */ ) +{ + if( nPointCount < 2 ) + throw lang::IllegalArgumentException("too few points", static_cast(this), 2); + + // determine if scaling and inverse scaling for x-values work + bool bDoXScaling( xScalingX.is()); + uno::Reference< chart2::XScaling > xInverseScaling; + if( bDoXScaling ) + xInverseScaling.set( xScalingX->getInverseScaling()); + bDoXScaling = bDoXScaling && xInverseScaling.is(); + + Sequence< geometry::RealPoint2D > aResult( nPointCount ); + auto pResult = aResult.getArray(); + + double fMin( min ); + double fFact = (max - min) / double(nPointCount-1); + + if( bDoXScaling ) + { + fMin = xScalingX->doScaling( min ); + fFact = (xScalingX->doScaling( max ) - fMin) / double(nPointCount-1); + } + + for(sal_Int32 nP=0; nPdoScaling( x ); + pResult[nP].X = x; + pResult[nP].Y = getCurveValue( x ); + } + + return aResult; +} + +double SAL_CALL RegressionCurveCalculator::getCorrelationCoefficient() +{ + return m_fCorrelationCoefficient; +} + +OUString SAL_CALL RegressionCurveCalculator::getRepresentation() +{ + return ImplGetRepresentation( Reference< util::XNumberFormatter >(), 0 ); +} + +OUString SAL_CALL RegressionCurveCalculator::getFormattedRepresentation( + const Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier, + sal_Int32 nNumberFormatKey, sal_Int32 nFormulaLength ) +{ + // create and prepare a number formatter + if( !xNumFmtSupplier.is()) + return getRepresentation(); + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext(), uno::UNO_SET_THROW ); + Reference< util::XNumberFormatter > xNumFormatter( util::NumberFormatter::create(xContext), uno::UNO_QUERY_THROW ); + xNumFormatter->attachNumberFormatsSupplier( xNumFmtSupplier ); + + if ( nFormulaLength > 0 ) + return ImplGetRepresentation( xNumFormatter, nNumberFormatKey, &nFormulaLength ); + return ImplGetRepresentation( xNumFormatter, nNumberFormatKey ); +} + +void RegressionCurveCalculator::addStringToEquation( + OUStringBuffer& aStrEquation, sal_Int32& nLineLength, OUStringBuffer const & aAddString, const sal_Int32* pMaxWidth) +{ + if ( pMaxWidth && ( nLineLength + aAddString.getLength() > *pMaxWidth ) ) + { // wrap line + aStrEquation.append( "\n " ); // start new line with a blank + nLineLength = 1; + } + aStrEquation.append( aAddString ); + nLineLength += aAddString.getLength(); +} + +void SAL_CALL RegressionCurveCalculator::setXYNames( const OUString& aXName, const OUString& aYName ) +{ + if ( aXName.isEmpty() ) + mXName = OUString ("x"); + else + mXName = aXName; + if ( aYName.isEmpty() ) + mYName = OUString ("f(x)"); + else + mYName = aYName; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionCurveHelper.cxx b/chart2/source/tools/RegressionCurveHelper.cxx new file mode 100644 index 000000000..60ac5ebd3 --- /dev/null +++ b/chart2/source/tools/RegressionCurveHelper.cxx @@ -0,0 +1,920 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::lang::XServiceName; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Exception; + +namespace +{ +OUString lcl_getServiceNameForType(SvxChartRegress eType) +{ + OUString aServiceName; + switch( eType ) + { + case SvxChartRegress::Linear: + aServiceName = "com.sun.star.chart2.LinearRegressionCurve"; + break; + case SvxChartRegress::Log: + aServiceName = "com.sun.star.chart2.LogarithmicRegressionCurve"; + break; + case SvxChartRegress::Exp: + aServiceName = "com.sun.star.chart2.ExponentialRegressionCurve"; + break; + case SvxChartRegress::Power: + aServiceName = "com.sun.star.chart2.PotentialRegressionCurve"; + break; + case SvxChartRegress::Polynomial: + aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve"; + break; + case SvxChartRegress::MovingAverage: + aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve"; + break; + default: + OSL_FAIL("unknown regression curve type - use linear instead"); + aServiceName = "com.sun.star.chart2.LinearRegressionCurve"; + break; + } + return aServiceName; +} + +} // anonymous namespace + +namespace chart +{ + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::createMeanValueLine() +{ + return new MeanValueRegressionCurve; +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::createRegressionCurveByServiceName( + std::u16string_view aServiceName ) +{ + rtl::Reference< RegressionCurveModel > xResult; + + // todo: use factory methods with service name + if( aServiceName == u"com.sun.star.chart2.LinearRegressionCurve" ) + { + xResult.set( new LinearRegressionCurve ); + } + else if( aServiceName == u"com.sun.star.chart2.LogarithmicRegressionCurve" ) + { + xResult.set( new LogarithmicRegressionCurve ); + } + else if( aServiceName == u"com.sun.star.chart2.ExponentialRegressionCurve" ) + { + xResult.set( new ExponentialRegressionCurve ); + } + else if( aServiceName == u"com.sun.star.chart2.PotentialRegressionCurve" ) + { + xResult.set( new PotentialRegressionCurve ); + } + else if( aServiceName == u"com.sun.star.chart2.PolynomialRegressionCurve" ) + { + xResult.set( new PolynomialRegressionCurve ); + } + else if( aServiceName == u"com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + xResult.set( new MovingAverageRegressionCurve ); + } + + return xResult; +} + +Reference< XRegressionCurveCalculator > RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( + std::u16string_view aServiceName ) +{ + Reference< XRegressionCurveCalculator > xResult; + + // todo: use factory methods with service name + if( aServiceName == u"com.sun.star.chart2.MeanValueRegressionCurve" ) + { + xResult.set( new MeanValueRegressionCurveCalculator() ); + } + if( aServiceName == u"com.sun.star.chart2.LinearRegressionCurve" ) + { + xResult.set( new LinearRegressionCurveCalculator() ); + } + else if( aServiceName == u"com.sun.star.chart2.LogarithmicRegressionCurve" ) + { + xResult.set( new LogarithmicRegressionCurveCalculator() ); + } + else if( aServiceName == u"com.sun.star.chart2.ExponentialRegressionCurve" ) + { + xResult.set( new ExponentialRegressionCurveCalculator() ); + } + else if( aServiceName == u"com.sun.star.chart2.PotentialRegressionCurve" ) + { + xResult.set( new PotentialRegressionCurveCalculator() ); + } + else if( aServiceName == u"com.sun.star.chart2.PolynomialRegressionCurve" ) + { + xResult.set( new PolynomialRegressionCurveCalculator() ); + } + else if( aServiceName == u"com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + xResult.set( new MovingAverageRegressionCurveCalculator() ); + } + + return xResult; +} + +void RegressionCurveHelper::initializeCurveCalculator( + const Reference< XRegressionCurveCalculator > & xOutCurveCalculator, + const Reference< data::XDataSource > & xSource, + bool bUseXValuesIfAvailable /* = true */ ) +{ + if( ! (xOutCurveCalculator.is() && + xSource.is() )) + return; + + Sequence< double > aXValues, aYValues; + bool bXValuesFound = false, bYValuesFound = false; + + Sequence< Reference< data::XLabeledDataSequence > > aDataSeqs( xSource->getDataSequences()); + sal_Int32 i = 0; + for( i=0; + ! (bXValuesFound && bYValuesFound) && i xSeq( aDataSeqs[i]->getValues()); + Reference< XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW ); + OUString aRole; + if( xProp->getPropertyValue( "Role" ) >>= aRole ) + { + if( bUseXValuesIfAvailable && !bXValuesFound && aRole == "values-x" ) + { + aXValues = DataSequenceToDoubleSequence( xSeq ); + bXValuesFound = true; + } + else if( !bYValuesFound && aRole == "values-y" ) + { + aYValues = DataSequenceToDoubleSequence( xSeq ); + bYValuesFound = true; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + if( ! bXValuesFound && + bYValuesFound ) + { + // initialize with 1, 2, ... + //first category (index 0) matches with real number 1.0 + aXValues.realloc( aYValues.getLength()); + auto pXValues = aXValues.getArray(); + for( i=0; irecalculateRegression( aXValues, aYValues ); +} + +void RegressionCurveHelper::initializeCurveCalculator( + const Reference< XRegressionCurveCalculator > & xOutCurveCalculator, + const Reference< XDataSeries > & xSeries, + const rtl::Reference<::chart::ChartModel> & xModel ) +{ + sal_Int32 nAxisType = ChartTypeHelper::getAxisType( + ChartModelHelper::getChartTypeOfSeries( xModel, xSeries ), 0 ); // x-axis + + initializeCurveCalculator( xOutCurveCalculator, + uno::Reference< data::XDataSource >( xSeries, uno::UNO_QUERY ), + (nAxisType == AxisType::REALNUMBER) ); +} + +bool RegressionCurveHelper::hasMeanValueLine( + const uno::Reference< XRegressionCurveContainer > & xRegCnt ) +{ + if( !xRegCnt.is()) + return false; + + try + { + const uno::Sequence< uno::Reference< XRegressionCurve > > aCurves( + xRegCnt->getRegressionCurves()); + for( uno::Reference< XRegressionCurve > const & curve : aCurves ) + { + if( isMeanValueLine( curve )) + return true; + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return false; +} + +bool RegressionCurveHelper::hasMeanValueLine( + const rtl::Reference< DataSeries > & xRegCnt ) +{ + if( !xRegCnt.is()) + return false; + + try + { + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( isMeanValueLine( curve )) + return true; + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return false; +} + +bool RegressionCurveHelper::isMeanValueLine( + const uno::Reference< chart2::XRegressionCurve > & xRegCurve ) +{ + uno::Reference< XServiceName > xServName( xRegCurve, uno::UNO_QUERY ); + return xServName.is() && + xServName->getServiceName() == + "com.sun.star.chart2.MeanValueRegressionCurve"; +} + +bool RegressionCurveHelper::isMeanValueLine( + const rtl::Reference< RegressionCurveModel > & xRegCurve ) +{ + return xRegCurve.is() && + xRegCurve->getServiceName() == + "com.sun.star.chart2.MeanValueRegressionCurve"; +} + +rtl::Reference< RegressionCurveModel > + RegressionCurveHelper::getMeanValueLine( + const uno::Reference< chart2::XRegressionCurveContainer > & xRegCnt ) +{ + if( xRegCnt.is()) + { + try + { + const uno::Sequence< uno::Reference< XRegressionCurve > > aCurves( + xRegCnt->getRegressionCurves()); + for( uno::Reference< XRegressionCurve > const & curve : aCurves ) + { + if( isMeanValueLine( curve )) + return dynamic_cast(curve.get()); + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nullptr; +} + +rtl::Reference< RegressionCurveModel > + RegressionCurveHelper::getMeanValueLine( + const rtl::Reference< DataSeries > & xRegCnt ) +{ + if( xRegCnt.is()) + { + try + { + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( isMeanValueLine( curve )) + return curve; + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return nullptr; +} + +void RegressionCurveHelper::addMeanValueLine( + uno::Reference< XRegressionCurveContainer > const & xRegCnt, + const uno::Reference< XPropertySet > & xSeriesProp ) +{ + if( !xRegCnt.is() || + ::chart::RegressionCurveHelper::hasMeanValueLine( xRegCnt ) ) + return; + + // todo: use a valid context + uno::Reference< XRegressionCurve > xCurve( createMeanValueLine() ); + xRegCnt->addRegressionCurve( xCurve ); + + if( xSeriesProp.is()) + { + uno::Reference< XPropertySet > xProp( xCurve, uno::UNO_QUERY ); + if( xProp.is()) + { + xProp->setPropertyValue( "LineColor", + xSeriesProp->getPropertyValue( "Color")); + } + } +} + +void RegressionCurveHelper::addMeanValueLine( + rtl::Reference< DataSeries > const & xRegCnt, + const uno::Reference< XPropertySet > & xSeriesProp ) +{ + if( !xRegCnt.is() || + ::chart::RegressionCurveHelper::hasMeanValueLine( xRegCnt ) ) + return; + + // todo: use a valid context + rtl::Reference< RegressionCurveModel > xCurve( createMeanValueLine() ); + xRegCnt->addRegressionCurve( xCurve ); + + if( xSeriesProp.is()) + { + xCurve->setPropertyValue( "LineColor", + xSeriesProp->getPropertyValue( "Color")); + } +} + +void RegressionCurveHelper::removeMeanValueLine( + Reference< XRegressionCurveContainer > const & xRegCnt ) +{ + if( !xRegCnt.is()) + return; + + try + { + const Sequence< Reference< XRegressionCurve > > aCurves( + xRegCnt->getRegressionCurves()); + for( Reference< XRegressionCurve > const & curve : aCurves ) + { + if( isMeanValueLine( curve )) + { + xRegCnt->removeRegressionCurve( curve ); + // attention: the iterator i has become invalid now + + // note: assume that there is only one mean-value curve + // to remove multiple mean-value curves remove the break + break; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void RegressionCurveHelper::removeMeanValueLine( + rtl::Reference< DataSeries > const & xRegCnt ) +{ + if( !xRegCnt.is()) + return; + + try + { + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( isMeanValueLine( curve )) + { + xRegCnt->removeRegressionCurve( curve ); + // attention: the iterator i has become invalid now + + // note: assume that there is only one mean-value curve + // to remove multiple mean-value curves remove the break + break; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::addRegressionCurve( + SvxChartRegress eType, + uno::Reference< XRegressionCurveContainer > const & xRegressionCurveContainer, + const uno::Reference< beans::XPropertySet >& xPropertySource, + const uno::Reference< beans::XPropertySet >& xEquationProperties ) +{ + rtl::Reference< RegressionCurveModel > xCurve; + + if( !xRegressionCurveContainer.is() ) + return xCurve; + + if( eType == SvxChartRegress::NONE ) + { + OSL_FAIL("don't create a regression curve of type none"); + return xCurve; + } + + OUString aServiceName( lcl_getServiceNameForType( eType )); + if( !aServiceName.isEmpty()) + { + // todo: use a valid context + xCurve = createRegressionCurveByServiceName( aServiceName ); + + if( xEquationProperties.is()) + xCurve->setEquationProperties( xEquationProperties ); + + if( xPropertySource.is()) + comphelper::copyProperties( xPropertySource, xCurve ); + else + { + uno::Reference< XPropertySet > xSeriesProp( xRegressionCurveContainer, uno::UNO_QUERY ); + if( xSeriesProp.is()) + { + xCurve->setPropertyValue( "LineColor", + xSeriesProp->getPropertyValue( "Color")); + } + } + } + xRegressionCurveContainer->addRegressionCurve( xCurve ); + + return xCurve; +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::addRegressionCurve( + SvxChartRegress eType, + rtl::Reference< DataSeries > const & xRegressionCurveContainer, + const uno::Reference< beans::XPropertySet >& xPropertySource, + const uno::Reference< beans::XPropertySet >& xEquationProperties ) +{ + rtl::Reference< RegressionCurveModel > xCurve; + + if( !xRegressionCurveContainer.is() ) + return xCurve; + + if( eType == SvxChartRegress::NONE ) + { + OSL_FAIL("don't create a regression curve of type none"); + return xCurve; + } + + OUString aServiceName( lcl_getServiceNameForType( eType )); + if( !aServiceName.isEmpty()) + { + // todo: use a valid context + xCurve = createRegressionCurveByServiceName( aServiceName ); + + if( xEquationProperties.is()) + xCurve->setEquationProperties( xEquationProperties ); + + if( xPropertySource.is()) + comphelper::copyProperties( xPropertySource, xCurve ); + else + { + xCurve->setPropertyValue( "LineColor", + xRegressionCurveContainer->getPropertyValue( "Color")); + } + } + xRegressionCurveContainer->addRegressionCurve( xCurve ); + + return xCurve; +} + +/** removes all regression curves that are not of type mean value + and returns true, if anything was removed + */ +bool RegressionCurveHelper::removeAllExceptMeanValueLine( + rtl::Reference< DataSeries > const & xRegCnt ) +{ + if( !xRegCnt.is()) + return false; + + bool bRemovedSomething = false; + try + { + std::vector< rtl::Reference< RegressionCurveModel > > aCurvesToDelete; + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( ! isMeanValueLine( curve )) + { + aCurvesToDelete.push_back( curve ); + } + } + + for (auto const& curveToDelete : aCurvesToDelete) + { + xRegCnt->removeRegressionCurve(curveToDelete); + bRemovedSomething = true; + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bRemovedSomething; +} + +void RegressionCurveHelper::removeEquations( + rtl::Reference< DataSeries > const & xRegCnt ) +{ + if( !xRegCnt.is()) + return; + + try + { + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( !isMeanValueLine( curve ) ) + { + uno::Reference< beans::XPropertySet > xEqProp( curve->getEquationProperties() ) ; + if( xEqProp.is()) + { + xEqProp->setPropertyValue( "ShowEquation", uno::Any( false )); + xEqProp->setPropertyValue( "XName", uno::Any( OUString("x") )); + xEqProp->setPropertyValue( "YName", uno::Any( OUString("f(x) ") )); + xEqProp->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( false )); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::changeRegressionCurveType( + SvxChartRegress eType, + uno::Reference< XRegressionCurveContainer > const & xRegressionCurveContainer, + uno::Reference< XRegressionCurve > const & xRegressionCurve ) +{ + xRegressionCurveContainer->removeRegressionCurve( xRegressionCurve ); + return RegressionCurveHelper::addRegressionCurve( + eType, + xRegressionCurveContainer, + uno::Reference< beans::XPropertySet >( xRegressionCurve, uno::UNO_QUERY ), + xRegressionCurve->getEquationProperties()); +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::getFirstCurveNotMeanValueLine( + const Reference< XRegressionCurveContainer > & xRegCnt ) +{ + if( !xRegCnt.is()) + return nullptr; + + try + { + const uno::Sequence< uno::Reference< chart2::XRegressionCurve > > aCurves( + xRegCnt->getRegressionCurves()); + for( uno::Reference< chart2::XRegressionCurve > const & curve : aCurves ) + { + if( ! isMeanValueLine( curve )) + { + return dynamic_cast(curve.get()); + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nullptr; +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::getFirstCurveNotMeanValueLine( + const rtl::Reference< DataSeries > & xRegCnt ) +{ + if( !xRegCnt.is()) + return nullptr; + + try + { + for( rtl::Reference< RegressionCurveModel > const & curve : xRegCnt->getRegressionCurves2() ) + { + if( ! isMeanValueLine( curve )) + { + return curve; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nullptr; +} + +rtl::Reference< RegressionCurveModel > RegressionCurveHelper::getRegressionCurveAtIndex( + const rtl::Reference< DataSeries >& xCurveContainer, + sal_Int32 aIndex ) +{ + if( !xCurveContainer.is()) + return nullptr; + + try + { + const std::vector< rtl::Reference< RegressionCurveModel > > aCurves(xCurveContainer->getRegressionCurves2()); + if(0 <= aIndex && o3tl::make_unsigned(aIndex) < aCurves.size()) + { + if(!isMeanValueLine(aCurves[aIndex])) + return aCurves[aIndex]; + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return nullptr; +} + +SvxChartRegress RegressionCurveHelper::getRegressionType( + const Reference< XRegressionCurve > & xCurve ) +{ + SvxChartRegress eResult = SvxChartRegress::Unknown; + + try + { + Reference< lang::XServiceName > xServName( xCurve, uno::UNO_QUERY ); + if( xServName.is()) + { + OUString aServiceName( xServName->getServiceName() ); + + if( aServiceName == "com.sun.star.chart2.LinearRegressionCurve" ) + { + eResult = SvxChartRegress::Linear; + } + else if( aServiceName == "com.sun.star.chart2.LogarithmicRegressionCurve" ) + { + eResult = SvxChartRegress::Log; + } + else if( aServiceName == "com.sun.star.chart2.ExponentialRegressionCurve" ) + { + eResult = SvxChartRegress::Exp; + } + else if( aServiceName == "com.sun.star.chart2.PotentialRegressionCurve" ) + { + eResult = SvxChartRegress::Power; + } + else if( aServiceName == "com.sun.star.chart2.MeanValueRegressionCurve" ) + { + eResult = SvxChartRegress::MeanValue; + } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + eResult = SvxChartRegress::Polynomial; + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + eResult = SvxChartRegress::MovingAverage; + } + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + return eResult; +} + +SvxChartRegress RegressionCurveHelper::getFirstRegressTypeNotMeanValueLine( + const Reference< XRegressionCurveContainer > & xRegCnt ) +{ + SvxChartRegress eResult = SvxChartRegress::NONE; + + if( xRegCnt.is()) + { + const Sequence< Reference< XRegressionCurve > > aCurves( + xRegCnt->getRegressionCurves()); + for( Reference< XRegressionCurve > const & curve : aCurves ) + { + SvxChartRegress eType = getRegressionType( curve ); + if( eType != SvxChartRegress::MeanValue && + eType != SvxChartRegress::Unknown ) + { + eResult = eType; + break; + } + } + } + + return eResult; +} + +OUString RegressionCurveHelper::getUINameForRegressionCurve( const Reference< XRegressionCurve >& xRegressionCurve ) +{ + OUString aResult = getRegressionCurveSpecificName(xRegressionCurve); + if (aResult.isEmpty()) + { + aResult = getRegressionCurveGenericName(xRegressionCurve); + if (!aResult.isEmpty()) + { + aResult += " (%SERIESNAME)"; + } + } + return aResult; +} + +OUString RegressionCurveHelper::getRegressionCurveGenericName(const Reference< XRegressionCurve >& xRegressionCurve) +{ + OUString aResult; + if(!xRegressionCurve.is()) + return aResult; + + Reference< lang::XServiceName > xServiceName( xRegressionCurve, uno::UNO_QUERY ); + if(!xServiceName.is()) + return aResult; + + OUString aServiceName(xServiceName->getServiceName()); + + if( aServiceName == "com.sun.star.chart2.MeanValueRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_MEAN); + } + else if( aServiceName == "com.sun.star.chart2.LinearRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_LINEAR); + } + else if( aServiceName == "com.sun.star.chart2.LogarithmicRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_LOG); + } + else if( aServiceName == "com.sun.star.chart2.ExponentialRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_EXP); + } + else if( aServiceName == "com.sun.star.chart2.PotentialRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_POWER); + } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_POLYNOMIAL); + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + aResult = SchResId(STR_REGRESSION_MOVING_AVERAGE); + } + return aResult; +} + +OUString RegressionCurveHelper::getRegressionCurveSpecificName(const Reference< XRegressionCurve >& xRegressionCurve) +{ + OUString aResult; + + if(!xRegressionCurve.is()) + return aResult; + + Reference xProperties( xRegressionCurve, uno::UNO_QUERY ); + if(!xProperties.is()) + return aResult; + + xProperties->getPropertyValue("CurveName") >>= aResult; + + return aResult; +} + +OUString RegressionCurveHelper::getRegressionCurveName( const Reference< XRegressionCurve >& xRegressionCurve ) +{ + OUString aResult = getRegressionCurveSpecificName(xRegressionCurve); + if (aResult.isEmpty()) + return getRegressionCurveGenericName(xRegressionCurve); + return aResult; +} + +std::vector< rtl::Reference< RegressionCurveModel > > + RegressionCurveHelper::getAllRegressionCurvesNotMeanValueLine( + const rtl::Reference< Diagram > & xDiagram ) +{ + std::vector< rtl::Reference< RegressionCurveModel > > aResult; + std::vector< rtl::Reference< DataSeries > > aSeries( DiagramHelper::getDataSeriesFromDiagram( xDiagram )); + for (auto const& elem : aSeries) + { + for( rtl::Reference< RegressionCurveModel > const & curve : elem->getRegressionCurves2() ) + { + if( ! isMeanValueLine( curve )) + aResult.push_back( curve ); + } + } + + return aResult; +} + +void RegressionCurveHelper::resetEquationPosition( + const Reference< chart2::XRegressionCurve > & xCurve ) +{ + if( !xCurve.is()) + return; + + try + { + static const OUStringLiteral aPosPropertyName( u"RelativePosition" ); + Reference< beans::XPropertySet > xEqProp( xCurve->getEquationProperties()); // since m233: , uno::UNO_SET_THROW ); + if( xEqProp->getPropertyValue( aPosPropertyName ).hasValue()) + xEqProp->setPropertyValue( aPosPropertyName, uno::Any()); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +sal_Int32 RegressionCurveHelper::getRegressionCurveIndex( + const rtl::Reference< DataSeries >& xContainer, + const rtl::Reference< RegressionCurveModel >& xCurve ) +{ + if( xContainer.is()) + { + const std::vector< rtl::Reference< RegressionCurveModel > > & aCurves( + xContainer->getRegressionCurves2()); + + for( std::size_t i = 0; i < aCurves.size(); ++i ) + { + if( xCurve == aCurves[i] ) + return i; + } + } + return -1; +} + +bool RegressionCurveHelper::hasEquation( const Reference< chart2::XRegressionCurve > & xCurve ) +{ + bool bHasEquation = false; + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xEquationProp( xCurve->getEquationProperties()); + if( xEquationProp.is()) + { + bool bShowEquation = false; + bool bShowCoefficient = false; + xEquationProp->getPropertyValue( "ShowEquation") >>= bShowEquation; + xEquationProp->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCoefficient; + bHasEquation = bShowEquation || bShowCoefficient; + } + } + return bHasEquation; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionCurveModel.cxx b/chart2/source/tools/RegressionCurveModel.cxx new file mode 100644 index 000000000..890913e34 --- /dev/null +++ b/chart2/source/tools/RegressionCurveModel.cxx @@ -0,0 +1,541 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "RegressionEquation.hxx" +#include +#include +#include +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace +{ +enum +{ + PROPERTY_DEGREE, + PROPERTY_PERIOD, + PROPERTY_EXTRAPOLATE_FORWARD, + PROPERTY_EXTRAPOLATE_BACKWARD, + PROPERTY_FORCE_INTERCEPT, + PROPERTY_INTERCEPT_VALUE, + PROPERTY_CURVE_NAME, + PROPERTY_MOVING_AVERAGE_TYPE +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "PolynomialDegree", + PROPERTY_DEGREE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MovingAveragePeriod", + PROPERTY_PERIOD, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "MovingAverageType", + PROPERTY_MOVING_AVERAGE_TYPE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ExtrapolateForward", + PROPERTY_EXTRAPOLATE_FORWARD, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ExtrapolateBackward", + PROPERTY_EXTRAPOLATE_BACKWARD, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ForceIntercept", + PROPERTY_FORCE_INTERCEPT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "InterceptValue", + PROPERTY_INTERCEPT_VALUE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "CurveName", + PROPERTY_CURVE_NAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND ); +} + +::chart::tPropertyValueMap GetStaticXXXDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + [](){ + ::chart::tPropertyValueMap aTmp; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aTmp ); + return aTmp; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& GetStaticRegressionCurveInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = + [](){ + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +uno::Reference< beans::XPropertySetInfo >& GetStaticRegressionCurveInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(GetStaticRegressionCurveInfoHelper() ) ); + return xPropertySetInfo; +}; + +} // anonymous namespace + +namespace chart +{ + +RegressionCurveModel::RegressionCurveModel( tCurveType eCurveType ) : + ::property::OPropertySet( m_aMutex ), + m_eRegressionCurveType( eCurveType ), + m_xModifyEventForwarder( new ModifyEventForwarder() ), + m_xEquationProperties( new RegressionEquation ) +{ + // set 0 line width (default) hard, so that it is always written to XML, + // because the old implementation uses different defaults + setFastPropertyValue_NoBroadcast( + LinePropertiesHelper::PROP_LINE_WIDTH, uno::Any( sal_Int32( 0 ))); + ModifyListenerHelper::addListener( m_xEquationProperties, m_xModifyEventForwarder ); +} + +RegressionCurveModel::RegressionCurveModel( const RegressionCurveModel & rOther ) : + impl::RegressionCurveModel_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_eRegressionCurveType( rOther.m_eRegressionCurveType ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + m_xEquationProperties.set( CloneHelper::CreateRefClone< beans::XPropertySet >()( rOther.m_xEquationProperties )); + ModifyListenerHelper::addListener( m_xEquationProperties, m_xModifyEventForwarder ); +} + +RegressionCurveModel::~RegressionCurveModel() +{} + +// ____ XRegressionCurve ____ +uno::Reference< chart2::XRegressionCurveCalculator > SAL_CALL + RegressionCurveModel::getCalculator() +{ + return RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( getServiceName()); +} + +uno::Reference< beans::XPropertySet > SAL_CALL RegressionCurveModel::getEquationProperties() +{ + return m_xEquationProperties; +} + +void SAL_CALL RegressionCurveModel::setEquationProperties( const uno::Reference< beans::XPropertySet >& xEquationProperties ) +{ + if( xEquationProperties.is()) + { + if( m_xEquationProperties.is()) + ModifyListenerHelper::removeListener( m_xEquationProperties, m_xModifyEventForwarder ); + + m_xEquationProperties.set( xEquationProperties ); + ModifyListenerHelper::addListener( m_xEquationProperties, m_xModifyEventForwarder ); + fireModifyEvent(); + } +} + +// ____ XServiceName ____ +OUString SAL_CALL RegressionCurveModel::getServiceName() +{ + switch( m_eRegressionCurveType ) + { + case CURVE_TYPE_MEAN_VALUE: + return "com.sun.star.chart2.MeanValueRegressionCurve"; + case CURVE_TYPE_LINEAR: + return "com.sun.star.chart2.LinearRegressionCurve"; + case CURVE_TYPE_LOGARITHM: + return "com.sun.star.chart2.LogarithmicRegressionCurve"; + case CURVE_TYPE_EXPONENTIAL: + return "com.sun.star.chart2.ExponentialRegressionCurve"; + case CURVE_TYPE_POWER: + return "com.sun.star.chart2.PotentialRegressionCurve"; + case CURVE_TYPE_POLYNOMIAL: + return "com.sun.star.chart2.PolynomialRegressionCurve"; + case CURVE_TYPE_MOVING_AVERAGE: + return "com.sun.star.chart2.MovingAverageRegressionCurve"; + } + + return OUString(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL RegressionCurveModel::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL RegressionCurveModel::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL RegressionCurveModel::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL RegressionCurveModel::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void RegressionCurveModel::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void RegressionCurveModel::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ OPropertySet ____ +void RegressionCurveModel::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = GetStaticXXXDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL RegressionCurveModel::getInfoHelper() +{ + return GetStaticRegressionCurveInfoHelper(); +} + +// ____ XPropertySet ____ +uno::Reference< beans::XPropertySetInfo > SAL_CALL RegressionCurveModel::getPropertySetInfo() +{ + return GetStaticRegressionCurveInfo(); +} + +// needed by MSC compiler +using impl::RegressionCurveModel_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( RegressionCurveModel, RegressionCurveModel_Base, OPropertySet ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( RegressionCurveModel, RegressionCurveModel_Base, OPropertySet ) + +// implementations + +MeanValueRegressionCurve::MeanValueRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_MEAN_VALUE ) +{} +MeanValueRegressionCurve::MeanValueRegressionCurve( + const MeanValueRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +MeanValueRegressionCurve::~MeanValueRegressionCurve() +{} + +OUString SAL_CALL MeanValueRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.MeanValueRegressionCurve"; +} + +sal_Bool SAL_CALL MeanValueRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL MeanValueRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.MeanValueRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL MeanValueRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new MeanValueRegressionCurve( *this )); +} + +LinearRegressionCurve::LinearRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_LINEAR ) +{} +LinearRegressionCurve::LinearRegressionCurve( + const LinearRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +LinearRegressionCurve::~LinearRegressionCurve() +{} + +OUString SAL_CALL LinearRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.LinearRegressionCurve"; +} + +sal_Bool SAL_CALL LinearRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LinearRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.LinearRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL LinearRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new LinearRegressionCurve( *this )); +} + +LogarithmicRegressionCurve::LogarithmicRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_LOGARITHM ) +{} +LogarithmicRegressionCurve::LogarithmicRegressionCurve( + const LogarithmicRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +LogarithmicRegressionCurve::~LogarithmicRegressionCurve() +{} + +OUString SAL_CALL LogarithmicRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.LogarithmicRegressionCurve"; +} + +sal_Bool SAL_CALL LogarithmicRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LogarithmicRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.LogarithmicRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL LogarithmicRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new LogarithmicRegressionCurve( *this )); +} + +ExponentialRegressionCurve::ExponentialRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_EXPONENTIAL ) +{} +ExponentialRegressionCurve::ExponentialRegressionCurve( + const ExponentialRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +ExponentialRegressionCurve::~ExponentialRegressionCurve() +{} + +OUString SAL_CALL ExponentialRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.ExponentialRegressionCurve"; +} + +sal_Bool SAL_CALL ExponentialRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ExponentialRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.ExponentialRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL ExponentialRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new ExponentialRegressionCurve( *this )); +} + +PotentialRegressionCurve::PotentialRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_POWER ) +{} +PotentialRegressionCurve::PotentialRegressionCurve( + const PotentialRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +PotentialRegressionCurve::~PotentialRegressionCurve() +{} + +OUString SAL_CALL PotentialRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.PotentialRegressionCurve"; +} + +sal_Bool SAL_CALL PotentialRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PotentialRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.PotentialRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL PotentialRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new PotentialRegressionCurve( *this )); +} + +PolynomialRegressionCurve::PolynomialRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_POLYNOMIAL ) +{} +PolynomialRegressionCurve::PolynomialRegressionCurve( + const PolynomialRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +PolynomialRegressionCurve::~PolynomialRegressionCurve() +{} + +OUString SAL_CALL PolynomialRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.PolynomialRegressionCurve"; +} + +sal_Bool SAL_CALL PolynomialRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PolynomialRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.PolynomialRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL PolynomialRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new PolynomialRegressionCurve( *this )); +} + +MovingAverageRegressionCurve::MovingAverageRegressionCurve() + : RegressionCurveModel( RegressionCurveModel::CURVE_TYPE_MOVING_AVERAGE ) +{} +MovingAverageRegressionCurve::MovingAverageRegressionCurve( + const MovingAverageRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +MovingAverageRegressionCurve::~MovingAverageRegressionCurve() +{} + +OUString SAL_CALL MovingAverageRegressionCurve::getImplementationName() +{ + return "com.sun.star.comp.chart2.MovingAverageRegressionCurve"; +} + +sal_Bool SAL_CALL MovingAverageRegressionCurve::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL MovingAverageRegressionCurve::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionCurve", "com.sun.star.chart2.MovingAverageRegressionCurve" }; +} + +uno::Reference< util::XCloneable > SAL_CALL MovingAverageRegressionCurve::createClone() +{ + return uno::Reference< util::XCloneable >( new MovingAverageRegressionCurve( *this )); +} + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ExponentialRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::ExponentialRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_LinearRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::LinearRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_LogarithmicRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::LogarithmicRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_MeanValueRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::MeanValueRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PotentialRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PotentialRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_PolynomialRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::PolynomialRegressionCurve ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_MovingAverageRegressionCurve_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::MovingAverageRegressionCurve ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionEquation.cxx b/chart2/source/tools/RegressionEquation.cxx new file mode 100644 index 000000000..d421b09d5 --- /dev/null +++ b/chart2/source/tools/RegressionEquation.cxx @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "RegressionEquation.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::uno { class XComponentContext; } + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::Property; +using ::osl::MutexGuard; + +namespace +{ + +enum +{ + PROP_EQUATION_SHOW, + PROP_EQUATION_XNAME, + PROP_EQUATION_YNAME, + PROP_EQUATION_SHOW_CORRELATION_COEFF, + PROP_EQUATION_REF_PAGE_SIZE, + PROP_EQUATION_REL_POS, + PROP_EQUATION_NUMBER_FORMAT +}; + +void lcl_AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ShowEquation", + PROP_EQUATION_SHOW, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "XName", + PROP_EQUATION_XNAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "YName", + PROP_EQUATION_YNAME, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ShowCorrelationCoefficient", + PROP_EQUATION_SHOW_CORRELATION_COEFF, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEDEFAULT ); + + rOutProperties.emplace_back( "ReferencePageSize", + PROP_EQUATION_REF_PAGE_SIZE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( "RelativePosition", + PROP_EQUATION_REL_POS, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + + rOutProperties.emplace_back( CHART_UNONAME_NUMFMT, + PROP_EQUATION_NUMBER_FORMAT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +::chart::tPropertyValueMap& GetStaticRegressionEquationDefaults() +{ + static ::chart::tPropertyValueMap aStaticDefaults = + [](){ + ::chart::tPropertyValueMap aOutMap; + ::chart::LinePropertiesHelper::AddDefaultsToMap( aOutMap ); + ::chart::FillProperties::AddDefaultsToMap( aOutMap ); + ::chart::CharacterProperties::AddDefaultsToMap( aOutMap ); + + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_EQUATION_SHOW, false ); + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_EQUATION_XNAME, OUString("x") ); + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_EQUATION_YNAME, OUString("f(x)") ); + ::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_EQUATION_SHOW_CORRELATION_COEFF, false ); + //::chart::PropertyHelper::setPropertyValueDefault( aOutMap, PROP_EQUATION_SEPARATOR, OUString( '\n' )); + + // override other defaults + ::chart::PropertyHelper::setPropertyValue( aOutMap, ::chart::FillProperties::PROP_FILL_STYLE, drawing::FillStyle_NONE ); + ::chart::PropertyHelper::setPropertyValue( aOutMap, ::chart::LinePropertiesHelper::PROP_LINE_STYLE, drawing::LineStyle_NONE ); + + float fDefaultCharHeight = 10.0; + ::chart::PropertyHelper::setPropertyValue( aOutMap, ::chart::CharacterProperties::PROP_CHAR_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aOutMap, ::chart::CharacterProperties::PROP_CHAR_ASIAN_CHAR_HEIGHT, fDefaultCharHeight ); + ::chart::PropertyHelper::setPropertyValue( aOutMap, ::chart::CharacterProperties::PROP_CHAR_COMPLEX_CHAR_HEIGHT, fDefaultCharHeight ); + return aOutMap; + }(); + return aStaticDefaults; +}; + +::cppu::OPropertyArrayHelper& GetStaticRegressionEquationInfoHelper() +{ + static ::cppu::OPropertyArrayHelper aPropHelper = + [](){ + std::vector< css::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); + ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); + ::chart::FillProperties::AddPropertiesToVector( aProperties ); + ::chart::CharacterProperties::AddPropertiesToVector( aProperties ); + ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties ); + + std::sort( aProperties.begin(), aProperties.end(), + ::chart::PropertyNameLess() ); + + return comphelper::containerToSequence( aProperties ); + }(); + return aPropHelper; +}; + +const uno::Reference< beans::XPropertySetInfo > & GetStaticRegressionEquationInfo() +{ + static uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( + ::cppu::OPropertySetHelper::createPropertySetInfo(GetStaticRegressionEquationInfoHelper()) ); + return xPropertySetInfo; +}; + +} // anonymous namespace + +namespace chart +{ + +RegressionEquation::RegressionEquation() : + ::property::OPropertySet( m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder()) +{} + +RegressionEquation::RegressionEquation( const RegressionEquation & rOther ) : + impl::RegressionEquation_Base(rOther), + ::property::OPropertySet( rOther, m_aMutex ), + m_xModifyEventForwarder( new ModifyEventForwarder()) +{} + +RegressionEquation::~RegressionEquation() +{} + +// ____ XCloneable ____ +uno::Reference< util::XCloneable > SAL_CALL RegressionEquation::createClone() +{ + return uno::Reference< util::XCloneable >( new RegressionEquation( *this )); +} + +// ____ OPropertySet ____ +void RegressionEquation::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const +{ + const tPropertyValueMap& rStaticDefaults = GetStaticRegressionEquationDefaults(); + tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) ); + if( aFound == rStaticDefaults.end() ) + rAny.clear(); + else + rAny = (*aFound).second; +} + +::cppu::IPropertyArrayHelper & SAL_CALL RegressionEquation::getInfoHelper() +{ + return GetStaticRegressionEquationInfoHelper(); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL RegressionEquation::getPropertySetInfo() +{ + return GetStaticRegressionEquationInfo(); +} + +// ____ XModifyBroadcaster ____ +void SAL_CALL RegressionEquation::addModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL RegressionEquation::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +// ____ XModifyListener ____ +void SAL_CALL RegressionEquation::modified( const lang::EventObject& aEvent ) +{ + m_xModifyEventForwarder->modified( aEvent ); +} + +// ____ XEventListener (base of XModifyListener) ____ +void SAL_CALL RegressionEquation::disposing( const lang::EventObject& /* Source */ ) +{ + // nothing +} + +// ____ OPropertySet ____ +void RegressionEquation::firePropertyChangeEvent() +{ + fireModifyEvent(); +} + +void RegressionEquation::fireModifyEvent() +{ + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +// ____ XTitle ____ +uno::Sequence< uno::Reference< chart2::XFormattedString > > SAL_CALL RegressionEquation::getText() +{ + MutexGuard aGuard( m_aMutex ); + return m_aStrings; +} + +void SAL_CALL RegressionEquation::setText( const uno::Sequence< uno::Reference< chart2::XFormattedString > >& Strings ) +{ + MutexGuard aGuard( m_aMutex ); + ModifyListenerHelper::removeListenerFromAllElements( + comphelper::sequenceToContainer > >( m_aStrings ), + m_xModifyEventForwarder ); + m_aStrings = Strings; + ModifyListenerHelper::addListenerToAllElements( + comphelper::sequenceToContainer > >( m_aStrings ), + m_xModifyEventForwarder ); + fireModifyEvent(); +} + +OUString SAL_CALL RegressionEquation::getImplementationName() +{ + return "com.sun.star.comp.chart2.RegressionEquation"; +} + +sal_Bool SAL_CALL RegressionEquation::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL RegressionEquation::getSupportedServiceNames() +{ + return { "com.sun.star.chart2.RegressionEquation", + "com.sun.star.beans.PropertySet", + "com.sun.star.drawing.FillProperties", + "com.sun.star.drawing.LineProperties", + "com.sun.star.style.CharacterProperties" }; +} + +using impl::RegressionEquation_Base; + +IMPLEMENT_FORWARD_XINTERFACE2( RegressionEquation, RegressionEquation_Base, ::property::OPropertySet ) + +} // namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_RegressionEquation_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new ::chart::RegressionEquation); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionEquation.hxx b/chart2/source/tools/RegressionEquation.hxx new file mode 100644 index 000000000..9c26a6ad9 --- /dev/null +++ b/chart2/source/tools/RegressionEquation.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace chart +{ + +namespace impl +{ +typedef ::cppu::WeakImplHelper< + css::lang::XServiceInfo, + css::util::XCloneable, + css::util::XModifyBroadcaster, + css::util::XModifyListener, + css::chart2::XTitle > + RegressionEquation_Base; +} + +class RegressionEquation final : + public cppu::BaseMutex, + public impl::RegressionEquation_Base, + public ::property::OPropertySet +{ +public: + explicit RegressionEquation(); + virtual ~RegressionEquation() override; + + virtual OUString SAL_CALL + getImplementationName() + override; + virtual sal_Bool SAL_CALL + supportsService( const OUString& ServiceName ) + override; + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() + override; + + /// merge XInterface implementations + DECLARE_XINTERFACE() + +private: + explicit RegressionEquation( const RegressionEquation & rOther ); + + // ____ OPropertySet ____ + virtual void GetDefaultValue( sal_Int32 nHandle, css::uno::Any& rAny ) const override; + + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + // ____ XCloneable ____ + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // ____ XModifyBroadcaster ____ + virtual void SAL_CALL addModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + virtual void SAL_CALL removeModifyListener( + const css::uno::Reference< css::util::XModifyListener >& aListener ) override; + + // ____ XModifyListener ____ + virtual void SAL_CALL modified( + const css::lang::EventObject& aEvent ) override; + + // ____ XEventListener (base of XModifyListener) ____ + virtual void SAL_CALL disposing( + const css::lang::EventObject& Source ) override; + + // ____ XTitle ____ + virtual css::uno::Sequence< + css::uno::Reference< css::chart2::XFormattedString > > SAL_CALL getText() override; + virtual void SAL_CALL setText( const css::uno::Sequence< + css::uno::Reference< + css::chart2::XFormattedString > >& Strings ) override; + + using ::cppu::OPropertySetHelper::disposing; + + // ____ OPropertySet ____ + virtual void firePropertyChangeEvent() override; + + void fireModifyEvent(); + + css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > > m_aStrings; + + rtl::Reference m_xModifyEventForwarder; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RelativePositionHelper.cxx b/chart2/source/tools/RelativePositionHelper.cxx new file mode 100644 index 000000000..260888e90 --- /dev/null +++ b/chart2/source/tools/RelativePositionHelper.cxx @@ -0,0 +1,381 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace chart +{ + +chart2::RelativePosition RelativePositionHelper::getReanchoredPosition( + const chart2::RelativePosition & rPosition, + const chart2::RelativeSize & rObjectSize, + drawing::Alignment aNewAnchor ) +{ + chart2::RelativePosition aResult( rPosition ); + if( rPosition.Anchor != aNewAnchor ) + { + sal_Int32 nShiftHalfWidths = 0; + sal_Int32 nShiftHalfHeights = 0; + + // normalize to top-left + switch( rPosition.Anchor ) + { + case drawing::Alignment_TOP_LEFT: + break; + case drawing::Alignment_LEFT: + nShiftHalfHeights -= 1; + break; + case drawing::Alignment_BOTTOM_LEFT: + nShiftHalfHeights -= 2; + break; + case drawing::Alignment_TOP: + nShiftHalfWidths -= 1; + break; + case drawing::Alignment_CENTER: + nShiftHalfWidths -= 1; + nShiftHalfHeights -= 1; + break; + case drawing::Alignment_BOTTOM: + nShiftHalfWidths -= 1; + nShiftHalfHeights -= 2; + break; + case drawing::Alignment_TOP_RIGHT: + nShiftHalfWidths -= 2; + break; + case drawing::Alignment_RIGHT: + nShiftHalfWidths -= 2; + nShiftHalfHeights -= 1; + break; + case drawing::Alignment_BOTTOM_RIGHT: + nShiftHalfWidths -= 2; + nShiftHalfHeights -= 2; + break; + case drawing::Alignment::Alignment_MAKE_FIXED_SIZE: + break; + } + + // transform + switch( aNewAnchor ) + { + case drawing::Alignment_TOP_LEFT: + break; + case drawing::Alignment_LEFT: + nShiftHalfHeights += 1; + break; + case drawing::Alignment_BOTTOM_LEFT: + nShiftHalfHeights += 2; + break; + case drawing::Alignment_TOP: + nShiftHalfWidths += 1; + break; + case drawing::Alignment_CENTER: + nShiftHalfWidths += 1; + nShiftHalfHeights += 1; + break; + case drawing::Alignment_BOTTOM: + nShiftHalfWidths += 1; + nShiftHalfHeights += 2; + break; + case drawing::Alignment_TOP_RIGHT: + nShiftHalfWidths += 2; + break; + case drawing::Alignment_RIGHT: + nShiftHalfWidths += 2; + nShiftHalfHeights += 1; + break; + case drawing::Alignment_BOTTOM_RIGHT: + nShiftHalfWidths += 2; + nShiftHalfHeights += 2; + break; + case drawing::Alignment::Alignment_MAKE_FIXED_SIZE: + break; + } + + if( nShiftHalfWidths != 0 ) + aResult.Primary += (rObjectSize.Primary / 2.0) * nShiftHalfWidths; + if( nShiftHalfHeights != 0 ) + aResult.Secondary += (rObjectSize.Secondary / 2.0) * nShiftHalfHeights; + } + + return aResult; +} + +awt::Point RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + awt::Point aPoint + , awt::Size aObjectSize + , drawing::Alignment aAnchor ) +{ + awt::Point aResult( aPoint ); + + double fXDelta = 0.0; + double fYDelta = 0.0; + + // adapt x-value + switch( aAnchor ) + { + case drawing::Alignment_TOP: + case drawing::Alignment_CENTER: + case drawing::Alignment_BOTTOM: + fXDelta -= static_cast< double >( aObjectSize.Width ) / 2.0; + break; + case drawing::Alignment_TOP_RIGHT: + case drawing::Alignment_RIGHT: + case drawing::Alignment_BOTTOM_RIGHT: + fXDelta -= aObjectSize.Width; + break; + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_LEFT: + case drawing::Alignment_BOTTOM_LEFT: + default: + // nothing to do + break; + } + + // adapt y-value + switch( aAnchor ) + { + case drawing::Alignment_LEFT: + case drawing::Alignment_CENTER: + case drawing::Alignment_RIGHT: + fYDelta -= static_cast< double >( aObjectSize.Height ) / 2.0; + break; + case drawing::Alignment_BOTTOM_LEFT: + case drawing::Alignment_BOTTOM: + case drawing::Alignment_BOTTOM_RIGHT: + fYDelta -= aObjectSize.Height; + break; + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_TOP: + case drawing::Alignment_TOP_RIGHT: + default: + // nothing to do + break; + } + + aResult.X += static_cast< sal_Int32 >( ::rtl::math::round( fXDelta )); + aResult.Y += static_cast< sal_Int32 >( ::rtl::math::round( fYDelta )); + + return aResult; +} + +awt::Point RelativePositionHelper::getCenterOfAnchoredObject( + awt::Point aPoint + , awt::Size aUnrotatedObjectSize + , drawing::Alignment aAnchor + , double fAnglePi ) +{ + awt::Point aResult( aPoint ); + + double fXDelta = 0.0; + double fYDelta = 0.0; + + // adapt x-value + switch( aAnchor ) + { + case drawing::Alignment_TOP: + case drawing::Alignment_CENTER: + case drawing::Alignment_BOTTOM: + // nothing to do + break; + case drawing::Alignment_TOP_RIGHT: + case drawing::Alignment_RIGHT: + case drawing::Alignment_BOTTOM_RIGHT: + fXDelta -= aUnrotatedObjectSize.Width/2; + break; + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_LEFT: + case drawing::Alignment_BOTTOM_LEFT: + default: + fXDelta += aUnrotatedObjectSize.Width/2; + break; + } + + // adapt y-value + switch( aAnchor ) + { + case drawing::Alignment_LEFT: + case drawing::Alignment_CENTER: + case drawing::Alignment_RIGHT: + // nothing to do + break; + case drawing::Alignment_BOTTOM_LEFT: + case drawing::Alignment_BOTTOM: + case drawing::Alignment_BOTTOM_RIGHT: + fYDelta -= aUnrotatedObjectSize.Height/2; + break; + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_TOP: + case drawing::Alignment_TOP_RIGHT: + fYDelta += aUnrotatedObjectSize.Height/2; + break; + default: + // nothing to do + break; + } + + //take rotation into account: + aResult.X += static_cast< sal_Int32 >( + ::rtl::math::round( fXDelta * std::cos( fAnglePi ) + fYDelta * std::sin( fAnglePi ) ) ); + aResult.Y += static_cast< sal_Int32 >( + ::rtl::math::round( - fXDelta * std::sin( fAnglePi ) + fYDelta * std::cos( fAnglePi ) ) ); + + return aResult; +} + +bool RelativePositionHelper::centerGrow( + chart2::RelativePosition & rInOutPosition, + chart2::RelativeSize & rInOutSize, + double fAmountX, double fAmountY ) +{ + chart2::RelativePosition aPos( rInOutPosition ); + chart2::RelativeSize aSize( rInOutSize ); + const double fPosCheckThreshold = 0.02; + const double fSizeCheckThreshold = 0.1; + + // grow/shrink, back to relative + aSize.Primary += fAmountX; + aSize.Secondary += fAmountY; + + double fShiftAmountX = fAmountX / 2.0; + double fShiftAmountY = fAmountY / 2.0; + + // shift X + switch( rInOutPosition.Anchor ) + { + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_LEFT: + case drawing::Alignment_BOTTOM_LEFT: + aPos.Primary -= fShiftAmountX; + break; + case drawing::Alignment_TOP: + case drawing::Alignment_CENTER: + case drawing::Alignment_BOTTOM: + // nothing + break; + case drawing::Alignment_TOP_RIGHT: + case drawing::Alignment_RIGHT: + case drawing::Alignment_BOTTOM_RIGHT: + aPos.Primary += fShiftAmountX; + break; + case drawing::Alignment::Alignment_MAKE_FIXED_SIZE: + break; + } + + // shift Y + switch( rInOutPosition.Anchor ) + { + case drawing::Alignment_TOP: + case drawing::Alignment_TOP_LEFT: + case drawing::Alignment_TOP_RIGHT: + aPos.Secondary -= fShiftAmountY; + break; + case drawing::Alignment_CENTER: + case drawing::Alignment_LEFT: + case drawing::Alignment_RIGHT: + // nothing + break; + case drawing::Alignment_BOTTOM: + case drawing::Alignment_BOTTOM_LEFT: + case drawing::Alignment_BOTTOM_RIGHT: + aPos.Secondary += fShiftAmountY; + break; + case drawing::Alignment::Alignment_MAKE_FIXED_SIZE: + break; + } + + // anchor must not be changed + OSL_ASSERT( rInOutPosition.Anchor == aPos.Anchor ); + + if( rInOutPosition.Primary == aPos.Primary && + rInOutPosition.Secondary == aPos.Secondary && + rInOutSize.Primary == aSize.Primary && + rInOutSize.Secondary == aSize.Secondary ) + return false; + + // Note: this somewhat complicated check allows the output being + // out-of-bounds if the input was also out-of-bounds, and the change is + // for "advantage". E.g., you have a chart that laps out on the left + // side. If you shrink it, this should be possible, also if it still + // laps out on the left side afterwards. But you shouldn't be able to + // grow it then. + + chart2::RelativePosition aUpperLeft( + RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_TOP_LEFT )); + chart2::RelativePosition aLowerRight( + RelativePositionHelper::getReanchoredPosition( aPos, aSize, drawing::Alignment_BOTTOM_RIGHT )); + + // Do not grow, if this leads to corners being off-screen + if( fAmountX > 0.0 && + ( (aUpperLeft.Primary < fPosCheckThreshold) || + (aLowerRight.Primary > (1.0 - fPosCheckThreshold)) )) + return false; + if( fAmountY > 0.0 && + ( (aUpperLeft.Secondary < fPosCheckThreshold) || + (aLowerRight.Secondary > (1.0 - fPosCheckThreshold)) )) + return false; + + // Do not shrink, if this leads to a size too small + if( fAmountX < 0.0 && + ( aSize.Primary < fSizeCheckThreshold )) + return false; + if( fAmountY < 0.0 && + ( aSize.Secondary < fSizeCheckThreshold )) + return false; + + rInOutPosition = aPos; + rInOutSize = aSize; + return true; +} + +bool RelativePositionHelper::moveObject( + chart2::RelativePosition & rInOutPosition, + const chart2::RelativeSize & rObjectSize, + double fAmountX, double fAmountY ) +{ + chart2::RelativePosition aPos( rInOutPosition ); + aPos.Primary += fAmountX; + aPos.Secondary += fAmountY; + const double fPosCheckThreshold = 0.02; + + chart2::RelativePosition aUpperLeft( + RelativePositionHelper::getReanchoredPosition( aPos, rObjectSize, drawing::Alignment_TOP_LEFT )); + chart2::RelativePosition aLowerRight( aUpperLeft ); + aLowerRight.Primary += rObjectSize.Primary; + aLowerRight.Secondary += rObjectSize.Secondary; + + const double fFarEdgeThreshold = 1.0 - fPosCheckThreshold; + if( ( fAmountX > 0.0 && (aLowerRight.Primary > fFarEdgeThreshold)) || + ( fAmountX < 0.0 && (aUpperLeft.Primary < fPosCheckThreshold)) || + ( fAmountY > 0.0 && (aLowerRight.Secondary > fFarEdgeThreshold)) || + ( fAmountY < 0.0 && (aUpperLeft.Secondary < fPosCheckThreshold)) ) + return false; + + rInOutPosition = aPos; + return true; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RelativeSizeHelper.cxx b/chart2/source/tools/RelativeSizeHelper.cxx new file mode 100644 index 000000000..c1bdc28fc --- /dev/null +++ b/chart2/source/tools/RelativeSizeHelper.cxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::std; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; + +namespace chart +{ + +double RelativeSizeHelper::calculate( + double fValue, + const awt::Size & rOldReferenceSize, + const awt::Size & rNewReferenceSize ) +{ + if( rOldReferenceSize.Width <= 0 || + rOldReferenceSize.Height <= 0 ) + return fValue; + + return min( + static_cast< double >( rNewReferenceSize.Width ) / static_cast< double >( rOldReferenceSize.Width ), + static_cast< double >( rNewReferenceSize.Height ) / static_cast< double >( rOldReferenceSize.Height )) + * fValue; +} + +void RelativeSizeHelper::adaptFontSizes( + SvxShapeText& xTargetProperties, + const awt::Size & rOldReferenceSize, + const awt::Size & rNewReferenceSize ) +{ + float fFontHeight = 0; + + vector< OUString > aProperties; + aProperties.emplace_back("CharHeight" ); + aProperties.emplace_back("CharHeightAsian" ); + aProperties.emplace_back("CharHeightComplex" ); + + for (auto const& property : aProperties) + { + try + { + if( xTargetProperties.SvxShape::getPropertyValue(property) >>= fFontHeight ) + { + xTargetProperties.SvxShape::setPropertyValue( + property, + Any( static_cast< float >( + calculate( fFontHeight, rOldReferenceSize, rNewReferenceSize )))); + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +void RelativeSizeHelper::adaptFontSizes( + const Reference< XPropertySet > & xTargetProperties, + const awt::Size & rOldReferenceSize, + const awt::Size & rNewReferenceSize ) +{ + if( ! xTargetProperties.is()) + return; + + float fFontHeight = 0; + + vector< OUString > aProperties; + aProperties.emplace_back("CharHeight" ); + aProperties.emplace_back("CharHeightAsian" ); + aProperties.emplace_back("CharHeightComplex" ); + + for (auto const& property : aProperties) + { + try + { + if( xTargetProperties->getPropertyValue(property) >>= fFontHeight ) + { + xTargetProperties->setPropertyValue( + property, + Any( static_cast< float >( + calculate( fFontHeight, rOldReferenceSize, rNewReferenceSize )))); + } + } + catch( const Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ResId.cxx b/chart2/source/tools/ResId.cxx new file mode 100644 index 000000000..aaa1d840c --- /dev/null +++ b/chart2/source/tools/ResId.cxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +namespace chart +{ + OUString SchResId(TranslateId aId) + { + return Translate::get(aId, Translate::Create("chart")); + } +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/Scaling.cxx b/chart2/source/tools/Scaling.cxx new file mode 100644 index 000000000..b49dab6d6 --- /dev/null +++ b/chart2/source/tools/Scaling.cxx @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } + +namespace +{ + +constexpr OUStringLiteral lcl_aServiceName_Logarithmic = u"com.sun.star.chart2.LogarithmicScaling"; +constexpr OUStringLiteral lcl_aServiceName_Exponential = u"com.sun.star.chart2.ExponentialScaling"; +constexpr OUStringLiteral lcl_aServiceName_Linear = u"com.sun.star.chart2.LinearScaling"; +constexpr OUStringLiteral lcl_aServiceName_Power = u"com.sun.star.chart2.PowerScaling"; + +} + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LogarithmicScaling::LogarithmicScaling() : + m_fBase( 10.0 ), + m_fLogOfBase( log( 10.0 ) ) +{ +} + +LogarithmicScaling::LogarithmicScaling( double fBase ) : + m_fBase( fBase ), + m_fLogOfBase( log( fBase ) ) +{ +} + +LogarithmicScaling::~LogarithmicScaling() +{ +} + +double SAL_CALL LogarithmicScaling::doScaling( double value ) +{ + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + return std::log( value ) / m_fLogOfBase; +} + +uno::Reference< XScaling > SAL_CALL LogarithmicScaling::getInverseScaling() +{ + return new ExponentialScaling( m_fBase ); +} + +OUString SAL_CALL LogarithmicScaling::getServiceName() +{ + return lcl_aServiceName_Logarithmic; +} + +OUString SAL_CALL LogarithmicScaling::getImplementationName() +{ + return lcl_aServiceName_Logarithmic; +} + +sal_Bool SAL_CALL LogarithmicScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LogarithmicScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_Logarithmic }; +} + +ExponentialScaling::ExponentialScaling() : + m_fBase( 10.0 ) +{ +} + +ExponentialScaling::ExponentialScaling( double fBase ) : + m_fBase( fBase ) +{ +} + +ExponentialScaling::~ExponentialScaling() +{ +} + +double SAL_CALL ExponentialScaling::doScaling( double value ) +{ + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + return std::pow( m_fBase, value ); +} + +uno::Reference< XScaling > SAL_CALL ExponentialScaling::getInverseScaling() +{ + return new LogarithmicScaling( m_fBase ); +} + +OUString SAL_CALL ExponentialScaling::getServiceName() +{ + return lcl_aServiceName_Exponential; +} + +OUString SAL_CALL ExponentialScaling::getImplementationName() +{ + return lcl_aServiceName_Exponential; +} + +sal_Bool SAL_CALL ExponentialScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ExponentialScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_Exponential }; +} + +LinearScaling::LinearScaling() : + m_fSlope( 1.0 ), + m_fOffset( 0.0 ) +{} + +LinearScaling::LinearScaling( double fSlope, double fOffset ) : + m_fSlope( fSlope ), + m_fOffset( fOffset ) +{} + +LinearScaling::~LinearScaling() +{} + +double SAL_CALL LinearScaling::doScaling( double value ) +{ + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + return m_fOffset + m_fSlope * value; +} + +uno::Reference< XScaling > SAL_CALL + LinearScaling::getInverseScaling() +{ + // ToDo: ApproxEqual ? + if( m_fSlope == 0 ) + throw uno::RuntimeException("Divide by zero exception"); + + return new LinearScaling( 1.0 / m_fSlope, m_fOffset / m_fSlope ); +} + +OUString SAL_CALL LinearScaling::getServiceName() +{ + return lcl_aServiceName_Linear; +} + +OUString SAL_CALL LinearScaling::getImplementationName() +{ + return lcl_aServiceName_Linear ; +} + +sal_Bool SAL_CALL LinearScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL LinearScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_Linear }; +} + +PowerScaling::PowerScaling() : + m_fExponent( 10.0 ) +{} + +PowerScaling::PowerScaling( double fExponent ) : + m_fExponent( fExponent ) +{} + +PowerScaling::~PowerScaling() +{} + +double SAL_CALL PowerScaling::doScaling( double value ) +{ + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + return std::pow( value, m_fExponent ); +} + +uno::Reference< XScaling > SAL_CALL + PowerScaling::getInverseScaling() +{ + // ToDo: ApproxEqual ? + if( m_fExponent == 0 ) + throw uno::RuntimeException("Divide by zero exception"); + + return new PowerScaling( 1.0 / m_fExponent ); +} + + OUString SAL_CALL +PowerScaling::getServiceName() +{ + return lcl_aServiceName_Power; +} + +OUString SAL_CALL PowerScaling::getImplementationName() +{ + return lcl_aServiceName_Power; +} + +sal_Bool SAL_CALL PowerScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL PowerScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_Power }; +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_chart2_LinearScaling_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::LinearScaling ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_chart2_ExponentialScaling_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::ExponentialScaling ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_chart2_LogarithmicScaling_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::LogarithmicScaling ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_chart2_PowerScaling_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new chart::PowerScaling ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/SceneProperties.cxx b/chart2/source/tools/SceneProperties.cxx new file mode 100644 index 000000000..a98bfef2d --- /dev/null +++ b/chart2/source/tools/SceneProperties.cxx @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void SceneProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + // transformation matrix + rOutProperties.emplace_back( "D3DTransformMatrix", + PROP_SCENE_TRANSF_MATRIX, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // distance: deprecated ( this is not used by the chart view; it's only here for compatibility with old chart ) + rOutProperties.emplace_back( "D3DSceneDistance", + PROP_SCENE_DISTANCE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // focalLength: deprecated ( this is not used by the chart view; it's only here for compatibility with old chart ) + rOutProperties.emplace_back( "D3DSceneFocalLength", + PROP_SCENE_FOCAL_LENGTH, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // shadowSlant + rOutProperties.emplace_back( "D3DSceneShadowSlant", + PROP_SCENE_SHADOW_SLANT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // shadeMode + rOutProperties.emplace_back( "D3DSceneShadeMode", + PROP_SCENE_SHADE_MODE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // ambientColor + rOutProperties.emplace_back( "D3DSceneAmbientColor", + PROP_SCENE_AMBIENT_COLOR, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // lightingMode + rOutProperties.emplace_back( "D3DSceneTwoSidedLighting", + PROP_SCENE_TWO_SIDED_LIGHTING, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // camera geometry + rOutProperties.emplace_back( "D3DCameraGeometry", + PROP_SCENE_CAMERA_GEOMETRY, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // perspective + rOutProperties.emplace_back( "D3DScenePerspective", + PROP_SCENE_PERSPECTIVE, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + + // Light Sources + // light source 1 + rOutProperties.emplace_back( "D3DSceneLightColor1", + PROP_SCENE_LIGHT_COLOR_1, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection1", + PROP_SCENE_LIGHT_DIRECTION_1, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn1", + PROP_SCENE_LIGHT_ON_1, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 2 + rOutProperties.emplace_back( "D3DSceneLightColor2", + PROP_SCENE_LIGHT_COLOR_2, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection2", + PROP_SCENE_LIGHT_DIRECTION_2, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn2", + PROP_SCENE_LIGHT_ON_2, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 3 + rOutProperties.emplace_back( "D3DSceneLightColor3", + PROP_SCENE_LIGHT_COLOR_3, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection3", + PROP_SCENE_LIGHT_DIRECTION_3, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn3", + PROP_SCENE_LIGHT_ON_3, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 4 + rOutProperties.emplace_back( "D3DSceneLightColor4", + PROP_SCENE_LIGHT_COLOR_4, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection4", + PROP_SCENE_LIGHT_DIRECTION_4, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn4", + PROP_SCENE_LIGHT_ON_4, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 5 + rOutProperties.emplace_back( "D3DSceneLightColor5", + PROP_SCENE_LIGHT_COLOR_5, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection5", + PROP_SCENE_LIGHT_DIRECTION_5, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn5", + PROP_SCENE_LIGHT_ON_5, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 6 + rOutProperties.emplace_back( "D3DSceneLightColor6", + PROP_SCENE_LIGHT_COLOR_6, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection6", + PROP_SCENE_LIGHT_DIRECTION_6, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn6", + PROP_SCENE_LIGHT_ON_6, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 7 + rOutProperties.emplace_back( "D3DSceneLightColor7", + PROP_SCENE_LIGHT_COLOR_7, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection7", + PROP_SCENE_LIGHT_DIRECTION_7, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn7", + PROP_SCENE_LIGHT_ON_7, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + // light source 8 + rOutProperties.emplace_back( "D3DSceneLightColor8", + PROP_SCENE_LIGHT_COLOR_8, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightDirection8", + PROP_SCENE_LIGHT_DIRECTION_8, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); + rOutProperties.emplace_back( "D3DSceneLightOn8", + PROP_SCENE_LIGHT_ON_8, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID + | beans::PropertyAttribute::MAYBEDEFAULT ); +} + +void SceneProperties::AddDefaultsToMap( + ::chart::tPropertyValueMap & rOutMap ) +{ + // Identity Matrix + drawing::HomogenMatrix aMtx; + aMtx.Line1.Column1 = aMtx.Line2.Column2 = + aMtx.Line3.Column3 = aMtx.Line4.Column4 = 1.0; + aMtx.Line1.Column2 = aMtx.Line1.Column3 = aMtx.Line1.Column4 = + aMtx.Line2.Column1 = aMtx.Line2.Column3 = aMtx.Line2.Column4 = + aMtx.Line3.Column1 = aMtx.Line3.Column2 = aMtx.Line3.Column4 = + aMtx.Line4.Column1 = aMtx.Line4.Column2 = aMtx.Line4.Column3 = 0.0; + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_TRANSF_MATRIX, aMtx ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_SCENE_DISTANCE, 4200 ); + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( rOutMap, PROP_SCENE_FOCAL_LENGTH, 8000 ); + +// PROP_SCENE_SHADOW_SLANT; + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_SHADE_MODE, drawing::ShadeMode_SMOOTH ); + + ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( + rOutMap, PROP_SCENE_AMBIENT_COLOR, ChartTypeHelper::getDefaultAmbientLightColor(false,nullptr)); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_TWO_SIDED_LIGHTING, true ); + + drawing::Position3D vrp( 0.0, 0.0, 1.0 ); + drawing::Direction3D vpn( 0.0, 0.0, 1.0 ); + drawing::Direction3D vup( 0.0, 1.0, 0.0 ); + drawing::CameraGeometry aDefaultCameraGeometry( vrp, vpn, vup ); + + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_CAMERA_GEOMETRY, aDefaultCameraGeometry ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_PERSPECTIVE, drawing::ProjectionMode_PERSPECTIVE ); + + // Light Sources + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_1, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_2, true ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_3, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_4, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_5, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_6, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_7, false ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_ON_8, false ); + + uno::Any aDefaultLightDirection( drawing::Direction3D( 0.0, 0.0, 1.0 ) ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_1, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_2, ChartTypeHelper::getDefaultSimpleLightDirection(nullptr)); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_3, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_4, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_5, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_6, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_7, aDefaultLightDirection ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_DIRECTION_8, aDefaultLightDirection ); + + uno::Any aDefaultLightColor; + aDefaultLightColor <<= ChartTypeHelper::getDefaultDirectLightColor(false,nullptr); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_1, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_2, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_3, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_4, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_5, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_6, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_7, aDefaultLightColor ); + ::chart::PropertyHelper::setPropertyValueDefault( rOutMap, PROP_SCENE_LIGHT_COLOR_8, aDefaultLightColor ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/StatisticsHelper.cxx b/chart2/source/tools/StatisticsHelper.cxx new file mode 100644 index 000000000..78c8b8dda --- /dev/null +++ b/chart2/source/tools/StatisticsHelper.cxx @@ -0,0 +1,363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using namespace ::com::sun::star; + +namespace +{ + +double lcl_getVariance( const Sequence< double > & rData, sal_Int32 & rOutValidCount ) +{ + const sal_Int32 nCount = rData.getLength(); + rOutValidCount = nCount; + + double fSum = 0.0; + double fQuadSum = 0.0; + + for( sal_Int32 i = 0; i < nCount; ++i ) + { + const double fData = rData[i]; + if( std::isnan( fData )) + --rOutValidCount; + else + { + fSum += fData; + fQuadSum += fData * fData; + } + } + + if( rOutValidCount == 0 ) + return std::numeric_limits::quiet_NaN(); + + const double fN = static_cast< double >( rOutValidCount ); + return (fQuadSum - fSum*fSum/fN) / fN; +} + +uno::Reference< chart2::data::XLabeledDataSequence > lcl_getErrorBarLabeledSequence( + const Reference< chart2::data::XDataSource > & xDataSource, + bool bPositiveValue, bool bYError, + OUString & rOutRoleNameUsed ) +{ + OUStringBuffer aRole( "error-bars-"); + if( bYError ) + aRole.append( 'y'); + else + aRole.append( 'x'); + + OUString aPlainRole = aRole.makeStringAndClear(); + aRole.append( aPlainRole ); + aRole.append( '-' ); + + if( bPositiveValue ) + aRole.append( "positive" ); + else + aRole.append( "negative" ); + + OUString aLongRole = aRole.makeStringAndClear(); + uno::Reference< chart2::data::XLabeledDataSequence > xLSeq = + ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aLongRole ); + // try role without "-negative" or "-positive" postfix + if( xLSeq.is()) + rOutRoleNameUsed = aLongRole; + else + { + xLSeq = ::chart::DataSeriesHelper::getDataSequenceByRole( xDataSource, aPlainRole ); + if( xLSeq.is()) + rOutRoleNameUsed = aPlainRole; + else + rOutRoleNameUsed = aLongRole; + } + + return xLSeq; +} + +void lcl_setRole( + const Reference< chart2::data::XDataSequence > & xNewSequence, + const OUString & rRole ) +{ + Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->setPropertyValue( "Role", uno::Any( rRole )); +} + +void lcl_addSequenceToDataSource( + const Reference< chart2::data::XDataSource > & xDataSource, + const Reference< chart2::data::XDataSequence > & xNewSequence, + const OUString & rRole ) +{ + Reference< chart2::data::XDataSink > xSink( xDataSource, uno::UNO_QUERY ); + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + if( ! xSink.is() ) + return; + + Reference< chart2::data::XLabeledDataSequence > xLSeq( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW ); + + lcl_setRole( xNewSequence, rRole ); + xLSeq->setValues( xNewSequence ); + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xDataSource->getDataSequences()); + aSequences.realloc( aSequences.getLength() + 1 ); + auto pSequences = aSequences.getArray(); + pSequences[ aSequences.getLength() - 1 ] = xLSeq; + xSink->setData( aSequences ); +} + +void lcl_setXMLRangePropertyAtDataSequence( + const Reference< chart2::data::XDataSequence > & xDataSequence, + const OUString & rXMLRange ) +{ + try + { + static const OUStringLiteral aXMLRangePropName( u"CachedXMLRange"); + Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); + if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName )) + xProp->setPropertyValue( aXMLRangePropName, uno::Any( rXMLRange )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +} // anonymous namespace + +namespace chart +{ + +double StatisticsHelper::getVariance( + const Sequence< double > & rData ) +{ + sal_Int32 nValCount; + return lcl_getVariance( rData, nValCount ); +} + +double StatisticsHelper::getStandardDeviation( const Sequence< double > & rData ) +{ + double fResult = getVariance( rData ); + if( ! std::isnan( fResult )) + fResult = sqrt( fResult ); + + return fResult; +} + +double StatisticsHelper::getStandardError( const Sequence< double > & rData ) +{ + sal_Int32 nValCount; + double fVar = lcl_getVariance( rData, nValCount ); + + if( nValCount == 0 || std::isnan( fVar )) + return std::numeric_limits::quiet_NaN(); + // standard-deviation / sqrt(n) + return sqrt( fVar ) / sqrt( double(nValCount) ); +} + +uno::Reference< chart2::data::XLabeledDataSequence > StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + const Reference< chart2::data::XDataSource > & xDataSource, + bool bPositiveValue, + bool bYError /* = true */ ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > xResult; + if( !xDataSource.is()) + return xResult; + + OUString aRole; + uno::Reference< chart2::data::XLabeledDataSequence > xLSeq = + lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole ); + if( xLSeq.is()) + xResult = xLSeq; + + return xResult; +} + +Reference< chart2::data::XDataSequence > StatisticsHelper::getErrorDataSequenceFromDataSource( + const Reference< chart2::data::XDataSource > & xDataSource, + bool bPositiveValue, + bool bYError /* = true */ ) +{ + uno::Reference< chart2::data::XLabeledDataSequence > xLSeq = + StatisticsHelper::getErrorLabeledDataSequenceFromDataSource( + xDataSource, bPositiveValue, + bYError ); + if( !xLSeq.is()) + return Reference< chart2::data::XDataSequence >(); + + return xLSeq->getValues(); +} + +double StatisticsHelper::getErrorFromDataSource( + const Reference< chart2::data::XDataSource > & xDataSource, + sal_Int32 nIndex, + bool bPositiveValue, + bool bYError /* = true */ ) +{ + double fResult = std::numeric_limits::quiet_NaN(); + + Reference< chart2::data::XDataSequence > xValues( + StatisticsHelper::getErrorDataSequenceFromDataSource( xDataSource, bPositiveValue, bYError )); + + Reference< chart2::data::XNumericalDataSequence > xNumValues( xValues, uno::UNO_QUERY ); + if( xNumValues.is()) + { + Sequence< double > aData( xNumValues->getNumericalData()); + if( nIndex < aData.getLength()) + fResult = aData[nIndex]; + } + else if( xValues.is()) + { + Sequence< uno::Any > aData( xValues->getData()); + if( nIndex < aData.getLength()) + aData[nIndex] >>= fResult; + } + + return fResult; +} + +void StatisticsHelper::setErrorDataSequence( + const Reference< chart2::data::XDataSource > & xDataSource, + const Reference< chart2::data::XDataProvider > & xDataProvider, + const OUString & rNewRange, + bool bPositiveValue, + bool bYError /* = true */, + OUString const * pXMLRange /* = 0 */ ) +{ + Reference< chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY ); + if( ! ( xDataSink.is() && xDataProvider.is())) + return; + + OUString aRole; + Reference< chart2::data::XLabeledDataSequence > xLSeq( + lcl_getErrorBarLabeledSequence( xDataSource, bPositiveValue, bYError, aRole )); + Reference< chart2::data::XDataSequence > xNewSequence( + xDataProvider->createDataSequenceByRangeRepresentation( rNewRange )); + if( xNewSequence.is()) + { + if( pXMLRange ) + lcl_setXMLRangePropertyAtDataSequence( xNewSequence, *pXMLRange ); + if( xLSeq.is()) + { + lcl_setRole( xNewSequence, aRole ); + xLSeq->setValues( xNewSequence ); + } + else + lcl_addSequenceToDataSource( xDataSource, xNewSequence, aRole ); + } +} + +Reference< beans::XPropertySet > StatisticsHelper::addErrorBars( + const Reference< chart2::XDataSeries > & xDataSeries, + sal_Int32 nStyle, + bool bYError /* = true */ ) +{ + Reference< beans::XPropertySet > xErrorBar; + Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY ); + if( !xSeriesProp.is()) + return xErrorBar; + + const OUString aPropName( + bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X)); + if( !( xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar ) || + !xErrorBar.is()) + { + xErrorBar.set( new ErrorBar ); + } + + OSL_ASSERT( xErrorBar.is()); + if( xErrorBar.is()) + { + xErrorBar->setPropertyValue( "ErrorBarStyle", uno::Any( nStyle )); + } + + xSeriesProp->setPropertyValue( aPropName, uno::Any( xErrorBar )); + + return xErrorBar; +} + +Reference< beans::XPropertySet > StatisticsHelper::getErrorBars( + const Reference< chart2::XDataSeries > & xDataSeries, + bool bYError /* = true */ ) +{ + Reference< beans::XPropertySet > xSeriesProp( xDataSeries, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xErrorBar; + const OUString aPropName( + bYError ? OUString(CHART_UNONAME_ERRORBAR_Y) : OUString(CHART_UNONAME_ERRORBAR_X)); + + if ( xSeriesProp.is()) + xSeriesProp->getPropertyValue( aPropName ) >>= xErrorBar; + + return xErrorBar; +} + +bool StatisticsHelper::hasErrorBars( + const Reference< chart2::XDataSeries > & xDataSeries, + bool bYError /* = true */ ) +{ + Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + return ( xErrorBar.is() && + ( xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + nStyle != css::chart::ErrorBarStyle::NONE ); +} + +void StatisticsHelper::removeErrorBars( + const Reference< chart2::XDataSeries > & xDataSeries, + bool bYError /* = true */ ) +{ + Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); + if ( xErrorBar.is()) + xErrorBar->setPropertyValue( "ErrorBarStyle", uno::Any( + css::chart::ErrorBarStyle::NONE )); +} + +bool StatisticsHelper::usesErrorBarRanges( + const Reference< chart2::XDataSeries > & xDataSeries, + bool bYError /* = true */ ) +{ + Reference< beans::XPropertySet > xErrorBar( getErrorBars( xDataSeries, bYError )); + sal_Int32 nStyle = css::chart::ErrorBarStyle::NONE; + + return ( xErrorBar.is() && + ( xErrorBar->getPropertyValue( "ErrorBarStyle") >>= nStyle ) && + nStyle == css::chart::ErrorBarStyle::FROM_DATA ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ThreeDHelper.cxx b/chart2/source/tools/ThreeDHelper.cxx new file mode 100644 index 000000000..06ce49b2e --- /dev/null +++ b/chart2/source/tools/ThreeDHelper.cxx @@ -0,0 +1,1457 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::rtl::math::cos; +using ::rtl::math::sin; +using ::rtl::math::tan; + +namespace +{ + +bool lcl_isRightAngledAxesSetAndSupported( const rtl::Reference< Diagram >& xDiagram ) +{ + if( xDiagram.is() ) + { + bool bRightAngledAxes = false; + xDiagram->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes; + if(bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) + { + return true; + } + } + } + return false; +} + +void lcl_RotateLightSource( const Reference< beans::XPropertySet >& xSceneProperties + , const OUString& rLightSourceDirection + , const OUString& rLightSourceOn + , const ::basegfx::B3DHomMatrix& rRotationMatrix ) +{ + if( !xSceneProperties.is() ) + return; + + bool bLightOn = false; + if( !(xSceneProperties->getPropertyValue( rLightSourceOn ) >>= bLightOn) ) + return; + + if( bLightOn ) + { + drawing::Direction3D aLight; + if( xSceneProperties->getPropertyValue( rLightSourceDirection ) >>= aLight ) + { + ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) ); + aLightVector = rRotationMatrix*aLightVector; + + xSceneProperties->setPropertyValue( rLightSourceDirection + , uno::Any( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) ); + } + } +} + +void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRottion, const Reference< beans::XPropertySet >& xSceneProperties ) +{ + if(!xSceneProperties.is()) + return; + + ::basegfx::B3DHomMatrix aLightRottion( rLightRottion ); + BaseGFXHelper::ReduceToRotationMatrix( aLightRottion ); + + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection1", "D3DSceneLightOn1", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection2", "D3DSceneLightOn2", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection3", "D3DSceneLightOn3", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection4", "D3DSceneLightOn4", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection5", "D3DSceneLightOn5", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection6", "D3DSceneLightOn6", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection7", "D3DSceneLightOn7", aLightRottion ); + lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection8", "D3DSceneLightOn8", aLightRottion ); +} + +::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties ) +{ + ::basegfx::B3DHomMatrix aInverseRotation; + double fXAngleRad=0.0; + double fYAngleRad=0.0; + double fZAngleRad=0.0; + ThreeDHelper::getRotationAngleFromDiagram( + xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); + aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad ); + aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 ); + aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 ); + return aInverseRotation; +} + +::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties ) +{ + ::basegfx::B3DHomMatrix aCompleteRotation; + double fXAngleRad=0.0; + double fYAngleRad=0.0; + double fZAngleRad=0.0; + ThreeDHelper::getRotationAngleFromDiagram( + xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); + aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + return aCompleteRotation; +} + +bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB ) +{ + return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX) + && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY) + && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ); +} + +bool lcl_isLightScheme( const rtl::Reference< Diagram >& xDiagram, bool bRealistic ) +{ + if(!xDiagram.is()) + return false; + + bool bIsOn = false; + xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2 ) >>= bIsOn; + if(!bIsOn) + return false; + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + + sal_Int32 nColor = 0; + xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ) >>= nColor; + if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) ) + return false; + + sal_Int32 nAmbientColor = 0; + xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR ) >>= nAmbientColor; + if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) ) + return false; + + drawing::Direction3D aDirection(0,0,0); + xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ) >>= aDirection; + + drawing::Direction3D aDefaultDirection( bRealistic + ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) + : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) ); + + //rotate default light direction when right angled axes are off but supported + { + bool bRightAngledAxes = false; + xDiagram->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes; + if(!bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) + { + ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagram ) ); + BaseGFXHelper::ReduceToRotationMatrix( aRotation ); + ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) ); + aLightVector = aRotation*aLightVector; + aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector ); + } + } + } + + return lcl_isEqual( aDirection, aDefaultDirection ); +} + +bool lcl_isRealisticLightScheme( const rtl::Reference< Diagram >& xDiagram ) +{ + return lcl_isLightScheme( xDiagram, true /*bRealistic*/ ); +} +bool lcl_isSimpleLightScheme( const rtl::Reference< Diagram >& xDiagram ) +{ + return lcl_isLightScheme( xDiagram, false /*bRealistic*/ ); +} +void lcl_setLightsForScheme( const rtl::Reference< Diagram >& xDiagram, const ThreeDLookScheme& rScheme ) +{ + if(!xDiagram.is()) + return; + if( rScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown) + return; + + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2, uno::Any( true ) ); + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + uno::Any aADirection( rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple + ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) + : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ); + + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2, aADirection ); + //rotate light direction when right angled axes are off but supported + { + bool bRightAngledAxes = false; + xDiagram->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes; + if(!bRightAngledAxes) + { + if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) ) + { + ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagram ) ); + BaseGFXHelper::ReduceToRotationMatrix( aRotation ); + lcl_RotateLightSource( xDiagram, "D3DSceneLightDirection2", "D3DSceneLightOn2", aRotation ); + } + } + } + + sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( + rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2, uno::Any( nColor ) ); + + sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( + rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR, uno::Any( nAmbientColor ) ); +} + +bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode + , sal_Int32 nRoundedEdges + , sal_Int32 nObjectLines ) +{ + if(aShadeMode!=drawing::ShadeMode_SMOOTH) + return false; + if(nRoundedEdges!=5) + return false; + if(nObjectLines!=0) + return false; + return true; +} + +bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode + , sal_Int32 nRoundedEdges + , sal_Int32 nObjectLines + , const rtl::Reference< Diagram >& xDiagram ) +{ + if(aShadeMode!=drawing::ShadeMode_FLAT) + return false; + if(nRoundedEdges!=0) + return false; + if(nObjectLines==0) + { + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + return ChartTypeHelper::noBordersForSimpleScheme( xChartType ); + } + if(nObjectLines!=1) + return false; + return true; +} + +void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode + , sal_Int32& rnRoundedEdges + , sal_Int32& rnObjectLines ) +{ + rShadeMode = drawing::ShadeMode_SMOOTH; + rnRoundedEdges = 5; + rnObjectLines = 0; +} + +void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode + , sal_Int32& rnRoundedEdges + , sal_Int32& rnObjectLines + , const rtl::Reference< Diagram >& xDiagram ) +{ + rShadeMode = drawing::ShadeMode_FLAT; + rnRoundedEdges = 0; + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1; +} + +} //end anonymous namespace + +drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie ) +{ + // ViewReferencePoint (Point on the View plane) + drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739); + // ViewPlaneNormal (Normal to the View Plane) + drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984); + // ViewUpVector (determines the v-axis direction on the view plane as + // projection of VUP parallel to VPN onto th view pane) + drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273); + + if( bPie ) + { + vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspective + vpn = drawing::Direction3D( 0.0, 0.0, 1.0 ); + vup = drawing::Direction3D( 0.0, 1.0, 0.0 ); + } + + return drawing::CameraGeometry( vrp, vpn, vup ); +} + +namespace +{ +::basegfx::B3DHomMatrix lcl_getCameraMatrix( const uno::Reference< beans::XPropertySet >& xSceneProperties ) +{ + drawing::HomogenMatrix aCameraMatrix; + + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + if( xSceneProperties.is() ) + xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG; + + ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) ); + ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) ); + + //normalize vectors: + aVPN.normalize(); + aVUP.normalize(); + + ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN ); + + //first line is VUP x VPN + aCameraMatrix.Line1.Column1 = aCross[0]; + aCameraMatrix.Line1.Column2 = aCross[1]; + aCameraMatrix.Line1.Column3 = aCross[2]; + aCameraMatrix.Line1.Column4 = 0.0; + + //second line is VUP + aCameraMatrix.Line2.Column1 = aVUP[0]; + aCameraMatrix.Line2.Column2 = aVUP[1]; + aCameraMatrix.Line2.Column3 = aVUP[2]; + aCameraMatrix.Line2.Column4 = 0.0; + + //third line is VPN + aCameraMatrix.Line3.Column1 = aVPN[0]; + aCameraMatrix.Line3.Column2 = aVPN[1]; + aCameraMatrix.Line3.Column3 = aVPN[2]; + aCameraMatrix.Line3.Column4 = 0.0; + + //fourth line is 0 0 0 1 + aCameraMatrix.Line4.Column1 = 0.0; + aCameraMatrix.Line4.Column2 = 0.0; + aCameraMatrix.Line4.Column3 = 0.0; + aCameraMatrix.Line4.Column4 = 1.0; + + return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix ); +} + +double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad ) +{ + //valid range: ]-Pi,Pi] + while( fAngleRad<=-M_PI ) + fAngleRad+=(2*M_PI); + while( fAngleRad>M_PI ) + fAngleRad-=(2*M_PI); + return fAngleRad; +} + +void lcl_ensureIntervalMinus1To1( double& rSinOrCos ) +{ + if (rSinOrCos < -1.0) + rSinOrCos = -1.0; + else if (rSinOrCos > 1.0) + rSinOrCos = 1.0; +} + +bool lcl_isSinZero( double fAngleRad ) +{ + return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 ); +} +bool lcl_isCosZero( double fAngleRad ) +{ + return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 ); +} + +} + +void ThreeDHelper::convertElevationRotationDegToXYZAngleRad( + sal_Int32 nElevationDeg, sal_Int32 nRotationDeg, + double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad) +{ + // for a description of the algorithm see issue 72994 + //https://bz.apache.org/ooo/show_bug.cgi?id=72994 + //https://bz.apache.org/ooo/attachment.cgi?id=50608 + + nElevationDeg = NormAngle360(nElevationDeg); + nRotationDeg = NormAngle360(nRotationDeg); + + double& x = rfXAngleRad; + double& y = rfYAngleRad; + double& z = rfZAngleRad; + + double E = basegfx::deg2rad(nElevationDeg); //elevation in Rad + double R = basegfx::deg2rad(nRotationDeg); //rotation in Rad + + if( (nRotationDeg == 0 || nRotationDeg == 180 ) + && ( nElevationDeg == 90 || nElevationDeg == 270 ) ) + { + //sR==0 && cE==0 + z = 0.0; + //element 23 + double f23 = cos(R)*sin(E); + if(f23>0) + x = M_PI_2; + else + x = -M_PI_2; + y = R; + } + else if( ( nRotationDeg == 90 || nRotationDeg == 270 ) + && ( nElevationDeg == 90 || nElevationDeg == 270 ) ) + { + //cR==0 && cE==0 + z = M_PI_2; + if( sin(R)>0 ) + x = M_PI_2; + else + x = -M_PI_2; + + if( (sin(R)*sin(E))>0 ) + y = 0.0; + else + y = M_PI; + } + else if( (nRotationDeg == 0 || nRotationDeg == 180 ) + && ( nElevationDeg == 0 || nElevationDeg == 180 ) ) + { + //sR==0 && sE==0 + z = 0.0; + y = R; + x = E; + } + else if( ( nRotationDeg == 90 || nRotationDeg == 270 ) + && ( nElevationDeg == 0 || nElevationDeg == 180 ) ) + { + //cR==0 && sE==0 + z = 0.0; + + if( (sin(R)/cos(E))>0 ) + y = M_PI_2; + else + y = -M_PI_2; + + if( (cos(E))>0 ) + x = 0; + else + x = M_PI; + } + else if ( nElevationDeg == 0 || nElevationDeg == 180 ) + { + //sR!=0 cR!=0 sE==0 + z = 0.0; + x = E; + y = R; + //use element 13 for sign + if((cos(x)*sin(y)*sin(R))<0.0) + y *= -1.0; + } + else if ( nElevationDeg == 90 || nElevationDeg == 270 ) + { + //sR!=0 cR!=0 cE==0 + //element 12 + 22 --> y=0 or M_PI and x=+-M_PI/2 + //-->element 13/23: + z = atan(sin(R)/(cos(R)*sin(E))); + //use element 13 for sign for x + if( (sin(R)*sin(z))>0.0 ) + x = M_PI_2; + else + x = -M_PI_2; + //use element 21 for y + if( (sin(R)*sin(E)*sin(z))>0.0) + y = 0.0; + else + y = M_PI; + } + else if ( nRotationDeg == 0 || nRotationDeg == 180 ) + { + //sE!=0 cE!=0 sR==0 + z = 0.0; + x = E; + y = R; + double f23 = cos(R)*sin(E); + if( (f23 * sin(x)) < 0.0 ) + x *= -1.0; //todo ?? + } + else if (nRotationDeg == 90 || nRotationDeg == 270) + { + //sE!=0 cE!=0 cR==0 + //z = +- M_PI/2; + //x = +- M_PI/2; + z = M_PI_2; + x = M_PI_2; + double sR = sin(R); + if( sR<0.0 ) + x *= -1.0; //different signs for x and z + + //use element 21: + double cy = sR*sin(E)/sin(z); + lcl_ensureIntervalMinus1To1(cy); + y = acos(cy); + + //use element 22 for sign: + if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0) + y *= -1.0; + } + else + { + z = atan(tan(R) * sin(E)); + if(cos(z)==0.0) + { + OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad"); + return; + } + double cy = cos(R)/cos(z); + lcl_ensureIntervalMinus1To1(cy); + y = acos(cy); + + //element 12 in 23 + double fDenominator = cos(z)*(1.0-pow(sin(y),2)); + if(fDenominator==0.0) + { + OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad"); + return; + } + double sx = cos(R)*sin(E)/fDenominator; + lcl_ensureIntervalMinus1To1(sx); + x = asin( sx ); + + //use element 13 for sign: + double f13a = cos(x)*cos(z)*sin(y); + double f13b = sin(R)-sx*sin(z); + if( (f13b*f13a)<0.0 ) + { + //change x or y + //use element 22 for further investigations: + //try + y *= -1; + double f22a = cos(x)*cos(z); + double f22b = cos(E)-(sx*sin(y)*sin(z)); + if( (f22a*f22b)<0.0 ) + { + y *= -1; + x=(M_PI-x); + } + } + else + { + //change nothing or both + //use element 22 for further investigations: + double f22a = cos(x)*cos(z); + double f22b = cos(E)-(sx*sin(y)*sin(z)); + if( (f22a*f22b)<0.0 ) + { + y *= -1; + x=(M_PI-x); + } + } + } +} + +void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg( + sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg, + double fXRad, double fYRad, double fZRad) +{ + // for a description of the algorithm see issue 72994 + //https://bz.apache.org/ooo/show_bug.cgi?id=72994 + //https://bz.apache.org/ooo/attachment.cgi?id=50608 + + double R = 0.0; //Rotation in Rad + double E = 0.0; //Elevation in Rad + + double& x = fXRad; + double& y = fYRad; + double& z = fZRad; + + double f11 = cos(y)*cos(z); + + if( lcl_isSinZero(y) ) + { + //siny == 0 + + if( lcl_isCosZero(x) ) + { + //siny == 0 && cosx == 0 + + if( lcl_isSinZero(z) ) + { + //siny == 0 && cosx == 0 && sinz == 0 + //example: x=+-90 y=0oder180 z=0(oder180) + + //element 13+11 + if( f11 > 0 ) + R = 0.0; + else + R = M_PI; + + //element 23 + double f23 = cos(z)*sin(x) / cos(R); + if( f23 > 0 ) + E = M_PI_2; + else + E = -M_PI_2; + } + else if( lcl_isCosZero(z) ) + { + //siny == 0 && cosx == 0 && cosz == 0 + //example: x=+-90 y=0oder180 z=+-90 + + double f13 = sin(x)*sin(z); + //element 13+11 + if( f13 > 0 ) + R = M_PI_2; + else + R = -M_PI_2; + + //element 21 + double f21 = cos(y)*sin(z) / sin(R); + if( f21 > 0 ) + E = M_PI_2; + else + E = -M_PI_2; + } + else + { + //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0 + //element 11 && 13 + double f13 = sin(x)*sin(z); + R = atan( f13/f11 ); + + if(f11<0) + R+=M_PI; + + //element 23 + double f23 = cos(z)*sin(x); + if( f23/cos(R) > 0 ) + E = M_PI_2; + else + E = -M_PI_2; + } + } + else if( lcl_isSinZero(x) ) + { + //sinY==0 sinX==0 + //element 13+11 + if( f11 > 0 ) + R = 0.0; + else + R = M_PI; + + double f22 = cos(x)*cos(z); + if( f22 > 0 ) + E = 0.0; + else + E = M_PI; + } + else if( lcl_isSinZero(z) ) + { + //sinY==0 sinZ==0 sinx!=0 cosx!=0 + //element 13+11 + if( f11 > 0 ) + R = 0.0; + else + R = M_PI; + + //element 22 && 23 + double f22 = cos(x)*cos(z); + double f23 = cos(z)*sin(x); + E = atan( f23/(f22*cos(R)) ); + if( (f22*cos(E))<0 ) + E+=M_PI; + } + else if( lcl_isCosZero(z) ) + { + //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0 + double f13 = sin(x)*sin(z); + //element 13+11 + if( f13 > 0 ) + R = M_PI_2; + else + R = -M_PI_2; + + //element 21+22 + double f21 = cos(y)*sin(z); + if( f21/sin(R) > 0 ) + E = M_PI_2; + else + E = -M_PI_2; + } + else + { + //sinY == 0 && all other !=0 + double f13 = sin(x)*sin(z); + R = atan( f13/f11 ); + if( (f11*cos(R))<0.0 ) + R+=M_PI; + + double f22 = cos(x)*cos(z); + if( !lcl_isCosZero(R) ) + E = atan( cos(z)*sin(x) /( f22*cos(R) ) ); + else + E = atan( cos(y)*sin(z) /( f22*sin(R) ) ); + if( (f22*cos(E))<0 ) + E+=M_PI; + } + } + else if( lcl_isCosZero(y) ) + { + //cosY==0 + + double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y); + if( f13 >= 0 ) + R = M_PI_2; + else + R = -M_PI_2; + + double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z); + if( f22 >= 0 ) + E = 0.0; + else + E = M_PI; + } + else if( lcl_isSinZero(x) ) + { + //cosY!=0 sinY!=0 sinX=0 + if( lcl_isSinZero(z) ) + { + //cosY!=0 sinY!=0 sinX=0 sinZ=0 + double f13 = cos(x)*cos(z)*sin(y); + R = atan( f13/f11 ); + //R = asin(f13); + if( f11<0 ) + R+=M_PI; + + double f22 = cos(x)*cos(z); + if( f22>0 ) + E = 0.0; + else + E = M_PI; + } + else if( lcl_isCosZero(z) ) + { + //cosY!=0 sinY!=0 sinX=0 cosZ=0 + R = x; + E = y;//or -y + //use 23 for 'signs' + double f23 = -1.0*cos(x)*sin(y)*sin(z); + if( (f23*cos(R)*sin(E))<0.0 ) + { + //change R or E + E = -y; + } + } + else + { + //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0 + double f13 = cos(x)*cos(z)*sin(y); + R = atan( f13/f11 ); + + if( f11<0 ) + R+=M_PI; + + double f21 = cos(y)*sin(z); + double f22 = cos(x)*cos(z); + E = atan(f21/(f22*sin(R)) ); + + if( (f22*cos(E))<0.0 ) + E+=M_PI; + } + } + else if( lcl_isCosZero(x) ) + { + //cosY!=0 sinY!=0 cosX=0 + + if( lcl_isSinZero(z) ) + { + //cosY!=0 sinY!=0 cosX=0 sinZ=0 + R=0;//13 -> R=0 or M_PI + if( f11<0.0 ) + R=M_PI; + E=M_PI_2;//22 -> E=+-M_PI/2 + //use element 11 and 23 for sign + double f23 = cos(z)*sin(x); + if( (f11*f23*sin(E))<0.0 ) + E=-M_PI_2; + } + else if( lcl_isCosZero(z) ) + { + //cosY!=0 sinY!=0 cosX=0 cosZ=0 + //element 11 & 13: + if( (sin(x)*sin(z))>0.0 ) + R=M_PI_2; + else + R=-M_PI_2; + //element 22: + E=acos( sin(x)*sin(y)*sin(z)); + //use element 21 for sign: + if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 ) + E*=-1.0; + } + else + { + //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0 + //element 13/11 + R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) ); + //use 13 for 'sign' + if( (sin(x)*sin(z))<0.0 ) + R += M_PI; + //element 22 + E = acos(sin(x)*sin(y)*sin(z) ); + //use 21 for sign + if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 ) + E*=-1.0; + } + } + else if( lcl_isSinZero(z) ) + { + //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0 + //element 11 + R=y; + //use element 13 for sign + if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 ) + R*=-1.0; + //element 22 + E = acos( cos(x)*cos(z) ); + //use element 23 for sign + if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 ) + E*=-1.0; + } + else if( lcl_isCosZero(z) ) + { + //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0 + //element 21/23 + R=atan(-cos(y)/(cos(x)*sin(y))); + //use element 13 for 'sign' + if( (sin(x)*sin(z)*sin(R))<0.0 ) + R+=M_PI; + //element 21/22 + E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) ); + //use element 23 for 'sign' + if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 ) + E+=M_PI; + } + else + { + //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0 + //13/11: + double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y); + R = atan( f13/ f11 ); + if(f11<0.0) + R+=M_PI; + double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z); + double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x); + //23/22: + E = atan( -1.0*f23/(f22*cos(R)) ); + if(f22<0.0) + E+=M_PI; + } + + rnElevationDeg = basegfx::fround(basegfx::rad2deg(E)); + rnRotationDeg = basegfx::fround(basegfx::rad2deg(R)); +} + +double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit ) +{ + if( fAngle<-1*fPositivLimit ) + fAngle=-1*fPositivLimit; + else if( fAngle>fPositivLimit ) + fAngle=fPositivLimit; + return fAngle; +} + +void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad ) +{ + rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, basegfx::deg2rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) ); + rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, basegfx::deg2rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) ); +} + +void ThreeDHelper::getRotationAngleFromDiagram( + const Reference< beans::XPropertySet >& xSceneProperties, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad ) +{ + //takes the camera and the transformation matrix into account + + rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0; + + if( !xSceneProperties.is() ) + return; + + //get camera rotation + ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( xSceneProperties ) ); + BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix ); + + //get scene rotation + ::basegfx::B3DHomMatrix aSceneRotation; + { + drawing::HomogenMatrix aHomMatrix; + if( xSceneProperties->getPropertyValue( "D3DTransformMatrix") >>= aHomMatrix ) + { + aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix ); + BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); + } + } + + ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation; + ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) ); + + rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX()); + rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY()); + rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ()); + + if(rfZAngleRad<-M_PI_2 || rfZAngleRad>M_PI_2) + { + rfZAngleRad-=M_PI; + rfXAngleRad-=M_PI; + rfYAngleRad=(M_PI-rfYAngleRad); + + rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad); + rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad); + rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad); + } +} + +void ThreeDHelper::switchRightAngledAxes( const Reference< beans::XPropertySet >& xSceneProperties, bool bRightAngledAxes ) +{ + try + { + if( xSceneProperties.is() ) + { + bool bOldRightAngledAxes = false; + xSceneProperties->getPropertyValue( "RightAngledAxes") >>= bOldRightAngledAxes; + if( bOldRightAngledAxes!=bRightAngledAxes) + { + xSceneProperties->setPropertyValue( "RightAngledAxes", uno::Any( bRightAngledAxes )); + if(bRightAngledAxes) + { + ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( xSceneProperties ) ); + lcl_rotateLights( aInverseRotation, xSceneProperties ); + } + else + { + ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( xSceneProperties ) ); + lcl_rotateLights( aCompleteRotation, xSceneProperties ); + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ThreeDHelper::setRotationAngleToDiagram( + const rtl::Reference< Diagram >& xDiagram + , double fXAngleRad, double fYAngleRad, double fZAngleRad ) +{ + //the rotation of the camera is not touched but taken into account + //the rotation difference is applied to the transformation matrix + + //the light sources will be adapted also + + if( !xDiagram.is() ) + return; + + try + { + //remind old rotation for adaptation of light directions + ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( xDiagram ) ); + + ::basegfx::B3DHomMatrix aInverseCameraRotation; + { + ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix( + lcl_getCameraMatrix( xDiagram ) ) ); + aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() ); + aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 ); + aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 ); + } + + ::basegfx::B3DHomMatrix aCumulatedRotation; + aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + + //calculate new scene matrix + ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation; + BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); + + //set new rotation to transformation matrix + xDiagram->setPropertyValue( + "D3DTransformMatrix", uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); + + //rotate lights if RightAngledAxes are not set or not supported + bool bRightAngledAxes = false; + xDiagram->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes; + if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) + { + ::basegfx::B3DHomMatrix aNewRotation; + aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); + lcl_rotateLights( aNewRotation*aInverseOldRotation, xDiagram ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +void ThreeDHelper::getRotationFromDiagram( const rtl::Reference< Diagram >& xSceneProperties + , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree ) +{ + double fXAngle, fYAngle, fZAngle; + ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle ); + + if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) + { + ThreeDHelper::convertXYZAngleRadToElevationRotationDeg( + rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle); + rnVerticalAngleDegree*=-1; + } + else + { + rnHorizontalAngleDegree = basegfx::fround(basegfx::rad2deg(fXAngle)); + rnVerticalAngleDegree = basegfx::fround(-1.0 * basegfx::rad2deg(fYAngle)); + // nZRotation = basegfx::fround(-1.0 * basegfx::rad2deg(fZAngle)); + } + + rnHorizontalAngleDegree = NormAngle180(rnHorizontalAngleDegree); + rnVerticalAngleDegree = NormAngle180(rnVerticalAngleDegree); +} + +void ThreeDHelper::setRotationToDiagram( const rtl::Reference< Diagram >& xDiagram + , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree ) +{ + //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false + double fXAngle = basegfx::deg2rad(nHorizontalAngleDegree); + double fYAngle = basegfx::deg2rad(-1 * nVerticalYAngleDegree); + double fZAngle = 0.0; + + if( !lcl_isRightAngledAxesSetAndSupported( xDiagram ) ) + ThreeDHelper::convertElevationRotationDegToXYZAngleRad( + nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle ); + + ThreeDHelper::setRotationAngleToDiagram( xDiagram, fXAngle, fYAngle, fZAngle ); +} + +void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance ) +{ + rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value + rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value +} + +void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance ) +{ + double fMin, fMax; + getCameraDistanceRange( fMin, fMax ); + if( rfCameraDistance < fMin ) + rfCameraDistance = fMin; + if( rfCameraDistance > fMax ) + rfCameraDistance = fMax; +} + +double ThreeDHelper::getCameraDistance( + const Reference< beans::XPropertySet >& xSceneProperties ) +{ + double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; + + if( !xSceneProperties.is() ) + return fCameraDistance; + + try + { + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG; + ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); + fCameraDistance = aVRP.getLength(); + + ensureCameraDistanceRange( fCameraDistance ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return fCameraDistance; +} + +void ThreeDHelper::setCameraDistance( + const Reference< beans::XPropertySet >& xSceneProperties, double fCameraDistance ) +{ + if( !xSceneProperties.is() ) + return; + + try + { + if( fCameraDistance <= 0 ) + fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; + + drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); + xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG; + ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); + if( ::basegfx::fTools::equalZero( aVRP.getLength() ) ) + aVRP = ::basegfx::B3DVector(0,0,1); + aVRP.setLength(fCameraDistance); + aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP ); + + xSceneProperties->setPropertyValue( "D3DCameraGeometry", uno::Any( aCG )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance ) +{ + double fMin, fMax; + ThreeDHelper::getCameraDistanceRange( fMin, fMax ); + //fMax <-> 0; fMin <->100 + //a/x + b = y + double a = 100.0*fMax*fMin/(fMax-fMin); + double b = -a/fMax; + + double fRet = a/fCameraDistance + b; + + return fRet; +} + +double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective ) +{ + double fMin, fMax; + ThreeDHelper::getCameraDistanceRange( fMin, fMax ); + //fMax <-> 0; fMin <->100 + //a/x + b = y + double a = 100.0*fMax*fMin/(fMax-fMin); + double b = -a/fMax; + + double fRet = a/(fPerspective - b); + + return fRet; +} + +ThreeDLookScheme ThreeDHelper::detectScheme( const rtl::Reference< Diagram >& xDiagram ) +{ + ThreeDLookScheme aScheme = ThreeDLookScheme::ThreeDLookScheme_Unknown; + + sal_Int32 nRoundedEdges; + sal_Int32 nObjectLines; + ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines ); + + //get shade mode and light settings: + drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); + try + { + if( xDiagram.is() ) + xDiagram->getPropertyValue( "D3DSceneShadeMode" )>>= aShadeMode; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, xDiagram ) ) + { + if( lcl_isSimpleLightScheme(xDiagram) ) + aScheme = ThreeDLookScheme::ThreeDLookScheme_Simple; + } + else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) ) + { + if( lcl_isRealisticLightScheme(xDiagram) ) + aScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic; + } + + return aScheme; +} + +void ThreeDHelper::setScheme( const rtl::Reference< Diagram >& xDiagram, ThreeDLookScheme aScheme ) +{ + if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown ) + return; + + drawing::ShadeMode aShadeMode; + sal_Int32 nRoundedEdges; + sal_Int32 nObjectLines; + + if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Simple ) + lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,xDiagram); + else + lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines); + + try + { + ThreeDHelper::setRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines ); + + if( xDiagram.is() ) + { + drawing::ShadeMode aOldShadeMode; + if( ! ( (xDiagram->getPropertyValue( "D3DSceneShadeMode" )>>=aOldShadeMode) && + aOldShadeMode == aShadeMode )) + { + xDiagram->setPropertyValue( "D3DSceneShadeMode", uno::Any( aShadeMode )); + } + } + + lcl_setLightsForScheme( xDiagram, aScheme ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + +} + +void ThreeDHelper::set3DSettingsToDefault( const rtl::Reference< Diagram >& xDiagram ) +{ + if(xDiagram.is()) + { + xDiagram->setPropertyToDefault( "D3DSceneDistance"); + xDiagram->setPropertyToDefault( "D3DSceneFocalLength"); + } + ThreeDHelper::setDefaultRotation( xDiagram ); + ThreeDHelper::setDefaultIllumination( xDiagram ); +} + +void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties, bool bPieOrDonut ) +{ + if( !xSceneProperties.is() ) + return; + + drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) ); + xSceneProperties->setPropertyValue( "D3DCameraGeometry", uno::Any( aCameraGeo )); + + ::basegfx::B3DHomMatrix aSceneRotation; + if( bPieOrDonut ) + aSceneRotation.rotate( -M_PI/3.0, 0, 0 ); + xSceneProperties->setPropertyValue( "D3DTransformMatrix", + uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); +} + +void ThreeDHelper::setDefaultRotation( const rtl::Reference< Diagram >& xDiagram ) +{ + bool bPieOrDonut( DiagramHelper::isPieOrDonutChart( xDiagram ) ); + ThreeDHelper::setDefaultRotation( xDiagram, bPieOrDonut ); +} + +void ThreeDHelper::setDefaultIllumination( const rtl::Reference<::chart::Diagram>& xDiagram ) +{ + if( !xDiagram.is() ) + return; + + drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); + try + { + xDiagram->getPropertyValue( "D3DSceneShadeMode" )>>= aShadeMode; + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7, uno::Any( false ) ); + xDiagram->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8, uno::Any( false ) ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + ThreeDLookScheme aScheme = (aShadeMode == drawing::ShadeMode_FLAT) + ? ThreeDLookScheme::ThreeDLookScheme_Simple + : ThreeDLookScheme::ThreeDLookScheme_Realistic; + lcl_setLightsForScheme( xDiagram, aScheme ); +} + +void ThreeDHelper::getRoundedEdgesAndObjectLines( + const rtl::Reference< Diagram > & xDiagram + , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines ) +{ + rnRoundedEdges = -1; + rnObjectLines = -1; + try + { + bool bDifferentRoundedEdges = false; + bool bDifferentObjectLines = false; + + drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID ); + + std::vector< rtl::Reference< DataSeries > > aSeriesList = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 nSeriesCount = static_cast( aSeriesList.size() ); + + OUString aPercentDiagonalPropertyName( "PercentDiagonal" ); + OUString aBorderStylePropertyName( "BorderStyle" ); + + for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS ) + { + rtl::Reference< DataSeries > xSeries( aSeriesList[nS] ); + if(!nS) + { + rnRoundedEdges = 0; + try + { + sal_Int16 nPercentDiagonal = 0; + + xSeries->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal; + rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal ); + + if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries + , aPercentDiagonalPropertyName, uno::Any(nPercentDiagonal) ) ) + bDifferentRoundedEdges = true; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + bDifferentRoundedEdges = true; + } + try + { + xSeries->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle; + + if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries + , aBorderStylePropertyName, uno::Any(aLineStyle) ) ) + bDifferentObjectLines = true; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + bDifferentObjectLines = true; + } + } + else + { + if( !bDifferentRoundedEdges ) + { + sal_Int16 nPercentDiagonal = 0; + xSeries->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal; + sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal ); + if(nCurrentRoundedEdges!=rnRoundedEdges + || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries + , aPercentDiagonalPropertyName, uno::Any( static_cast< sal_Int16 >(rnRoundedEdges) ) ) ) + { + bDifferentRoundedEdges = true; + } + } + + if( !bDifferentObjectLines ) + { + drawing::LineStyle aCurrentLineStyle; + xSeries->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle; + if(aCurrentLineStyle!=aLineStyle + || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries + , aBorderStylePropertyName, uno::Any(aLineStyle) ) ) + bDifferentObjectLines = true; + } + } + if( bDifferentRoundedEdges && bDifferentObjectLines ) + break; + } + + //set rnObjectLines + rnObjectLines = 0; + if( bDifferentObjectLines ) + rnObjectLines = -1; + else if( aLineStyle == drawing::LineStyle_SOLID ) + rnObjectLines = 1; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ThreeDHelper::setRoundedEdgesAndObjectLines( + const rtl::Reference< Diagram > & xDiagram + , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines ) +{ + if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 ) + return; + + drawing::LineStyle aLineStyle( drawing::LineStyle_NONE ); + if(nObjectLines==1) + aLineStyle = drawing::LineStyle_SOLID; + + uno::Any aALineStyle( aLineStyle); + uno::Any aARoundedEdges( static_cast< sal_Int16 >( nRoundedEdges )); + + std::vector< rtl::Reference< DataSeries > > aSeriesList = + DiagramHelper::getDataSeriesFromDiagram( xDiagram ); + sal_Int32 nSeriesCount = static_cast( aSeriesList.size() ); + for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS ) + { + rtl::Reference< DataSeries > xSeries( aSeriesList[nS] ); + + if( nRoundedEdges>=0 && nRoundedEdges<=100 ) + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "PercentDiagonal", aARoundedEdges ); + + if( nObjectLines==0 || nObjectLines==1 ) + DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", aALineStyle ); + } +} + +CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const rtl::Reference< ::chart::Diagram >& xDiagram ) +{ + CuboidPlanePosition eRet(CuboidPlanePosition_Left); + + double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; + ThreeDHelper::getRotationAngleFromDiagram( xDiagram, fXAngleRad, fYAngleRad, fZAngleRad ); + if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) ) + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); + } + if( sin(fYAngleRad)>0.0 ) + eRet = CuboidPlanePosition_Right; + return eRet; +} + +CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const rtl::Reference< Diagram >& xDiagram ) +{ + CuboidPlanePosition eRet(CuboidPlanePosition_Back); + + double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; + ThreeDHelper::getRotationAngleFromDiagram( xDiagram, fXAngleRad, fYAngleRad, fZAngleRad ); + if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) ) + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); + } + if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 ) + eRet = CuboidPlanePosition_Front; + return eRet; +} + +CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const rtl::Reference< Diagram >& xDiagram ) +{ + CuboidPlanePosition eRet(CuboidPlanePosition_Bottom); + + double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; + ThreeDHelper::getRotationAngleFromDiagram( xDiagram, fXAngleRad, fYAngleRad, fZAngleRad ); + if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) ) + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); + } + if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 ) + eRet = CuboidPlanePosition_Top; + return eRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/TitleHelper.cxx b/chart2/source/tools/TitleHelper.cxx new file mode 100644 index 000000000..943adace7 --- /dev/null +++ b/chart2/source/tools/TitleHelper.cxx @@ -0,0 +1,420 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace { + +uno::Reference< XTitled > lcl_getTitleParentFromDiagram( + TitleHelper::eTitleType nTitleIndex + , const rtl::Reference< Diagram >& xDiagram ) +{ + uno::Reference< XTitled > xResult; + + if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION || + nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) + { + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + + if( nTitleIndex == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) + nTitleIndex = bIsVertical ? TitleHelper::X_AXIS_TITLE : TitleHelper::Y_AXIS_TITLE; + else + nTitleIndex = bIsVertical ? TitleHelper::Y_AXIS_TITLE : TitleHelper::X_AXIS_TITLE; + } + + switch( nTitleIndex ) + { + case TitleHelper::SUB_TITLE: + if( xDiagram.is()) + xResult = xDiagram; + break; + case TitleHelper::X_AXIS_TITLE: + if( xDiagram.is()) + xResult = AxisHelper::getAxis( 0, true, xDiagram ); + break; + case TitleHelper::Y_AXIS_TITLE: + if( xDiagram.is()) + xResult = AxisHelper::getAxis( 1, true, xDiagram ); + break; + case TitleHelper::Z_AXIS_TITLE: + if( xDiagram.is()) + xResult = AxisHelper::getAxis( 2, true, xDiagram ); + break; + case TitleHelper::SECONDARY_X_AXIS_TITLE: + if( xDiagram.is()) + xResult = AxisHelper::getAxis( 0, false, xDiagram ); + break; + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + if( xDiagram.is()) + xResult = AxisHelper::getAxis( 1, false, xDiagram ); + break; + + case TitleHelper::MAIN_TITLE: + default: + OSL_FAIL( "Unsupported Title-Type requested" ); + break; + } + + return xResult; +} + +uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex + , const rtl::Reference< Diagram >& xDiagram ) +{ + uno::Reference< XTitled > xResult; + switch( nTitleIndex ) + { + case TitleHelper::MAIN_TITLE: + SAL_WARN("chart2", "should not be reached"); + break; + case TitleHelper::SUB_TITLE: + case TitleHelper::X_AXIS_TITLE: + case TitleHelper::Y_AXIS_TITLE: + case TitleHelper::Z_AXIS_TITLE: + case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION: + case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION: + case TitleHelper::SECONDARY_X_AXIS_TITLE: + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + xResult.set( lcl_getTitleParentFromDiagram( nTitleIndex, xDiagram )); + break; + default: + OSL_FAIL( "Unsupported Title-Type requested" ); + break; + } + + return xResult; +} + +uno::Reference< XTitled > lcl_getTitleParent( TitleHelper::eTitleType nTitleIndex + , const rtl::Reference<::chart::ChartModel>& xModel ) +{ + if(nTitleIndex == TitleHelper::MAIN_TITLE) + { + return xModel; + } + + rtl::Reference< Diagram > xDiagram; + + if( xModel.is()) + xDiagram = xModel->getFirstChartDiagram(); + + return lcl_getTitleParent( nTitleIndex, xDiagram ); +} + +} + +uno::Reference< XTitle > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex + , ChartModel& rModel ) +{ + if(nTitleIndex == TitleHelper::MAIN_TITLE) + return rModel.getTitleObject(); + + rtl::Reference< Diagram > xDiagram = rModel.getFirstChartDiagram(); + uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xDiagram ) ); + if( xTitled.is()) + return xTitled->getTitleObject(); + return nullptr; +} + +uno::Reference< XTitle > TitleHelper::getTitle( TitleHelper::eTitleType nTitleIndex + , const rtl::Reference& xModel ) +{ + uno::Reference< XTitled > xTitled; + if(nTitleIndex == TitleHelper::MAIN_TITLE) + { + xTitled = xModel; + } + else + { + rtl::Reference< Diagram > xDiagram; + if( xModel.is()) + xDiagram = xModel->getFirstChartDiagram(); + xTitled = lcl_getTitleParent( nTitleIndex, xDiagram ); + } + if( xTitled.is()) + return xTitled->getTitleObject(); + return nullptr; +} + +uno::Reference< XTitle > TitleHelper::createOrShowTitle( + TitleHelper::eTitleType eTitleType + , const OUString& rTitleText + , const rtl::Reference& xModel + , const uno::Reference< uno::XComponentContext > & xContext ) +{ + uno::Reference< chart2::XTitle > xTitled( TitleHelper::getTitle( eTitleType, xModel ) ); + if( xTitled.is()) + { + css::uno::Reference xProps(xTitled, css::uno::UNO_QUERY_THROW); + xProps->setPropertyValue("Visible",css::uno::Any(true)); + return xTitled; + } + else + { + return createTitle(eTitleType, rTitleText, xModel, xContext, nullptr/*pRefSizeProvider*/); + } +} + +uno::Reference< XTitle > TitleHelper::createTitle( + TitleHelper::eTitleType eTitleType + , const OUString& rTitleText + , const rtl::Reference& xModel + , const uno::Reference< uno::XComponentContext > & xContext + , ReferenceSizeProvider * pRefSizeProvider ) +{ + rtl::Reference< ::chart::Title > xTitle; + uno::Reference< XTitled > xTitled( lcl_getTitleParent( eTitleType, xModel ) ); + + if( !xTitled.is() ) + { + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xModel ) ); + rtl::Reference< Axis > xAxis; + switch( eTitleType ) + { + case TitleHelper::SECONDARY_X_AXIS_TITLE: + xAxis = AxisHelper::createAxis( 0, false, xDiagram, xContext ); + break; + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + xAxis = AxisHelper::createAxis( 1, false, xDiagram, xContext ); + break; + default: + break; + } + if( xAxis.is() ) + { + xAxis->setPropertyValue( "Show", uno::Any( false ) ); + xTitled = lcl_getTitleParent( eTitleType, xModel ); + } + } + + if(xTitled.is()) + { + rtl::Reference< Diagram > xDiagram( ChartModelHelper::findDiagram( xModel ) ); + + xTitle = new ::chart::Title(); + + // default char height (main: 13.0 == default) + float fDefaultCharHeightSub = 11.0; + float fDefaultCharHeightAxis = 9.0; + switch( eTitleType ) + { + case TitleHelper::SUB_TITLE: + TitleHelper::setCompleteString( + rTitleText, xTitle, xContext, & fDefaultCharHeightSub ); + break; + case TitleHelper::X_AXIS_TITLE: + case TitleHelper::Y_AXIS_TITLE: + case TitleHelper::Z_AXIS_TITLE: + case TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION: + case TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION: + case TitleHelper::SECONDARY_X_AXIS_TITLE: + case TitleHelper::SECONDARY_Y_AXIS_TITLE: + TitleHelper::setCompleteString( + rTitleText, xTitle, xContext, & fDefaultCharHeightAxis ); + break; + default: + TitleHelper::setCompleteString( rTitleText, xTitle, xContext ); + break; + } + + // set/clear autoscale + if( pRefSizeProvider ) + pRefSizeProvider->setValuesAtTitle( xTitle ); + + xTitled->setTitleObject( xTitle ); + + //default rotation 90 degree for y axis title in normal coordinatesystems or for x axis title for swapped coordinatesystems + if( eTitleType == TitleHelper::X_AXIS_TITLE || + eTitleType == TitleHelper::Y_AXIS_TITLE || + eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE || + eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE ) + + { + try + { + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + + if( (!bIsVertical && eTitleType == TitleHelper::Y_AXIS_TITLE) + || (bIsVertical && eTitleType == TitleHelper::X_AXIS_TITLE) + || (!bIsVertical && eTitleType == TitleHelper::SECONDARY_Y_AXIS_TITLE) + || (bIsVertical && eTitleType == TitleHelper::SECONDARY_X_AXIS_TITLE) ) + { + xTitle->setPropertyValue( "TextRotation", uno::Any( 90.0 )); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + return xTitle; + +} + +OUString TitleHelper::getCompleteString( const uno::Reference< XTitle >& xTitle ) +{ + if(!xTitle.is()) + return OUString(); + OUStringBuffer aRet; + const uno::Sequence< uno::Reference< XFormattedString > > aStringList = xTitle->getText(); + for( uno::Reference< XFormattedString > const & formattedStr : aStringList ) + aRet.append( formattedStr->getString() ); + return aRet.makeStringAndClear(); +} + +void TitleHelper::setCompleteString( const OUString& rNewText + , const uno::Reference< XTitle >& xTitle + , const uno::Reference< uno::XComponentContext > & xContext + , const float * pDefaultCharHeight /* = 0 */ ) +{ + //the format of the first old text portion will be maintained if there is any + if(!xTitle.is()) + return; + + OUString aNewText = rNewText; + + bool bStacked = false; + uno::Reference< beans::XPropertySet > xTitleProperties( xTitle, uno::UNO_QUERY ); + if( xTitleProperties.is() ) + xTitleProperties->getPropertyValue( "StackCharacters" ) >>= bStacked; + + if( bStacked ) + { + //#i99841# remove linebreaks that were added for vertical stacking + OUStringBuffer aUnstackedStr; + OUStringBuffer aSource(rNewText); + + bool bBreakIgnored = false; + sal_Int32 nLen = rNewText.getLength(); + for( sal_Int32 nPos = 0; nPos < nLen; ++nPos ) + { + sal_Unicode aChar = aSource[nPos]; + if( aChar != '\n' ) + { + aUnstackedStr.append( aChar ); + bBreakIgnored = false; + } + else if( aChar == '\n' && bBreakIgnored ) + aUnstackedStr.append( aChar ); + else + bBreakIgnored = true; + } + aNewText = aUnstackedStr.makeStringAndClear(); + } + + uno::Sequence< uno::Reference< XFormattedString > > aNewStringList; + + uno::Sequence< uno::Reference< XFormattedString > > aOldStringList = xTitle->getText(); + if( aOldStringList.hasElements() ) + { + aNewStringList = { aOldStringList[0] }; + aNewStringList[0]->setString( aNewText ); + } + else + { + uno::Reference< chart2::XFormattedString2 > xFormattedString = + chart2::FormattedString::create( xContext ); + + xFormattedString->setString( aNewText ); + aNewStringList = { xFormattedString }; + if( pDefaultCharHeight != nullptr ) + { + try + { + uno::Any aFontSize( *pDefaultCharHeight ); + xFormattedString->setPropertyValue( "CharHeight", aFontSize ); + xFormattedString->setPropertyValue( "CharHeightAsian", aFontSize ); + xFormattedString->setPropertyValue( "CharHeightComplex", aFontSize ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + } + xTitle->setText( aNewStringList ); +} + +void TitleHelper::removeTitle( TitleHelper::eTitleType nTitleIndex + , const rtl::Reference& xModel ) +{ + uno::Reference< XTitled > xTitled( lcl_getTitleParent( nTitleIndex, xModel ) ); + if( xTitled.is()) + { + xTitled->setTitleObject(nullptr); + } +} + +bool TitleHelper::getTitleType( eTitleType& rType + , const css::uno::Reference< css::chart2::XTitle >& xTitle + , const rtl::Reference& xModel ) +{ + if( !xTitle.is() || !xModel.is() ) + return false; + + Reference< chart2::XTitle > xCurrentTitle; + for( sal_Int32 nTitleType = TITLE_BEGIN; nTitleType < NORMAL_TITLE_END; nTitleType++ ) + { + xCurrentTitle = TitleHelper::getTitle( static_cast(nTitleType), xModel ); + if( xCurrentTitle == xTitle ) + { + rType = static_cast(nTitleType); + return true; + } + } + + return false; +} + +void TitleHelper::hideTitle( TitleHelper::eTitleType nTitleIndex + , const rtl::Reference& xModel) +{ + uno::Reference< chart2::XTitle > xTitled( TitleHelper::getTitle( nTitleIndex, xModel ) ); + if( xTitled.is()) + { + css::uno::Reference xProps(xTitled, css::uno::UNO_QUERY_THROW); + xProps->setPropertyValue("Visible",css::uno::Any(false)); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/UncachedDataSequence.cxx b/chart2/source/tools/UncachedDataSequence.cxx new file mode 100644 index 000000000..b07fc11ad --- /dev/null +++ b/chart2/source/tools/UncachedDataSequence.cxx @@ -0,0 +1,316 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::osl::MutexGuard; + +// necessary for MS compiler +using ::comphelper::OPropertyContainer; +using ::chart::impl::UncachedDataSequence_Base; + +namespace +{ +constexpr OUStringLiteral lcl_aServiceName = u"com.sun.star.comp.chart.UncachedDataSequence"; + +enum +{ + PROP_NUMBERFORMAT_KEY, + PROP_PROPOSED_ROLE, + PROP_XML_RANGE +}; +} // anonymous namespace + +namespace chart +{ + +UncachedDataSequence::UncachedDataSequence( + const rtl::Reference< InternalDataProvider > & xIntDataProv, + const OUString & rRangeRepresentation ) + : OPropertyContainer( GetBroadcastHelper()), + UncachedDataSequence_Base( GetMutex()), + m_nNumberFormatKey(0), + m_xDataProvider( xIntDataProv ), + m_aSourceRepresentation( rRangeRepresentation ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); +} + +UncachedDataSequence::UncachedDataSequence( + const rtl::Reference< InternalDataProvider > & xIntDataProv, + const OUString & rRangeRepresentation, + const OUString & rRole ) + : OPropertyContainer( GetBroadcastHelper()), + UncachedDataSequence_Base( GetMutex()), + m_nNumberFormatKey(0), + m_xDataProvider( xIntDataProv ), + m_aSourceRepresentation( rRangeRepresentation ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); + setFastPropertyValue_NoBroadcast( PROP_PROPOSED_ROLE, uno::Any( rRole )); +} + +UncachedDataSequence::UncachedDataSequence( const UncachedDataSequence & rSource ) + : OPropertyContainer( GetBroadcastHelper()), + UncachedDataSequence_Base( GetMutex()), + m_nNumberFormatKey( rSource.m_nNumberFormatKey ), + m_sRole( rSource.m_sRole ), + m_xDataProvider( rSource.m_xDataProvider ), + m_aSourceRepresentation( rSource.m_aSourceRepresentation ), + m_xModifyEventForwarder( new ModifyEventForwarder() ) +{ + registerProperties(); +} + +UncachedDataSequence::~UncachedDataSequence() +{} + +void UncachedDataSequence::registerProperties() +{ + registerProperty( "NumberFormatKey", + PROP_NUMBERFORMAT_KEY, + 0, // PropertyAttributes + & m_nNumberFormatKey, + cppu::UnoType::get() ); + + registerProperty( "Role", + PROP_PROPOSED_ROLE, + 0, // PropertyAttributes + & m_sRole, + cppu::UnoType::get() ); + + registerProperty( "CachedXMLRange", + PROP_XML_RANGE, + 0, // PropertyAttributes + & m_aXMLRange, + cppu::UnoType::get() ); +} + +IMPLEMENT_FORWARD_XINTERFACE2( UncachedDataSequence, UncachedDataSequence_Base, OPropertyContainer ) +IMPLEMENT_FORWARD_XTYPEPROVIDER2( UncachedDataSequence, UncachedDataSequence_Base, OPropertyContainer ) + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL UncachedDataSequence::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ); +} + +// ____ ::comphelper::OPropertySetHelper ____ +::cppu::IPropertyArrayHelper& UncachedDataSequence::getInfoHelper() +{ + return *getArrayHelper(); +} + +// ____ ::comphelper::OPropertyArrayHelper ____ +::cppu::IPropertyArrayHelper* UncachedDataSequence::createArrayHelper() const +{ + Sequence< beans::Property > aProps; + // describes all properties which have been registered in the ctor + describeProperties( aProps ); + + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +OUString SAL_CALL UncachedDataSequence::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL UncachedDataSequence::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL UncachedDataSequence::getSupportedServiceNames() +{ + return { + lcl_aServiceName, + "com.sun.star.chart2.data.DataSequence", + "com.sun.star.chart2.data.NumericalDataSequence", + "com.sun.star.chart2.data.TextualDataSequence" + }; +} + +// ________ XNumericalDataSequence ________ +Sequence< double > SAL_CALL UncachedDataSequence::getNumericalData() +{ + Sequence< double > aResult; + MutexGuard aGuard( GetMutex() ); + if( m_xDataProvider.is()) + { + const Sequence< uno::Any > aValues( m_xDataProvider->getDataByRangeRepresentation( m_aSourceRepresentation )); + aResult.realloc( aValues.getLength()); + std::transform( aValues.begin(), aValues.end(), + aResult.getArray(), CommonFunctors::AnyToDouble()); + } + return aResult; +} + +// ________ XTextualDataSequence ________ +Sequence< OUString > SAL_CALL UncachedDataSequence::getTextualData() +{ + Sequence< OUString > aResult; + MutexGuard aGuard( GetMutex() ); + if( m_xDataProvider.is()) + { + const Sequence< uno::Any > aValues( m_xDataProvider->getDataByRangeRepresentation( m_aSourceRepresentation )); + aResult.realloc( aValues.getLength()); + std::transform( aValues.begin(), aValues.end(), + aResult.getArray(), CommonFunctors::AnyToString()); + } + return aResult; +} + +// ________ XDataSequence ________ +Sequence< Any > SAL_CALL UncachedDataSequence::getData() +{ + MutexGuard aGuard( GetMutex() ); + if( m_xDataProvider.is()) + return m_xDataProvider->getDataByRangeRepresentation( m_aSourceRepresentation ); + return Sequence< Any >(); +} + +OUString SAL_CALL UncachedDataSequence::getSourceRangeRepresentation() +{ + return getName(); +} + +Sequence< OUString > SAL_CALL UncachedDataSequence::generateLabel( chart2::data::LabelOrigin ) +{ + // auto-generated label + sal_Int32 nSeries = m_aSourceRepresentation.toInt32() + 1; + OUString aResString(::chart::SchResId(STR_DATA_UNNAMED_SERIES_WITH_INDEX)); + static const OUStringLiteral aReplacementStr(u"%NUMBER"); + sal_Int32 nIndex = aResString.indexOf(aReplacementStr); + OUString aName; + if( nIndex != -1 ) + aName = aResString.replaceAt(nIndex, aReplacementStr.getLength(), OUString::number(nSeries)); + return Sequence< OUString >( &aName, 1 ); +} + +::sal_Int32 SAL_CALL UncachedDataSequence::getNumberFormatKeyByIndex( ::sal_Int32 ) +{ + return m_nNumberFormatKey; +} + +// ____ XIndexReplace ____ +void SAL_CALL UncachedDataSequence::replaceByIndex( ::sal_Int32 Index, const uno::Any& Element ) +{ + MutexGuard aGuard( GetMutex() ); + Sequence< Any > aData( getData()); + if( Index < aData.getLength() && + m_xDataProvider.is() ) + { + aData.getArray()[Index] = Element; + m_xDataProvider->setDataByRangeRepresentation( m_aSourceRepresentation, aData ); + fireModifyEvent(); + } +} + +// ____ XIndexAccess (base of XIndexReplace) ____ +::sal_Int32 SAL_CALL UncachedDataSequence::getCount() +{ + OSL_FAIL( "Implement!" ); + return 0; +} + +uno::Any SAL_CALL UncachedDataSequence::getByIndex( ::sal_Int32 ) +{ + OSL_FAIL( "Implement!" ); + return uno::Any(); +} + +// ____ XElementAccess (base of XIndexAccess) ____ +uno::Type SAL_CALL UncachedDataSequence::getElementType() +{ + return cppu::UnoType::get(); +} + +sal_Bool SAL_CALL UncachedDataSequence::hasElements() +{ + if( ! m_xDataProvider.is()) + return false; + return m_xDataProvider->hasDataByRangeRepresentation( m_aSourceRepresentation ); +} + +// ____ XNamed ____ +OUString SAL_CALL UncachedDataSequence::getName() +{ + return m_aSourceRepresentation; +} + +void SAL_CALL UncachedDataSequence::setName( const OUString& aName ) +{ + m_aSourceRepresentation = aName; + fireModifyEvent(); +} + +Reference< util::XCloneable > SAL_CALL UncachedDataSequence::createClone() +{ + return new UncachedDataSequence( *this ); +} + +// ____ XModifiable ____ +sal_Bool SAL_CALL UncachedDataSequence::isModified() +{ + return false; +} + +void SAL_CALL UncachedDataSequence::setModified( sal_Bool bModified ) +{ + if( bModified ) + fireModifyEvent(); +} + +// ____ XModifyBroadcaster (base of XModifiable) ____ +void SAL_CALL UncachedDataSequence::addModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->addModifyListener( aListener ); +} + +void SAL_CALL UncachedDataSequence::removeModifyListener( const Reference< util::XModifyListener >& aListener ) +{ + m_xModifyEventForwarder->removeModifyListener( aListener ); +} + +void UncachedDataSequence::fireModifyEvent() +{ + // @todo: currently never called, as data changes are not yet reported by + // the data provider + m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this ))); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/UserDefinedProperties.cxx b/chart2/source/tools/UserDefinedProperties.cxx new file mode 100644 index 000000000..f610ae0f7 --- /dev/null +++ b/chart2/source/tools/UserDefinedProperties.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::beans::Property; + +namespace chart +{ + +void UserDefinedProperties::AddPropertiesToVector( + std::vector< Property > & rOutProperties ) +{ + rOutProperties.emplace_back( "ChartUserDefinedAttributes", + PROP_XML_USERDEF_CHART, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "TextUserDefinedAttributes", + PROP_XML_USERDEF_TEXT, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + rOutProperties.emplace_back( "ParaUserDefinedAttributes", + PROP_XML_USERDEF_PARA, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); + // UserDefinedAttributesSupplier + rOutProperties.emplace_back( "UserDefinedAttributes", + PROP_XML_USERDEF, + cppu::UnoType::get(), + beans::PropertyAttribute::BOUND + | beans::PropertyAttribute::MAYBEVOID ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WeakListenerAdapter.cxx b/chart2/source/tools/WeakListenerAdapter.cxx new file mode 100644 index 000000000..16b3d8150 --- /dev/null +++ b/chart2/source/tools/WeakListenerAdapter.cxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +WeakSelectionChangeListenerAdapter::WeakSelectionChangeListenerAdapter( + const Reference< view::XSelectionChangeListener > & xListener ) : + WeakListenerAdapter< css::view::XSelectionChangeListener >( xListener ) +{} + +WeakSelectionChangeListenerAdapter::~WeakSelectionChangeListenerAdapter() +{} + +void SAL_CALL WeakSelectionChangeListenerAdapter::selectionChanged( const lang::EventObject& aEvent ) +{ + Reference< view::XSelectionChangeListener > xSelChgListener( getListener() ); + if( xSelChgListener.is()) + xSelChgListener->selectionChanged( aEvent ); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WrappedDefaultProperty.cxx b/chart2/source/tools/WrappedDefaultProperty.cxx new file mode 100644 index 000000000..74d2b4b0a --- /dev/null +++ b/chart2/source/tools/WrappedDefaultProperty.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +WrappedDefaultProperty::WrappedDefaultProperty( + const OUString& rOuterName, const OUString& rInnerName, + const uno::Any& rNewOuterDefault ) : + WrappedProperty( rOuterName, rInnerName ), + m_aOuterDefaultValue( rNewOuterDefault ) +{} + +WrappedDefaultProperty::~WrappedDefaultProperty() +{} + +void WrappedDefaultProperty::setPropertyToDefault( + const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + Reference< beans::XPropertySet > xInnerPropSet( xInnerPropertyState, uno::UNO_QUERY ); + if( xInnerPropSet.is()) + setPropertyValue( m_aOuterDefaultValue, xInnerPropSet ); +} + +uno::Any WrappedDefaultProperty::getPropertyDefault( + const Reference< beans::XPropertyState >& /* xInnerPropertyState */ ) const +{ + return m_aOuterDefaultValue; +} + +beans::PropertyState WrappedDefaultProperty::getPropertyState( + const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + beans::PropertyState aState = beans::PropertyState_DIRECT_VALUE; + try + { + Reference< beans::XPropertySet > xInnerProp( xInnerPropertyState, uno::UNO_QUERY_THROW ); + uno::Any aValue = getPropertyValue( xInnerProp ); + if( m_aOuterDefaultValue == convertInnerToOuterValue( aValue )) + aState = beans::PropertyState_DEFAULT_VALUE; + } + catch( const beans::UnknownPropertyException& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return aState; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WrappedDirectStateProperty.cxx b/chart2/source/tools/WrappedDirectStateProperty.cxx new file mode 100644 index 000000000..ff74fac8c --- /dev/null +++ b/chart2/source/tools/WrappedDirectStateProperty.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +WrappedDirectStateProperty::WrappedDirectStateProperty( + const OUString& rOuterName, const OUString& rInnerName ) : + WrappedProperty( rOuterName, rInnerName ) +{} + +WrappedDirectStateProperty::~WrappedDirectStateProperty() +{} + +beans::PropertyState WrappedDirectStateProperty::getPropertyState( + const Reference< beans::XPropertyState >& /* xInnerPropertyState */ ) const +{ + return beans::PropertyState_DIRECT_VALUE; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WrappedIgnoreProperty.cxx b/chart2/source/tools/WrappedIgnoreProperty.cxx new file mode 100644 index 000000000..4e62dca5b --- /dev/null +++ b/chart2/source/tools/WrappedIgnoreProperty.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +WrappedIgnoreProperty::WrappedIgnoreProperty( const OUString& rOuterName, const Any& rDefaultValue ) + : WrappedProperty( rOuterName, OUString() ) + , m_aDefaultValue( rDefaultValue ) + , m_aCurrentValue( rDefaultValue ) +{ +} +WrappedIgnoreProperty::~WrappedIgnoreProperty() +{ +} + +void WrappedIgnoreProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + m_aCurrentValue = rOuterValue; +} + +Any WrappedIgnoreProperty::getPropertyValue( const Reference< beans::XPropertySet >& /* xInnerPropertySet */ ) const +{ + return m_aCurrentValue; +} + +void WrappedIgnoreProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& /* xInnerPropertyState */ ) const +{ + m_aCurrentValue = m_aDefaultValue; +} + +Any WrappedIgnoreProperty::getPropertyDefault( const Reference< beans::XPropertyState >& /* xInnerPropertyState */ ) const +{ + return m_aDefaultValue; +} + +beans::PropertyState WrappedIgnoreProperty::getPropertyState( const Reference< beans::XPropertyState >& /* xInnerPropertyState */ ) const +{ + return ( m_aCurrentValue == m_aDefaultValue + ? beans::PropertyState_DEFAULT_VALUE + : beans::PropertyState_DIRECT_VALUE ); +} + +void WrappedIgnoreProperties::addIgnoreLineProperties( std::vector< std::unique_ptr >& rList ) +{ + rList.emplace_back( new WrappedIgnoreProperty( "LineStyle", uno::Any( drawing::LineStyle_SOLID ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "LineDashName", uno::Any( OUString() ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "LineColor", uno::Any( sal_Int32(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "LineTransparence", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "LineWidth", uno::Any( sal_Int32(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "LineJoint", uno::Any( drawing::LineJoint_ROUND ) ) ); +} + +void WrappedIgnoreProperties::addIgnoreFillProperties( std::vector< std::unique_ptr >& rList ) +{ + addIgnoreFillProperties_without_BitmapProperties( rList ); + addIgnoreFillProperties_only_BitmapProperties( rList ); +} + +void WrappedIgnoreProperties::addIgnoreFillProperties_without_BitmapProperties( std::vector< std::unique_ptr >& rList ) +{ + rList.emplace_back( new WrappedIgnoreProperty( "FillStyle", uno::Any( drawing::FillStyle_SOLID ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillColor", uno::Any( sal_Int32(-1) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillTransparence", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillTransparenceGradientName", uno::Any( OUString() ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillGradientName", uno::Any( OUString() ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillHatchName", uno::Any( OUString() ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBackground", uno::Any( false ) ) ); +} + +void WrappedIgnoreProperties::addIgnoreFillProperties_only_BitmapProperties( std::vector< std::unique_ptr >& rList ) +{ + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapOffsetX", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapOffsetY", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapPositionOffsetX", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapPositionOffsetY", uno::Any( sal_Int16(0) ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapRectanglePoint", uno::Any( drawing::RectanglePoint_LEFT_TOP ) ) ); + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapLogicalSize", uno::Any( false ) ) );//todo correct default? + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapSizeX", uno::Any( sal_Int32(10) ) ) );//todo which default? + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapSizeY", uno::Any( sal_Int32(10) ) ) );//todo which default? + rList.emplace_back( new WrappedIgnoreProperty( "FillBitmapMode", uno::Any( drawing::BitmapMode_REPEAT ) ) ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WrappedProperty.cxx b/chart2/source/tools/WrappedProperty.cxx new file mode 100644 index 000000000..ee28aba86 --- /dev/null +++ b/chart2/source/tools/WrappedProperty.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +WrappedProperty::WrappedProperty( const OUString& rOuterName, const OUString& rInnerName) + : m_aOuterName( rOuterName ) + , m_aInnerName( rInnerName ) +{ +} +WrappedProperty::~WrappedProperty() +{ +} + +OUString WrappedProperty::getInnerName() const +{ + return m_aInnerName; +} + +Any WrappedProperty::convertInnerToOuterValue( const Any& rInnerValue ) const +{ + return rInnerValue; +} +Any WrappedProperty::convertOuterToInnerValue( const Any& rOuterValue ) const +{ + return rOuterValue; +} + +void WrappedProperty::setPropertyValue( const Any& rOuterValue, const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + if(xInnerPropertySet.is()) + xInnerPropertySet->setPropertyValue( getInnerName(), convertOuterToInnerValue( rOuterValue ) ); +} + +Any WrappedProperty::getPropertyValue( const Reference< beans::XPropertySet >& xInnerPropertySet ) const +{ + Any aRet; + if( xInnerPropertySet.is() ) + { + aRet = xInnerPropertySet->getPropertyValue( getInnerName() ); + aRet = convertInnerToOuterValue( aRet ); + } + return aRet; +} + +void WrappedProperty::setPropertyToDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + if( xInnerPropertyState.is() && !getInnerName().isEmpty() ) + xInnerPropertyState->setPropertyToDefault(getInnerName()); + else + { + Reference< beans::XPropertySet > xInnerProp( xInnerPropertyState, uno::UNO_QUERY ); + setPropertyValue( getPropertyDefault( xInnerPropertyState ), xInnerProp ); + } +} + +Any WrappedProperty::getPropertyDefault( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + Any aRet; + if( xInnerPropertyState.is() ) + { + aRet = xInnerPropertyState->getPropertyDefault( getInnerName() ); + aRet = convertInnerToOuterValue( aRet ); + } + return aRet; +} + +beans::PropertyState WrappedProperty::getPropertyState( const Reference< beans::XPropertyState >& xInnerPropertyState ) const +{ + beans::PropertyState aState = beans::PropertyState_DIRECT_VALUE; + OUString aInnerName( getInnerName() ); + if( xInnerPropertyState.is() && !aInnerName.isEmpty() ) + aState = xInnerPropertyState->getPropertyState( aInnerName ); + else + { + try + { + Reference< beans::XPropertySet > xInnerProp( xInnerPropertyState, uno::UNO_QUERY ); + uno::Any aValue = getPropertyValue( xInnerProp ); + if( !aValue.hasValue() ) + aState = beans::PropertyState_DEFAULT_VALUE; + else + { + uno::Any aDefault = getPropertyDefault( xInnerPropertyState ); + if( aValue == aDefault ) + aState = beans::PropertyState_DEFAULT_VALUE; + } + } + catch( const beans::UnknownPropertyException& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + return aState; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/WrappedPropertySet.cxx b/chart2/source/tools/WrappedPropertySet.cxx new file mode 100644 index 000000000..ead7f6d05 --- /dev/null +++ b/chart2/source/tools/WrappedPropertySet.cxx @@ -0,0 +1,445 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +namespace chart +{ + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +WrappedPropertySet::WrappedPropertySet() +{ +} +WrappedPropertySet::~WrappedPropertySet() +{ + clearWrappedPropertySet(); +} + +Reference< beans::XPropertyState > WrappedPropertySet::getInnerPropertyState() +{ + return Reference< beans::XPropertyState >( getInnerPropertySet(), uno::UNO_QUERY ); +} + +void WrappedPropertySet::clearWrappedPropertySet() +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );//do not use different mutex than is already used for static property sequence + + m_pPropertyArrayHelper.reset(); + m_pWrappedPropertyMap.reset(); + + m_xInfo = nullptr; +} + +//XPropertySet +Reference< beans::XPropertySetInfo > SAL_CALL WrappedPropertySet::getPropertySetInfo( ) +{ + Reference< beans::XPropertySetInfo > xInfo = m_xInfo; + if( !xInfo.is() ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );//do not use different mutex than is already used for static property sequence + xInfo = m_xInfo; + if( !xInfo.is() ) + { + xInfo = ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + m_xInfo = xInfo; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return m_xInfo; +} + +void SAL_CALL WrappedPropertySet::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) +{ + try + { + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( pWrappedProperty ) + pWrappedProperty->setPropertyValue( rValue, xInnerPropertySet ); + else if( xInnerPropertySet.is() ) + xInnerPropertySet->setPropertyValue( rPropertyName, rValue ); + else + { + SAL_WARN("chart2.tools", "found no inner property set to map to"); + } + } + catch( const beans::UnknownPropertyException& ) + { + throw; + } + catch( const beans::PropertyVetoException& ) + { + throw; + } + catch( const lang::IllegalArgumentException& ) + { + throw; + } + catch( const lang::WrappedTargetException& ) + { + throw; + } + catch( const uno::RuntimeException& ) + { + throw; + } + catch( const uno::Exception& ex ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + TOOLS_WARN_EXCEPTION( "chart2", "invalid exception caught in WrappedPropertySet::setPropertyValue"); + throw lang::WrappedTargetException( ex.Message, nullptr, anyEx ); + } +} +Any SAL_CALL WrappedPropertySet::getPropertyValue( const OUString& rPropertyName ) +{ + Any aRet; + + try + { + sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName ); + const WrappedProperty* pWrappedProperty = getWrappedProperty( nHandle ); + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyValue( xInnerPropertySet ); + else if( xInnerPropertySet.is() ) + aRet = xInnerPropertySet->getPropertyValue( rPropertyName ); + else + { + SAL_WARN("chart2.tools", "found no inner property set to map to"); + } + } + catch( const beans::UnknownPropertyException& ) + { + throw; + } + catch( const lang::WrappedTargetException& ) + { + throw; + } + catch( const uno::RuntimeException& ) + { + throw; + } + catch( const uno::Exception& ex ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + TOOLS_WARN_EXCEPTION( "chart2", "invalid exception caught in WrappedPropertySet::setPropertyValue"); + throw lang::WrappedTargetException( ex.Message, nullptr, anyEx ); + } + + return aRet; +} + +void SAL_CALL WrappedPropertySet::addPropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& xListener ) +{ + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + xInnerPropertySet->addPropertyChangeListener( pWrappedProperty->getInnerName(), xListener ); + else + xInnerPropertySet->addPropertyChangeListener( rPropertyName, xListener ); + } +} +void SAL_CALL WrappedPropertySet::removePropertyChangeListener( const OUString& rPropertyName, const Reference< beans::XPropertyChangeListener >& aListener ) +{ + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + xInnerPropertySet->removePropertyChangeListener( pWrappedProperty->getInnerName(), aListener ); + else + xInnerPropertySet->removePropertyChangeListener( rPropertyName, aListener ); + } +} +void SAL_CALL WrappedPropertySet::addVetoableChangeListener( const OUString& rPropertyName, const Reference< beans::XVetoableChangeListener >& aListener ) +{ + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + xInnerPropertySet->addVetoableChangeListener( pWrappedProperty->getInnerName(), aListener ); + else + xInnerPropertySet->addVetoableChangeListener( rPropertyName, aListener ); + } +} +void SAL_CALL WrappedPropertySet::removeVetoableChangeListener( const OUString& rPropertyName, const Reference< beans::XVetoableChangeListener >& aListener ) +{ + Reference< beans::XPropertySet > xInnerPropertySet( getInnerPropertySet() ); + if( xInnerPropertySet.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + xInnerPropertySet->removeVetoableChangeListener( pWrappedProperty->getInnerName(), aListener ); + else + xInnerPropertySet->removeVetoableChangeListener( rPropertyName, aListener ); + } +} + +//XMultiPropertySet +void SAL_CALL WrappedPropertySet::setPropertyValues( const Sequence< OUString >& rNameSeq, const Sequence< Any >& rValueSeq ) +{ + bool bUnknownProperty = false; + sal_Int32 nMinCount = std::min( rValueSeq.getLength(), rNameSeq.getLength() ); + for(sal_Int32 nN=0; nN SAL_CALL WrappedPropertySet::getPropertyValues( const Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN& /* rNameSeq */, const Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented yet"); + //todo +} +void SAL_CALL WrappedPropertySet::removePropertiesChangeListener( const Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented yet"); + //todo +} +void SAL_CALL WrappedPropertySet::firePropertiesChangeEvent( const Sequence< OUString >& /* rNameSeq */, const Reference< beans::XPropertiesChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented yet"); + //todo +} + +//XPropertyState +beans::PropertyState SAL_CALL WrappedPropertySet::getPropertyState( const OUString& rPropertyName ) +{ + beans::PropertyState aState( beans::PropertyState_DIRECT_VALUE ); + + Reference< beans::XPropertyState > xInnerPropertyState( getInnerPropertyState() ); + if( xInnerPropertyState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aState = pWrappedProperty->getPropertyState( xInnerPropertyState ); + else + aState = xInnerPropertyState->getPropertyState( rPropertyName ); + } + return aState; +} + +const WrappedProperty* WrappedPropertySet::getWrappedProperty( const OUString& rOuterName ) +{ + sal_Int32 nHandle = getInfoHelper().getHandleByName( rOuterName ); + return getWrappedProperty( nHandle ); +} + +const WrappedProperty* WrappedPropertySet::getWrappedProperty( sal_Int32 nHandle ) +{ + tWrappedPropertyMap::const_iterator aFound( getWrappedPropertyMap().find( nHandle ) ); + if( aFound != getWrappedPropertyMap().end() ) + return (*aFound).second.get(); + return nullptr; +} + +Sequence< beans::PropertyState > SAL_CALL WrappedPropertySet::getPropertyStates( const Sequence< OUString >& rNameSeq ) +{ + Sequence< beans::PropertyState > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN xInnerPropertyState( getInnerPropertyState() ); + if( xInnerPropertyState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + pWrappedProperty->setPropertyToDefault( xInnerPropertyState ); + else + xInnerPropertyState->setPropertyToDefault( rPropertyName ); + } +} +Any SAL_CALL WrappedPropertySet::getPropertyDefault( const OUString& rPropertyName ) +{ + Any aRet; + Reference< beans::XPropertyState > xInnerPropertyState( getInnerPropertyState() ); + if( xInnerPropertyState.is() ) + { + const WrappedProperty* pWrappedProperty = getWrappedProperty( rPropertyName ); + if( pWrappedProperty ) + aRet = pWrappedProperty->getPropertyDefault(xInnerPropertyState); + else + aRet = xInnerPropertyState->getPropertyDefault( rPropertyName ); + } + return aRet; +} + +//XMultiPropertyStates +void SAL_CALL WrappedPropertySet::setAllPropertiesToDefault( ) +{ + const Sequence< beans::Property >& rPropSeq = getPropertySequence(); + for(beans::Property const & prop : rPropSeq) + { + setPropertyToDefault( prop.Name ); + } +} +void SAL_CALL WrappedPropertySet::setPropertiesToDefault( const Sequence< OUString >& rNameSeq ) +{ + for(OUString const & s : rNameSeq) + { + setPropertyToDefault( s ); + } +} +Sequence< Any > SAL_CALL WrappedPropertySet::getPropertyDefaults( const Sequence< OUString >& rNameSeq ) +{ + Sequence< Any > aRetSeq; + if( rNameSeq.hasElements() ) + { + aRetSeq.realloc( rNameSeq.getLength() ); + auto pRetSeq = aRetSeq.getArray(); + for(sal_Int32 nN=0; nN > aPropList( createWrappedProperties() ); + p = new tWrappedPropertyMap; + + for (auto & elem : aPropList) + { + sal_Int32 nHandle = getInfoHelper().getHandleByName( elem->getOuterName() ); + + if( nHandle == -1 ) + { + OSL_FAIL( "missing property in property list" ); + } + else if( p->find( nHandle ) != p->end() ) + { + //duplicate Wrapped property + OSL_FAIL( "duplicate Wrapped property" ); + } + else + (*p)[ nHandle ] = std::move(elem); + } + + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + m_pWrappedPropertyMap.reset(p); + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return *m_pWrappedPropertyMap; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/XMLRangeHelper.cxx b/chart2/source/tools/XMLRangeHelper.cxx new file mode 100644 index 000000000..196a03965 --- /dev/null +++ b/chart2/source/tools/XMLRangeHelper.cxx @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include + +namespace +{ +/** unary function that escapes backslashes and single quotes in a sal_Unicode + array (which you can get from an OUString with getStr()) and puts the result + into the OUStringBuffer given in the CTOR + */ +class lcl_Escape +{ +public: + explicit lcl_Escape( OUStringBuffer & aResultBuffer ) : m_aResultBuffer( aResultBuffer ) {} + void operator() ( sal_Unicode aChar ) + { + static const sal_Unicode s_aQuote( '\'' ); + static const sal_Unicode s_aBackslash( '\\' ); + + if( aChar == s_aQuote || + aChar == s_aBackslash ) + m_aResultBuffer.append( s_aBackslash ); + m_aResultBuffer.append( aChar ); + } + +private: + OUStringBuffer & m_aResultBuffer; +}; + +/** unary function that removes backslash escapes in a sal_Unicode array (which + you can get from an OUString with getStr()) and puts the result into the + OUStringBuffer given in the CTOR + */ +class lcl_UnEscape +{ +public: + explicit lcl_UnEscape( OUStringBuffer & aResultBuffer ) : m_aResultBuffer( aResultBuffer ) {} + void operator() ( sal_Unicode aChar ) + { + static const sal_Unicode s_aBackslash( '\\' ); + + if( aChar != s_aBackslash ) + m_aResultBuffer.append( aChar ); + } + +private: + OUStringBuffer & m_aResultBuffer; +}; + +void lcl_getXMLStringForCell( const ::chart::XMLRangeHelper::Cell & rCell, OUStringBuffer * output ) +{ + OSL_ASSERT(output != nullptr); + + if( rCell.empty()) + return; + + sal_Int32 nCol = rCell.nColumn; + output->append( '.' ); + if( ! rCell.bRelativeColumn ) + output->append( '$' ); + + // get A, B, C, ..., AA, AB, ... representation of column number + if( nCol < 26 ) + output->append( static_cast('A' + nCol) ); + else if( nCol < 702 ) + { + output->append( static_cast('A' + nCol / 26 - 1 )); + output->append( static_cast('A' + nCol % 26) ); + } + else // works for nCol <= 18,278 + { + output->append( static_cast('A' + nCol / 702 - 1 )); + output->append( static_cast('A' + (nCol % 702) / 26 )); + output->append( static_cast('A' + nCol % 26) ); + } + + // write row number as number + if( ! rCell.bRelativeRow ) + output->append( '$' ); + output->append( rCell.nRow + sal_Int32(1) ); +} + +void lcl_getSingleCellAddressFromXMLString( + std::u16string_view rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + ::chart::XMLRangeHelper::Cell & rOutCell ) +{ + // expect "\$?[a-zA-Z]+\$?[1-9][0-9]*" + static const sal_Unicode aDollar( '$' ); + static const sal_Unicode aLetterA( 'A' ); + + OUString aCellStr = OUString(rXMLString.substr( nStartPos, nEndPos - nStartPos + 1 )).toAsciiUpperCase(); + const sal_Unicode* pStrArray = aCellStr.getStr(); + sal_Int32 nLength = aCellStr.getLength(); + sal_Int32 i = nLength - 1, nColumn = 0; + + // parse number for row + while( rtl::isAsciiDigit( pStrArray[ i ] ) && i >= 0 ) + i--; + rOutCell.nRow = (o3tl::toInt32(aCellStr.subView( i + 1 ))) - 1; + // a dollar in XML means absolute (whereas in UI it means relative) + if( pStrArray[ i ] == aDollar ) + { + i--; + rOutCell.bRelativeRow = false; + } + else + rOutCell.bRelativeRow = true; + + // parse rest for column + sal_Int32 nPower = 1; + while( rtl::isAsciiAlpha( pStrArray[ i ] )) + { + nColumn += (pStrArray[ i ] - aLetterA + 1) * nPower; + i--; + nPower *= 26; + } + rOutCell.nColumn = nColumn - 1; + + rOutCell.bRelativeColumn = true; + if( i >= 0 && + pStrArray[ i ] == aDollar ) + rOutCell.bRelativeColumn = false; + rOutCell.bIsEmpty = false; +} + +bool lcl_getCellAddressFromXMLString( + const OUString& rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + ::chart::XMLRangeHelper::Cell & rOutCell, + OUString& rOutTableName ) +{ + static const sal_Unicode aDot( '.' ); + static const sal_Unicode aQuote( '\'' ); + static const sal_Unicode aBackslash( '\\' ); + + sal_Int32 nNextDelimiterPos = nStartPos; + + sal_Int32 nDelimiterPos = nStartPos; + bool bInQuotation = false; + // parse table name + while( nDelimiterPos < nEndPos && + ( bInQuotation || rXMLString[ nDelimiterPos ] != aDot )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nDelimiterPos ] == aBackslash ) + ++nDelimiterPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nDelimiterPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nDelimiterPos; + } + + if( nDelimiterPos == -1 ) + return false; + + if( nDelimiterPos > nStartPos && nDelimiterPos < nEndPos ) + { + // there is a table name before the address + + OUStringBuffer aTableNameBuffer; + const sal_Unicode * pTableName = rXMLString.getStr(); + + // remove escapes from table name + std::for_each( pTableName + nStartPos, + pTableName + nDelimiterPos, + lcl_UnEscape( aTableNameBuffer )); + + // unquote quoted table name + const sal_Unicode * pBuf = aTableNameBuffer.getStr(); + if( pBuf[ 0 ] == aQuote && + pBuf[ aTableNameBuffer.getLength() - 1 ] == aQuote ) + { + OUString aName = aTableNameBuffer.makeStringAndClear(); + rOutTableName = aName.copy( 1, aName.getLength() - 2 ); + } + else + rOutTableName = aTableNameBuffer.makeStringAndClear(); + } + else + nDelimiterPos = nStartPos; + + for( sal_Int32 i = 0; + nNextDelimiterPos < nEndPos; + nDelimiterPos = nNextDelimiterPos, i++ ) + { + nNextDelimiterPos = rXMLString.indexOf( aDot, nDelimiterPos + 1 ); + if( nNextDelimiterPos == -1 || + nNextDelimiterPos > nEndPos ) + nNextDelimiterPos = nEndPos + 1; + + if( i==0 ) + // only take first cell + lcl_getSingleCellAddressFromXMLString( + rXMLString, nDelimiterPos + 1, nNextDelimiterPos - 1, rOutCell ); + } + + return true; +} + +bool lcl_getCellRangeAddressFromXMLString( + const OUString& rXMLString, + sal_Int32 nStartPos, sal_Int32 nEndPos, + ::chart::XMLRangeHelper::CellRange & rOutRange ) +{ + bool bResult = true; + static const sal_Unicode aColon( ':' ); + static const sal_Unicode aQuote( '\'' ); + static const sal_Unicode aBackslash( '\\' ); + + sal_Int32 nDelimiterPos = nStartPos; + bool bInQuotation = false; + // parse table name + while( nDelimiterPos < nEndPos && + ( bInQuotation || rXMLString[ nDelimiterPos ] != aColon )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nDelimiterPos ] == aBackslash ) + ++nDelimiterPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nDelimiterPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nDelimiterPos; + } + + if( nDelimiterPos == nEndPos ) + { + // only one cell + bResult = lcl_getCellAddressFromXMLString( rXMLString, nStartPos, nEndPos, + rOutRange.aUpperLeft, + rOutRange.aTableName ); + if( rOutRange.aTableName.isEmpty() ) + bResult = false; + } + else + { + // range (separated by a colon) + bResult = lcl_getCellAddressFromXMLString( rXMLString, nStartPos, nDelimiterPos - 1, + rOutRange.aUpperLeft, + rOutRange.aTableName ); + if( rOutRange.aTableName.isEmpty() ) + bResult = false; + + OUString sTableSecondName; + if( bResult ) + { + bResult = lcl_getCellAddressFromXMLString( rXMLString, nDelimiterPos + 1, nEndPos, + rOutRange.aLowerRight, + sTableSecondName ); + } + if( bResult && + !sTableSecondName.isEmpty() && + sTableSecondName != rOutRange.aTableName ) + bResult = false; + } + + return bResult; +} + +} // anonymous namespace + +namespace chart::XMLRangeHelper +{ + +CellRange getCellRangeFromXMLString( const OUString & rXMLString ) +{ + static const sal_Unicode aSpace( ' ' ); + static const sal_Unicode aQuote( '\'' ); +// static const sal_Unicode aDoubleQuote( '\"' ); + static const sal_Unicode aDollar( '$' ); + static const sal_Unicode aBackslash( '\\' ); + + const sal_Int32 nLength = rXMLString.getLength(); + + // reset + CellRange aResult; + + // iterate over different ranges + for( sal_Int32 nStartPos = 0, nEndPos = nStartPos; + nEndPos < nLength; + nStartPos = ++nEndPos ) + { + // find start point of next range + + // ignore leading '$' + if( rXMLString[ nEndPos ] == aDollar) + nEndPos++; + + bool bInQuotation = false; + // parse range + while( nEndPos < nLength && + ( bInQuotation || rXMLString[ nEndPos ] != aSpace )) + { + // skip escaped characters (with backslash) + if( rXMLString[ nEndPos ] == aBackslash ) + ++nEndPos; + // toggle quotation mode when finding single quotes + else if( rXMLString[ nEndPos ] == aQuote ) + bInQuotation = ! bInQuotation; + + ++nEndPos; + } + + if( ! lcl_getCellRangeAddressFromXMLString( + rXMLString, + nStartPos, nEndPos - 1, + aResult )) + { + // if an error occurred, bail out + return CellRange(); + } + } + + return aResult; +} + +OUString getXMLStringFromCellRange( const CellRange & rRange ) +{ + static const sal_Unicode aSpace( ' ' ); + static const sal_Unicode aQuote( '\'' ); + + OUStringBuffer aBuffer; + + if( !rRange.aTableName.isEmpty()) + { + bool bNeedsEscaping = ( rRange.aTableName.indexOf( aQuote ) > -1 ); + bool bNeedsQuoting = bNeedsEscaping || ( rRange.aTableName.indexOf( aSpace ) > -1 ); + + // quote table name if it contains spaces or quotes + if( bNeedsQuoting ) + { + // leading quote + aBuffer.append( aQuote ); + + // escape existing quotes + if( bNeedsEscaping ) + { + const sal_Unicode * pTableNameBeg = rRange.aTableName.getStr(); + + // append the quoted string at the buffer + std::for_each( pTableNameBeg, + pTableNameBeg + rRange.aTableName.getLength(), + lcl_Escape( aBuffer ) ); + } + else + aBuffer.append( rRange.aTableName ); + + // final quote + aBuffer.append( aQuote ); + } + else + aBuffer.append( rRange.aTableName ); + } + lcl_getXMLStringForCell( rRange.aUpperLeft, &aBuffer ); + + if( ! rRange.aLowerRight.empty()) + { + // we have a range (not a single cell) + aBuffer.append( u':'); + lcl_getXMLStringForCell( rRange.aLowerRight, &aBuffer ); + } + + return aBuffer.makeStringAndClear(); +} + +} // namespace chart::XMLRangeHelper + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/DateHelper.cxx b/chart2/source/view/axes/DateHelper.cxx new file mode 100644 index 000000000..4c4a96dce --- /dev/null +++ b/chart2/source/view/axes/DateHelper.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +bool DateHelper::IsInSameYear( const Date& rD1, const Date& rD2 ) +{ + return rD1.GetYear() == rD2.GetYear(); +} + +bool DateHelper::IsInSameMonth( const Date& rD1, const Date& rD2 ) +{ + return (rD1.GetYear() == rD2.GetYear()) + && (rD1.GetMonth() == rD2.GetMonth()); +} + +Date DateHelper::GetDateSomeMonthsAway( const Date& rD, sal_Int32 nMonthDistance ) +{ + Date aRet(rD); + aRet.AddMonths( nMonthDistance ); + return aRet; +} + +Date DateHelper::GetDateSomeYearsAway( const Date& rD, sal_Int32 nYearDistance ) +{ + Date aRet(rD); + aRet.AddYears( static_cast(nYearDistance) ); + return aRet; +} + +bool DateHelper::IsLessThanOneMonthAway( const Date& rD1, const Date& rD2 ) +{ + Date aDMin( DateHelper::GetDateSomeMonthsAway( rD1, -1 ) ); + Date aDMax( DateHelper::GetDateSomeMonthsAway( rD1, 1 ) ); + + return rD2 > aDMin && rD2 < aDMax; +} + +bool DateHelper::IsLessThanOneYearAway( const Date& rD1, const Date& rD2 ) +{ + Date aDMin( DateHelper::GetDateSomeYearsAway( rD1, -1 ) ); + Date aDMax( DateHelper::GetDateSomeYearsAway( rD1, 1 ) ); + + return rD2 > aDMin && rD2 < aDMax; +} + +double DateHelper::RasterizeDateValue( double fValue, const Date& rNullDate, tools::Long TimeResolution ) +{ + if (std::isnan(fValue)) + return fValue; + + Date aDate(rNullDate); aDate.AddDays(::rtl::math::approxFloor(fValue)); + switch(TimeResolution) + { + case css::chart::TimeUnit::DAY: + break; + case css::chart::TimeUnit::YEAR: + aDate.SetMonth(1); + aDate.SetDay(1); + break; + case css::chart::TimeUnit::MONTH: + default: + aDate.SetDay(1); + break; + } + return aDate - rNullDate; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/DateScaling.cxx b/chart2/source/view/axes/DateScaling.cxx new file mode 100644 index 000000000..15cb59635 --- /dev/null +++ b/chart2/source/view/axes/DateScaling.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DateScaling.hxx" +#include +#include +#include + +#include + +namespace +{ + +constexpr OUStringLiteral lcl_aServiceName_DateScaling = u"com.sun.star.chart2.DateScaling"; +constexpr OUStringLiteral lcl_aServiceName_InverseDateScaling + = u"com.sun.star.chart2.InverseDateScaling"; + +const double lcl_fNumberOfMonths = 12.0;//todo: this needs to be offered by basic tools Date class if it should be more generic +} + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +DateScaling::DateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ) + : m_aNullDate( rNullDate ) + , m_nTimeUnit( nTimeUnit ) + , m_bShifted( bShifted ) +{ +} + +DateScaling::~DateScaling() +{ +} + +double SAL_CALL DateScaling::doScaling( double value ) +{ + double fResult(value); + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + switch( m_nTimeUnit ) + { + case DAY: + fResult = value; + if(m_bShifted) + fResult+=0.5; + break; + case YEAR: + case MONTH: + default: + { + Date aDate(m_aNullDate); + aDate.AddDays(::rtl::math::approxFloor(value)); + fResult = aDate.GetYear(); + fResult *= lcl_fNumberOfMonths;//assuming equal count of months in each year + fResult += aDate.GetMonth(); + + double fDayOfMonth = aDate.GetDay(); + fDayOfMonth -= 1.0; + double fDaysInMonth = aDate.GetDaysInMonth(); + fResult += fDayOfMonth/fDaysInMonth; + if(m_bShifted) + { + if( m_nTimeUnit==YEAR ) + fResult += 0.5*lcl_fNumberOfMonths; + else + fResult += 0.5; + } + break; + } + } + return fResult; +} + +uno::Reference< XScaling > SAL_CALL DateScaling::getInverseScaling() +{ + return new InverseDateScaling( m_aNullDate, m_nTimeUnit, m_bShifted ); +} + +OUString SAL_CALL DateScaling::getServiceName() +{ + return lcl_aServiceName_DateScaling; +} + +OUString SAL_CALL DateScaling::getImplementationName() +{ + return lcl_aServiceName_DateScaling; +} + +sal_Bool SAL_CALL DateScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL DateScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_DateScaling }; +} + +InverseDateScaling::InverseDateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ) + : m_aNullDate( rNullDate ) + , m_nTimeUnit( nTimeUnit ) + , m_bShifted( bShifted ) +{ +} + +InverseDateScaling::~InverseDateScaling() +{ +} + +double SAL_CALL InverseDateScaling::doScaling( double value ) +{ + double fResult(value); + if( std::isnan( value ) || std::isinf( value ) ) + return std::numeric_limits::quiet_NaN(); + else + { + switch( m_nTimeUnit ) + { + case DAY: + if(m_bShifted) + value -= 0.5; + fResult = value; + break; + case YEAR: + case MONTH: + default: + //Date aDate(m_aNullDate); + if(m_bShifted) + { + if( m_nTimeUnit==YEAR ) + value -= 0.5*lcl_fNumberOfMonths; + else + value -= 0.5; + } + Date aDate( Date::EMPTY ); + double fYear = ::rtl::math::approxFloor(value/lcl_fNumberOfMonths); + double fMonth = ::rtl::math::approxFloor(value-(fYear*lcl_fNumberOfMonths)); + if( fMonth==0.0 ) + { + fYear--; + fMonth=12.0; + } + aDate.SetYear( static_cast(fYear) ); + aDate.SetMonth( static_cast(fMonth) ); + aDate.SetDay( 1 ); + double fMonthCount = (fYear*lcl_fNumberOfMonths)+fMonth; + double fDay = (value-fMonthCount)*aDate.GetDaysInMonth(); + fDay += 1.0; + aDate.SetDay( static_cast(::rtl::math::round(fDay)) ); + fResult = aDate - m_aNullDate; + break; + } + } + return fResult; +} + +uno::Reference< XScaling > SAL_CALL InverseDateScaling::getInverseScaling() +{ + return new DateScaling( m_aNullDate, m_nTimeUnit, m_bShifted ); +} + +OUString SAL_CALL InverseDateScaling::getServiceName() +{ + return lcl_aServiceName_InverseDateScaling; +} + +OUString SAL_CALL InverseDateScaling::getImplementationName() +{ + return lcl_aServiceName_InverseDateScaling; +} + +sal_Bool SAL_CALL InverseDateScaling::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL InverseDateScaling::getSupportedServiceNames() +{ + return { lcl_aServiceName_InverseDateScaling }; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/DateScaling.hxx b/chart2/source/view/axes/DateScaling.hxx new file mode 100644 index 000000000..29b7a139a --- /dev/null +++ b/chart2/source/view/axes/DateScaling.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace chart +{ + +class DateScaling : + public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + DateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ); + virtual ~DateScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) override; + + virtual css::uno::Reference< + css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const Date m_aNullDate; + const sal_Int32 m_nTimeUnit; + const bool m_bShifted; +}; + +class InverseDateScaling : + public ::cppu::WeakImplHelper< + css::chart2::XScaling, + css::lang::XServiceName, + css::lang::XServiceInfo + > +{ +public: + InverseDateScaling( const Date& rNullDate, sal_Int32 nTimeUnit, bool bShifted ); + virtual ~InverseDateScaling() override; + + /// declare XServiceInfo methods + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // ____ XScaling ____ + virtual double SAL_CALL doScaling( double value ) override; + + virtual css::uno::Reference< css::chart2::XScaling > SAL_CALL + getInverseScaling() override; + + // ____ XServiceName ____ + virtual OUString SAL_CALL getServiceName() override; + +private: + const Date m_aNullDate; + const sal_Int32 m_nTimeUnit; + const bool m_bShifted; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx b/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx new file mode 100644 index 000000000..eaf5c4347 --- /dev/null +++ b/chart2/source/view/axes/MinimumAndMaximumSupplier.cxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +MergedMinimumAndMaximumSupplier::MergedMinimumAndMaximumSupplier() +{ +} + +MergedMinimumAndMaximumSupplier::~MergedMinimumAndMaximumSupplier() +{ +} + +void MergedMinimumAndMaximumSupplier::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + m_aMinimumAndMaximumSupplierList.insert( pMinimumAndMaximumSupplier ); +} + +bool MergedMinimumAndMaximumSupplier::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + return m_aMinimumAndMaximumSupplierList.count( pMinimumAndMaximumSupplier ) != 0; +} + +double MergedMinimumAndMaximumSupplier::getMinimumX() +{ + double fGlobalExtremum = std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMinimumX(); + if(fLocalExtremum::quiet_NaN(); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumX() +{ + double fGlobalExtremum = -std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMaximumX(); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(std::isinf(fGlobalExtremum)) + return std::numeric_limits::quiet_NaN(); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + double fGlobalExtremum = std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMinimumYInRange( fMinimumX, fMaximumX, nAxisIndex ); + if(fLocalExtremum::quiet_NaN(); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + double fGlobalExtremum = -std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMaximumYInRange( fMinimumX, fMaximumX, nAxisIndex ); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(std::isinf(fGlobalExtremum)) + return std::numeric_limits::quiet_NaN(); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMinimumZ() +{ + double fGlobalExtremum = std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMinimumZ(); + if(fLocalExtremum::quiet_NaN(); + return fGlobalExtremum; +} + +double MergedMinimumAndMaximumSupplier::getMaximumZ() +{ + double fGlobalExtremum = -std::numeric_limits::infinity(); + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + double fLocalExtremum = elem->getMaximumZ(); + if(fLocalExtremum>fGlobalExtremum) + fGlobalExtremum=fLocalExtremum; + } + if(std::isinf(fGlobalExtremum)) + return std::numeric_limits::quiet_NaN(); + return fGlobalExtremum; +} + +bool MergedMinimumAndMaximumSupplier::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) +{ + // only return true, if *all* suppliers want to scale to the main tick marks + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + if( !elem->isExpandBorderToIncrementRhythm( nDimensionIndex ) ) + return false; + return true; +} + +bool MergedMinimumAndMaximumSupplier::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) +{ + // only return true, if *all* suppliers want to expand the range + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + if( !elem->isExpandIfValuesCloseToBorder( nDimensionIndex ) ) + return false; + return true; +} + +bool MergedMinimumAndMaximumSupplier::isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) +{ + // already return true, if at least one supplier wants to expand the range + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + if( elem->isExpandWideValuesToZero( nDimensionIndex ) ) + return true; + return false; +} + +bool MergedMinimumAndMaximumSupplier::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) +{ + // already return true, if at least one supplier wants to expand the range + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + if( elem->isExpandNarrowValuesTowardZero( nDimensionIndex ) ) + return true; + return false; +} + +bool MergedMinimumAndMaximumSupplier::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) +{ + // should not be called + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + if( elem->isSeparateStackingForDifferentSigns( nDimensionIndex ) ) + return true; + return false; +} + +void MergedMinimumAndMaximumSupplier::clearMinimumAndMaximumSupplierList() +{ + m_aMinimumAndMaximumSupplierList.clear(); +} + +tools::Long MergedMinimumAndMaximumSupplier::calculateTimeResolutionOnXAxis() +{ + tools::Long nRet = css::chart::TimeUnit::YEAR; + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + { + tools::Long nCurrent = elem->calculateTimeResolutionOnXAxis(); + if(nRet>nCurrent) + nRet=nCurrent; + } + return nRet; +} + +void MergedMinimumAndMaximumSupplier::setTimeResolutionOnXAxis( tools::Long nTimeResolution, const Date& rNullDate ) +{ + for (auto const& elem : m_aMinimumAndMaximumSupplierList) + elem->setTimeResolutionOnXAxis( nTimeResolution, rNullDate ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/ScaleAutomatism.cxx b/chart2/source/view/axes/ScaleAutomatism.cxx new file mode 100644 index 000000000..24195c8fd --- /dev/null +++ b/chart2/source/view/axes/ScaleAutomatism.cxx @@ -0,0 +1,989 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "Tickmarks_Equidistant.hxx" +#include +#include "DateScaling.hxx" +#include +#include +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +const sal_Int32 MAXIMUM_MANUAL_INCREMENT_COUNT = 500; +const sal_Int32 MAXIMUM_SUB_INCREMENT_COUNT = 100; + +static sal_Int32 lcl_getMaximumAutoIncrementCount( sal_Int32 nAxisType ) +{ + sal_Int32 nMaximumAutoIncrementCount = 10; + if( nAxisType==AxisType::DATE ) + nMaximumAutoIncrementCount = MAXIMUM_MANUAL_INCREMENT_COUNT; + return nMaximumAutoIncrementCount; +} + +namespace +{ + +void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount ) +{ + if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT ) + rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT; +} + +}//end anonymous namespace + +ExplicitScaleData::ExplicitScaleData() + : Minimum(0.0) + , Maximum(10.0) + , Origin(0.0) + , Orientation(css::chart2::AxisOrientation_MATHEMATICAL) + , AxisType(css::chart2::AxisType::REALNUMBER) + , m_bShiftedCategoryPosition(false) + , TimeResolution(css::chart::TimeUnit::DAY) + , NullDate(30,12,1899) +{ +} + +ExplicitSubIncrement::ExplicitSubIncrement() + : IntervalCount(2) + , PostEquidistant(true) +{ +} + +ExplicitIncrementData::ExplicitIncrementData() + : MajorTimeInterval(1,css::chart::TimeUnit::DAY) + , MinorTimeInterval(1,css::chart::TimeUnit::DAY) + , Distance(1.0) + , PostEquidistant(true) + , BaseValue(0.0) +{ +} + +ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate ) + : m_aSourceScale( rSourceScale ) + , m_fValueMinimum( 0.0 ) + , m_fValueMaximum( 0.0 ) + , m_nMaximumAutoMainIncrementCount( lcl_getMaximumAutoIncrementCount( rSourceScale.AxisType ) ) + , m_bExpandBorderToIncrementRhythm( false ) + , m_bExpandIfValuesCloseToBorder( false ) + , m_bExpandWideValuesToZero( false ) + , m_bExpandNarrowValuesTowardZero( false ) + , m_nTimeResolution(css::chart::TimeUnit::DAY) + , m_aNullDate(rNullDate) +{ + resetValueRange(); + + double fExplicitOrigin = 0.0; + if( m_aSourceScale.Origin >>= fExplicitOrigin ) + expandValueRange( fExplicitOrigin, fExplicitOrigin); +} + +void ScaleAutomatism::resetValueRange( ) +{ + m_fValueMinimum = std::numeric_limits::quiet_NaN(); + m_fValueMaximum = std::numeric_limits::quiet_NaN(); +} + +void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum ) +{ + // if m_fValueMinimum and m_fValueMaximum == 0, it means that they were not determined. + // m_fValueMinimum == 0 makes impossible to determine real minimum, + // so they need to be reset tdf#96807 + if( (m_fValueMinimum == 0.0) && (m_fValueMaximum == 0.0) ) + resetValueRange(); + if( (fMinimum < m_fValueMinimum) || std::isnan( m_fValueMinimum ) ) + m_fValueMinimum = fMinimum; + if( (fMaximum > m_fValueMaximum) || std::isnan( m_fValueMaximum ) ) + m_fValueMaximum = fMaximum; +} + +void ScaleAutomatism::setAutoScalingOptions( + bool bExpandBorderToIncrementRhythm, + bool bExpandIfValuesCloseToBorder, + bool bExpandWideValuesToZero, + bool bExpandNarrowValuesTowardZero ) +{ + // if called multiple times, enable an option, if it is set in at least one call + m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm; + m_bExpandIfValuesCloseToBorder |= bExpandIfValuesCloseToBorder; + m_bExpandWideValuesToZero |= bExpandWideValuesToZero; + m_bExpandNarrowValuesTowardZero |= bExpandNarrowValuesTowardZero; + + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + m_bExpandIfValuesCloseToBorder = false; +} + +void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount ) +{ + if( nMaximumAutoMainIncrementCount < 2 ) + m_nMaximumAutoMainIncrementCount = 2; //#i82006 + else if( nMaximumAutoMainIncrementCount > lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ) ) + m_nMaximumAutoMainIncrementCount = lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ); + else + m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount; +} + +void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution ) +{ + m_nTimeResolution = nTimeResolution; +} + +void ScaleAutomatism::calculateExplicitScaleAndIncrement( + ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const +{ + // fill explicit scale + rExplicitScale.Orientation = m_aSourceScale.Orientation; + rExplicitScale.Scaling = m_aSourceScale.Scaling; + rExplicitScale.AxisType = m_aSourceScale.AxisType; + rExplicitScale.NullDate = m_aNullDate; + + bool bAutoMinimum = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum); + bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum); + bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin); + + // automatic scale minimum + if( bAutoMinimum ) + { + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + rExplicitScale.Minimum = 0.0; + else if( std::isnan( m_fValueMinimum ) ) + { + if( m_aSourceScale.AxisType==AxisType::DATE ) + rExplicitScale.Minimum = 36526.0; //1.1.2000 + else + rExplicitScale.Minimum = 0.0; //@todo get Minimum from scaling or from plotter???? + } + else + rExplicitScale.Minimum = m_fValueMinimum; + } + + // automatic scale maximum + if( bAutoMaximum ) + { + if( m_aSourceScale.AxisType==AxisType::PERCENT ) + rExplicitScale.Maximum = 1.0; + else if( std::isnan( m_fValueMaximum ) ) + { + if( m_aSourceScale.AxisType==AxisType::DATE ) + rExplicitScale.Maximum = 40179.0; //1.1.2010 + else + rExplicitScale.Maximum = 10.0; //@todo get Maximum from scaling or from plotter???? + } + else + rExplicitScale.Maximum = m_fValueMaximum; + } + + //fill explicit increment + + rExplicitScale.m_bShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition; + bool bIsLogarithm = false; + + //minimum and maximum of the ExplicitScaleData may be changed if allowed + if( m_aSourceScale.AxisType==AxisType::DATE ) + calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES ) + calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else + { + bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling ); + if( bIsLogarithm ) + calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + else + calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum ); + } + + // automatic origin + if( bAutoOrigin ) + { + // #i71415# automatic origin for logarithmic axis + double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0; + + if( fDefaulOrigin < rExplicitScale.Minimum ) + fDefaulOrigin = rExplicitScale.Minimum; + else if( fDefaulOrigin > rExplicitScale.Maximum ) + fDefaulOrigin = rExplicitScale.Maximum; + + rExplicitScale.Origin = fDefaulOrigin; + } +} + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // no scaling for categories + rExplicitScale.Scaling.clear(); + + if( rExplicitScale.m_bShiftedCategoryPosition ) + rExplicitScale.Maximum += 1.0; + + // ensure that at least one category is visible + if( rExplicitScale.Maximum <= rExplicitScale.Minimum ) + rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0; + + // default increment settings + rExplicitIncrement.PostEquidistant = true; // does not matter anyhow + rExplicitIncrement.Distance = 1.0; // category axis always have a main increment of 1 + rExplicitIncrement.BaseValue = 0.0; // category axis always have a base of 0 + + // automatic minimum and maximum + if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) + rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement ); + if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) + rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement ); + + //prevent performance killover + double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance ); + if( static_cast< sal_Int32 >( fDistanceCount ) > MAXIMUM_MANUAL_INCREMENT_COUNT ) + { + double fMinimumFloor = ::rtl::math::approxFloor( rExplicitScale.Minimum ); + double fMaximumCeil = ::rtl::math::approxCeil( rExplicitScale.Maximum ); + rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / MAXIMUM_MANUAL_INCREMENT_COUNT ); + } + + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 2; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = false; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForLogarithmic( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // *** STEP 1: initialize the range data *** + + const double fInputMinimum = rExplicitScale.Minimum; + const double fInputMaximum = rExplicitScale.Maximum; + + double fSourceMinimum = rExplicitScale.Minimum; + double fSourceMaximum = rExplicitScale.Maximum; + + // set automatic PostEquidistant to true (maybe scaling dependent?) + // Note: scaling with PostEquidistant==false is untested and needs review + if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) + rExplicitIncrement.PostEquidistant = true; + + /* All following scaling code will operate on the logarithms of the source + values. In the last step, the original values will be restored. */ + uno::Reference< XScaling > xScaling = rExplicitScale.Scaling; + if( !xScaling.is() ) + xScaling.set( AxisHelper::createLogarithmicScaling() ); + uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling(); + + fSourceMinimum = xScaling->doScaling( fSourceMinimum ); + if( !std::isfinite( fSourceMinimum ) ) + fSourceMinimum = 0.0; + else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) ) + fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum ); + + fSourceMaximum = xScaling->doScaling( fSourceMaximum ); + if( !std::isfinite( fSourceMaximum ) ) + fSourceMaximum = 0.0; + else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) ) + fSourceMaximum = ::rtl::math::approxFloor( fSourceMaximum ); + + /* If range is invalid (minimum greater than maximum), change one of the + variable limits to validate the range. In this step, a zero-sized range + is still allowed. */ + if( fSourceMinimum > fSourceMaximum ) + { + // force changing the maximum, if both limits are fixed + if( bAutoMaximum || !bAutoMinimum ) + fSourceMaximum = fSourceMinimum; + else + fSourceMinimum = fSourceMaximum; + } + + /* If maximum is less than 0 (and therefore minimum too), minimum and + maximum will be negated and swapped to make the following algorithms + easier. Example: Both ranges [2,5] and [-5,-2] will be processed as + [2,5], and the latter will be swapped back later. The range [0,0] is + explicitly excluded from swapping (this would result in [-1,0] instead + of the expected [0,1]). */ + bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); + if( bSwapAndNegateRange ) + { + double fTempValue = fSourceMinimum; + fSourceMinimum = -fSourceMaximum; + fSourceMaximum = -fTempValue; + std::swap( bAutoMinimum, bAutoMaximum ); + } + + // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** + + double fTempMinimum = fSourceMinimum; + double fTempMaximum = fSourceMaximum; + + /* If minimum is variable and greater than 0 (and therefore maximum too), + means all original values are greater than 1 (or all values are less + than 1, and the range has been swapped above), then: */ + if( bAutoMinimum && (fTempMinimum > 0.0) ) + { + double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); + double fMaximumFloor = ::rtl::math::approxFloor( fTempMaximum ); + // handle the exact value B^(n+1) to be in the range [B^n,B^(n+1)] + if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) ) + fMaximumFloor -= 1.0; + + if( fMinimumFloor == fMaximumFloor ) + { + /* if minimum and maximum are in one increment interval, expand + minimum toward 0 to make the 'shorter' data points visible. */ + if( m_bExpandNarrowValuesTowardZero ) + fTempMinimum -= 1.0; + } + } + + /* If range is still zero-sized (e.g. when minimum is fixed), set minimum + to 0, which makes the axis start/stop at the value 1. */ + if( fTempMinimum == fTempMaximum ) + { + if( bAutoMinimum && (fTempMaximum > 0.0) ) + fTempMinimum = 0.0; + else + fTempMaximum += 1.0; // always add one interval, even if maximum is fixed + } + + // *** STEP 3: calculate main interval size *** + + // base value (anchor position of the intervals), already scaled + if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) + { + //scaling dependent + //@maybe todo is this default also plotter dependent ?? + if( !bAutoMinimum ) + rExplicitIncrement.BaseValue = fTempMinimum; + else if( !bAutoMaximum ) + rExplicitIncrement.BaseValue = fTempMaximum; + else + rExplicitIncrement.BaseValue = 0.0; + } + + // calculate automatic interval + bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); + if( bAutoDistance ) + rExplicitIncrement.Distance = 0.0; + + /* Restrict number of allowed intervals with user-defined distance to + MAXIMUM_MANUAL_INCREMENT_COUNT. */ + sal_Int32 nMaxMainIncrementCount = bAutoDistance ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + + // repeat calculation until number of intervals are valid + bool bNeedIteration = true; + bool bHasCalculatedDistance = false; + while( bNeedIteration ) + { + if( bAutoDistance ) + { + // first iteration: calculate interval size from axis limits + if( !bHasCalculatedDistance ) + { + double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum ); + double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum ); + rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / nMaxMainIncrementCount ); + } + else + { + // following iterations: increase distance + rExplicitIncrement.Distance += 1.0; + } + + // for next iteration: distance calculated -> use else path to increase + bHasCalculatedDistance = true; + } + + // *** STEP 4: additional space above or below the data points *** + + double fAxisMinimum = fTempMinimum; + double fAxisMaximum = fTempMaximum; + + // round to entire multiples of the distance and add additional space + if( bAutoMinimum && m_bExpandBorderToIncrementRhythm ) + { + fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); + + //ensure valid values after scaling #i100995# + if( !bAutoDistance ) + { + double fCheck = xInverseScaling->doScaling( fAxisMinimum ); + if( !std::isfinite( fCheck ) || fCheck <= 0 ) + { + bAutoDistance = true; + bHasCalculatedDistance = false; + continue; + } + } + } + if( bAutoMaximum && m_bExpandBorderToIncrementRhythm ) + { + fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); + + //ensure valid values after scaling #i100995# + if( !bAutoDistance ) + { + double fCheck = xInverseScaling->doScaling( fAxisMaximum ); + if( !std::isfinite( fCheck ) || fCheck <= 0 ) + { + bAutoDistance = true; + bHasCalculatedDistance = false; + continue; + } + } + } + + // set the resulting limits (swap back to negative range if needed) + if( bSwapAndNegateRange ) + { + rExplicitScale.Minimum = -fAxisMaximum; + rExplicitScale.Maximum = -fAxisMinimum; + } + else + { + rExplicitScale.Minimum = fAxisMinimum; + rExplicitScale.Maximum = fAxisMaximum; + } + + /* If the number of intervals is too high (e.g. due to invalid fixed + distance or due to added space above or below data points), + calculate again with increased distance. */ + double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); + bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; + // if manual distance is invalid, trigger automatic calculation + if( bNeedIteration ) + bAutoDistance = true; + + // convert limits back to logarithmic scale + rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum ); + rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum ); + + //ensure valid values after scaling #i100995# + if( !std::isfinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0) + { + rExplicitScale.Minimum = fInputMinimum; + if( !std::isfinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0 ) + rExplicitScale.Minimum = 1.0; + } + if( !std::isfinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) + { + rExplicitScale.Maximum= fInputMaximum; + if( !std::isfinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 ) + rExplicitScale.Maximum = 10.0; + } + if( rExplicitScale.Maximum < rExplicitScale.Minimum ) + std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum ); + } + + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 9; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = false; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForDateTimeAxis( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + Date aMinDate(m_aNullDate); aMinDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Minimum)); + Date aMaxDate(m_aNullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum)); + rExplicitIncrement.PostEquidistant = false; + + if( aMinDate > aMaxDate ) + { + std::swap(aMinDate,aMaxDate); + } + + if( !(m_aSourceScale.TimeIncrement.TimeResolution >>= rExplicitScale.TimeResolution) ) + rExplicitScale.TimeResolution = m_nTimeResolution; + + rExplicitScale.Scaling = new DateScaling(m_aNullDate,rExplicitScale.TimeResolution,false); + + // choose min and max suitable to time resolution + switch( rExplicitScale.TimeResolution ) + { + case DAY: + if( rExplicitScale.m_bShiftedCategoryPosition ) + ++aMaxDate; //for explicit scales we need one interval more (maximum excluded) + break; + case MONTH: + aMinDate.SetDay(1); + aMaxDate.SetDay(1); + if( rExplicitScale.m_bShiftedCategoryPosition ) + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) + if( DateHelper::IsLessThanOneMonthAway( aMinDate, aMaxDate ) ) + { + if( bAutoMaximum || !bAutoMinimum ) + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMinDate,1); + else + aMinDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); + } + break; + case YEAR: + aMinDate.SetDay(1); + aMinDate.SetMonth(1); + aMaxDate.SetDay(1); + aMaxDate.SetMonth(1); + if( rExplicitScale.m_bShiftedCategoryPosition ) + aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded) + if( DateHelper::IsLessThanOneYearAway( aMinDate, aMaxDate ) ) + { + if( bAutoMaximum || !bAutoMinimum ) + aMaxDate = DateHelper::GetDateSomeYearsAway(aMinDate,1); + else + aMinDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); + } + break; + } + + // set the resulting limits (swap back to negative range if needed) + rExplicitScale.Minimum = aMinDate - m_aNullDate; + rExplicitScale.Maximum = aMaxDate - m_aNullDate; + + bool bAutoMajor = !(m_aSourceScale.TimeIncrement.MajorTimeInterval >>= rExplicitIncrement.MajorTimeInterval); + bool bAutoMinor = !(m_aSourceScale.TimeIncrement.MinorTimeInterval >>= rExplicitIncrement.MinorTimeInterval); + + sal_Int32 nMaxMainIncrementCount = bAutoMajor ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + if( nMaxMainIncrementCount > 1 ) + nMaxMainIncrementCount--; + + //choose major time interval: + tools::Long nDayCount = aMaxDate - aMinDate; + tools::Long nMainIncrementCount = 1; + if( !bAutoMajor ) + { + tools::Long nIntervalDayCount = rExplicitIncrement.MajorTimeInterval.Number; + if( rExplicitIncrement.MajorTimeInterval.TimeUnit < rExplicitScale.TimeResolution ) + rExplicitIncrement.MajorTimeInterval.TimeUnit = rExplicitScale.TimeResolution; + switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + case YEAR: + nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + } + nMainIncrementCount = nDayCount/nIntervalDayCount; + if( nMainIncrementCount > nMaxMainIncrementCount ) + bAutoMajor = true; + } + if( bAutoMajor ) + { + tools::Long nNumer = 1; + tools::Long nIntervalDays = nDayCount / nMaxMainIncrementCount; + double nDaysPerInterval = 1.0; + if( nIntervalDays>365 || rExplicitScale.TimeResolution==YEAR ) + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = YEAR; + nDaysPerInterval = 365.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + } + else if( nIntervalDays>31 || rExplicitScale.TimeResolution==MONTH ) + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH; + nDaysPerInterval = 31.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + } + else + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = DAY; + nDaysPerInterval = 1.0; + } + + nNumer = static_cast( rtl::math::approxFloor( nIntervalDays/nDaysPerInterval ) ); + if(nNumer<=0) + nNumer=1; + if( rExplicitIncrement.MajorTimeInterval.TimeUnit == DAY ) + { + if( nNumer>2 && nNumer<7 ) + nNumer=7; + else if( nNumer>7 ) + { + rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH; + nDaysPerInterval = 31.0; + nNumer = static_cast( rtl::math::approxFloor( nIntervalDays/nDaysPerInterval ) ); + if(nNumer<=0) + nNumer=1; + } + } + rExplicitIncrement.MajorTimeInterval.Number = nNumer; + nMainIncrementCount = static_cast(nDayCount/(nNumer*nDaysPerInterval)); + } + + //choose minor time interval: + if( !bAutoMinor ) + { + if( rExplicitIncrement.MinorTimeInterval.TimeUnit > rExplicitIncrement.MajorTimeInterval.TimeUnit ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; + tools::Long nIntervalDayCount = rExplicitIncrement.MinorTimeInterval.Number; + switch( rExplicitIncrement.MinorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + case YEAR: + nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ... + break; + } + if( nDayCount/nIntervalDayCount > nMaxMainIncrementCount ) + bAutoMinor = true; + } + if( !bAutoMinor ) + return; + + rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit; + rExplicitIncrement.MinorTimeInterval.Number = 1; + if( nMainIncrementCount > 100 ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; + else + { + if( rExplicitIncrement.MajorTimeInterval.Number >= 2 ) + { + if( !(rExplicitIncrement.MajorTimeInterval.Number%2) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/2; + else if( !(rExplicitIncrement.MajorTimeInterval.Number%3) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/3; + else if( !(rExplicitIncrement.MajorTimeInterval.Number%5) ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/5; + else if( rExplicitIncrement.MajorTimeInterval.Number > 50 ) + rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number; + } + else + { + switch( rExplicitIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + break; + case MONTH: + if( rExplicitScale.TimeResolution == DAY ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = DAY; + break; + case YEAR: + if( rExplicitScale.TimeResolution <= MONTH ) + rExplicitIncrement.MinorTimeInterval.TimeUnit = MONTH; + break; + } + } + } + +} + +void ScaleAutomatism::calculateExplicitIncrementAndScaleForLinear( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const +{ + // *** STEP 1: initialize the range data *** + + double fSourceMinimum = rExplicitScale.Minimum; + double fSourceMaximum = rExplicitScale.Maximum; + + // set automatic PostEquidistant to true (maybe scaling dependent?) + if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) ) + rExplicitIncrement.PostEquidistant = true; + + /* If range is invalid (minimum greater than maximum), change one of the + variable limits to validate the range. In this step, a zero-sized range + is still allowed. */ + if( fSourceMinimum > fSourceMaximum ) + { + // force changing the maximum, if both limits are fixed + if( bAutoMaximum || !bAutoMinimum ) + fSourceMaximum = fSourceMinimum; + else + fSourceMinimum = fSourceMaximum; + } + + /* If maximum is zero or negative (and therefore minimum too), minimum and + maximum will be negated and swapped to make the following algorithms + easier. Example: Both ranges [2,5] and [-5,-2] will be processed as + [2,5], and the latter will be swapped back later. The range [0,0] is + explicitly excluded from swapping (this would result in [-1,0] instead + of the expected [0,1]). */ + bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0); + if( bSwapAndNegateRange ) + { + double fTempValue = fSourceMinimum; + fSourceMinimum = -fSourceMaximum; + fSourceMaximum = -fTempValue; + std::swap( bAutoMinimum, bAutoMaximum ); + } + + // *** STEP 2: find temporary (unrounded) axis minimum and maximum *** + + double fTempMinimum = fSourceMinimum; + double fTempMaximum = fSourceMaximum; + + /* If minimum is variable and greater than 0 (and therefore maximum too), + means all values are positive (or all values are negative, and the + range has been swapped above), then: */ + if( bAutoMinimum && (fTempMinimum > 0.0) ) + { + /* If minimum equals maximum, or if minimum is less than 5/6 of + maximum, set minimum to 0. */ + if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) ) + { + if( m_bExpandWideValuesToZero ) + fTempMinimum = 0.0; + } + /* Else (minimum is greater than or equal to 5/6 of maximum), add half + of the visible range (expand minimum toward 0) to make the + 'shorter' data points visible. */ + else + { + if( m_bExpandNarrowValuesTowardZero ) + fTempMinimum -= (fTempMaximum - fTempMinimum) / 2.0; + } + } + + /* If range is still zero-sized (e.g. when minimum is fixed), add some + space to a variable limit. */ + if( fTempMinimum == fTempMaximum ) + { + if( bAutoMaximum || !bAutoMinimum ) + { + // change 0 to 1, otherwise double the value + if( fTempMaximum == 0.0 ) + fTempMaximum = 1.0; + else + fTempMaximum *= 2.0; + } + else + { + // change 0 to -1, otherwise halve the value + if( fTempMinimum == 0.0 ) + fTempMinimum = -1.0; + else + fTempMinimum /= 2.0; + } + } + + // *** STEP 3: calculate main interval size *** + + // base value (anchor position of the intervals) + if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) ) + { + if( !bAutoMinimum ) + rExplicitIncrement.BaseValue = fTempMinimum; + else if( !bAutoMaximum ) + rExplicitIncrement.BaseValue = fTempMaximum; + else + rExplicitIncrement.BaseValue = 0.0; + } + + // calculate automatic interval + bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance); + /* Restrict number of allowed intervals with user-defined distance to + MAXIMUM_MANUAL_INCREMENT_COUNT. */ + sal_Int32 nMaxMainIncrementCount = bAutoDistance ? + m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT; + + double fDistanceMagnitude = 0.0; + double fDistanceNormalized = 0.0; + bool bHasNormalizedDistance = false; + + // repeat calculation until number of intervals are valid + bool bNeedIteration = true; + while( bNeedIteration ) + { + if( bAutoDistance ) + { + // first iteration: calculate interval size from axis limits + if( !bHasNormalizedDistance ) + { + // raw size of an interval + double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount; + + // if distance of is less than 1e-307, do not do anything + if( fDistance <= 1.0e-307 ) + { + fDistanceNormalized = 1.0; + fDistanceMagnitude = 1.0e-307; + } + else if ( !std::isfinite(fDistance) ) + { + // fdo#43703: Handle values bigger than limits correctly + fDistanceNormalized = 1.0; + fDistanceMagnitude = std::numeric_limits::max(); + } + else + { + // distance magnitude (a power of 10) + int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) ); + fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent ); + + // stick normalized distance to a few predefined values + fDistanceNormalized = fDistance / fDistanceMagnitude; + if( fDistanceNormalized <= 1.0 ) + fDistanceNormalized = 1.0; + else if( fDistanceNormalized <= 2.0 ) + fDistanceNormalized = 2.0; + else if( fDistanceNormalized <= 5.0 ) + fDistanceNormalized = 5.0; + else + { + fDistanceNormalized = 1.0; + fDistanceMagnitude *= 10; + } + } + // for next iteration: distance is normalized -> use else path to increase distance + bHasNormalizedDistance = true; + } + // following iterations: increase distance, use only allowed values + else + { + if( fDistanceNormalized == 1.0 ) + fDistanceNormalized = 2.0; + else if( fDistanceNormalized == 2.0 ) + fDistanceNormalized = 5.0; + else + { + fDistanceNormalized = 1.0; + fDistanceMagnitude *= 10; + } + } + + // set the resulting distance + rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude; + } + + // *** STEP 4: additional space above or below the data points *** + + double fAxisMinimum = fTempMinimum; + double fAxisMaximum = fTempMaximum; + + // round to entire multiples of the distance and add additional space + if( bAutoMinimum ) + { + // round to entire multiples of the distance, based on the base value + if( m_bExpandBorderToIncrementRhythm ) + fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement ); + // additional space, if source minimum is to near at axis minimum + if( m_bExpandIfValuesCloseToBorder ) + if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) + fAxisMinimum -= rExplicitIncrement.Distance; + } + if( bAutoMaximum ) + { + // round to entire multiples of the distance, based on the base value + if( m_bExpandBorderToIncrementRhythm ) + fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement ); + // additional space, if source maximum is to near at axis maximum + if( m_bExpandIfValuesCloseToBorder ) + if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) ) + fAxisMaximum += rExplicitIncrement.Distance; + } + + // set the resulting limits (swap back to negative range if needed) + if( bSwapAndNegateRange ) + { + rExplicitScale.Minimum = -fAxisMaximum; + rExplicitScale.Maximum = -fAxisMinimum; + } + else + { + rExplicitScale.Minimum = fAxisMinimum; + rExplicitScale.Maximum = fAxisMaximum; + } + + /* If the number of intervals is too high (e.g. due to invalid fixed + distance or due to added space above or below data points), + calculate again with increased distance. */ + double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance ); + bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount; + // if manual distance is invalid, trigger automatic calculation + if( bNeedIteration ) + bAutoDistance = true; + } + + //fill explicit sub increment + sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength(); + for( sal_Int32 nN=0; nN>=aExplicitSubIncrement.IntervalCount)) + { + //scaling dependent + //@todo autocalculate IntervalCount dependent on MainIncrement and scaling + aExplicitSubIncrement.IntervalCount = 2; + } + lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount ); + if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant)) + { + //scaling dependent + aExplicitSubIncrement.PostEquidistant = false; + } + rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/TickmarkProperties.hxx b/chart2/source/view/axes/TickmarkProperties.hxx new file mode 100644 index 000000000..cbb0398b6 --- /dev/null +++ b/chart2/source/view/axes/TickmarkProperties.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace chart +{ +struct TickmarkProperties +{ + sal_Int32 + RelativePos; //Position in screen values relative to the axis where the tickmark line starts + sal_Int32 Length; //Length of the tickmark line in screen values + + VLineProperties aLineProperties; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks.cxx b/chart2/source/view/axes/Tickmarks.cxx new file mode 100644 index 000000000..01e4a7216 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Tickmarks.hxx" +#include "Tickmarks_Equidistant.hxx" +#include "Tickmarks_Dates.hxx" +#include +#include "VAxisProperties.hxx" +#include +#include + +using namespace ::com::sun::star; +using ::basegfx::B2DVector; + +namespace chart { + +TickInfo::TickInfo( const uno::Reference& xInverse ) +: fScaledTickValue( 0.0 ) +, xInverseScaling( xInverse ) +, aTickScreenPosition(0.0,0.0) +, nFactorForLimitedTextWidth(1) +, bPaintIt( true ) +{ +} + +double TickInfo::getUnscaledTickValue() const +{ + if( xInverseScaling.is() ) + return xInverseScaling->doScaling( fScaledTickValue ); + else + return fScaledTickValue; +} + +sal_Int32 TickInfo::getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const +{ + //return the positive distance between the two first tickmarks in screen values + + B2DVector aDistance = rOherTickInfo.aTickScreenPosition - aTickScreenPosition; + sal_Int32 nRet = static_cast(aDistance.getLength()); + if(nRet<0) + nRet *= -1; + return nRet; +} + +PureTickIter::PureTickIter( TickInfoArrayType& rTickInfoVector ) + : m_rTickVector(rTickInfoVector) + , m_aTickIter(m_rTickVector.begin()) +{ +} +PureTickIter::~PureTickIter() +{ +} +TickInfo* PureTickIter::firstInfo() +{ + m_aTickIter = m_rTickVector.begin(); + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + return nullptr; +} +TickInfo* PureTickIter::nextInfo() +{ + if(m_aTickIter!=m_rTickVector.end()) + { + ++m_aTickIter; + if(m_aTickIter!=m_rTickVector.end()) + return &*m_aTickIter; + } + return nullptr; +} + +TickFactory::TickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) +{ + //@todo: make sure that the scale is valid for the scaling + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return an inverse Scaling" ); + } + + m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + + m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); +} + +TickFactory::~TickFactory() +{ +} + +bool TickFactory::isDateAxis() const +{ + return m_rScale.AxisType == chart2::AxisType::DATE; +} + +void TickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicks( rAllTickInfos ); +} + +void TickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const +{ + if( isDateAxis() ) + DateTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); + else + EquidistantTickFactory( m_rScale, m_rIncrement ).getAllTicksShifted( rAllTickInfos ); +} + +// ___TickFactory_2D___ +TickFactory2D::TickFactory2D( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement + //, double fStretch_SceneToScreen, double fOffset_SceneToScreen ) + , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos + , const B2DVector& rAxisLineToLabelLineShift ) + : TickFactory( rScale, rIncrement ) + , m_aAxisStartScreenPosition2D(rStartScreenPos) + , m_aAxisEndScreenPosition2D(rEndScreenPos) + , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift) + , m_fStretch_LogicToScreen(1.0) + , m_fOffset_LogicToScreen(0.0) +{ + double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin; + if (m_rScale.Orientation == chart2::AxisOrientation_MATHEMATICAL) + { + m_fStretch_LogicToScreen = 1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMin; + } + else + { + B2DVector aSwap(m_aAxisStartScreenPosition2D); + m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D; + m_aAxisEndScreenPosition2D = aSwap; + + m_fStretch_LogicToScreen = -1.0/fWidthY; + m_fOffset_LogicToScreen = -m_fScaledVisibleMax; + } +} + +TickFactory2D::~TickFactory2D() +{ +} + +bool TickFactory2D::isHorizontalAxis() const +{ + // check trivial cases: + if ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ) + return true; + if ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ) + return false; + + // for skew axes compare angle with horizontal vector + double fInclination = std::abs(B2DVector(m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D).angle(B2DVector(1.0, 0.0))); + return fInclination < M_PI_4 || fInclination > (M_PI-M_PI_4); +} +bool TickFactory2D::isVerticalAxis() const +{ + // check trivial cases: + if ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() ) + return true; + if ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() ) + return false; + + // for skew axes compare angle with vertical vector + double fInclination = std::abs(B2DVector(m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D).angle(B2DVector(0.0, -1.0))); + return fInclination < M_PI_4 || fInclination > (M_PI-M_PI_4); +} +//static +sal_Int32 TickFactory2D::getTickScreenDistance( TickIter& rIter ) +{ + //return the positive distance between the two first tickmarks in screen values + //if there are less than two tickmarks -1 is returned + + const TickInfo* pFirstTickInfo = rIter.firstInfo(); + const TickInfo* pSecondTickInfo = rIter.nextInfo(); + if(!pSecondTickInfo || !pFirstTickInfo) + return -1; + + return pFirstTickInfo->getScreenDistanceBetweenTicks( *pSecondTickInfo ); +} + +B2DVector TickFactory2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const +{ + B2DVector aRet(m_aAxisStartScreenPosition2D); + aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D) + *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStretch_LogicToScreen); + return aRet; +} + +void TickFactory2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties + , bool bPlaceAtLabels ) const +{ + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aTickScreenPosition = getTickScreenPosition2D(fScaledLogicTickValue); + if( bPlaceAtLabels ) + aTickScreenPosition += m_aAxisLineToLabelLineShift; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos; + B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length; + + rPoints.getArray()[nSequenceIndex] + = { { static_cast(aStart.getX()), static_cast(aStart.getY()) }, + { static_cast(aEnd.getX()), static_cast(aEnd.getY()) } }; +} + +B2DVector TickFactory2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties, bool bIncludeFarAwayDistanceIfSo, bool bIncludeSpaceBetweenTickAndText ) const +{ + bool bFarAwayLabels = false; + if( rAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START + || rAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + bFarAwayLabels = true; + + double fInnerDirectionSign = rAxisProperties.maLabelAlignment.mfInnerTickDirection; + if( fInnerDirectionSign==0.0 ) + fInnerDirectionSign = 1.0; + + B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D; + aMainDirection.normalize(); + B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection *= fInnerDirectionSign; + aOrthoDirection.normalize(); + + B2DVector aStart(0,0), aEnd(0,0); + if( bFarAwayLabels ) + { + TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() ); + aStart = aOrthoDirection*aProps.RelativePos; + aEnd = aStart - aOrthoDirection*aProps.Length; + } + else + { + for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;) + { + const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN]; + B2DVector aNewStart = aOrthoDirection*rProps.RelativePos; + B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length; + if(aNewStart.getLength()>aStart.getLength()) + aStart=aNewStart; + if(aNewEnd.getLength()>aEnd.getLength()) + aEnd=aNewEnd; + } + } + + B2DVector aLabelDirection(aStart); + if (rAxisProperties.maLabelAlignment.mfInnerTickDirection != rAxisProperties.maLabelAlignment.mfLabelDirection) + aLabelDirection = aEnd; + + B2DVector aOrthoLabelDirection(aOrthoDirection); + if (rAxisProperties.maLabelAlignment.mfInnerTickDirection != rAxisProperties.maLabelAlignment.mfLabelDirection) + aOrthoLabelDirection*=-1.0; + aOrthoLabelDirection.normalize(); + if( bIncludeSpaceBetweenTickAndText ) + aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING; + if( bFarAwayLabels && bIncludeFarAwayDistanceIfSo ) + aLabelDirection += m_aAxisLineToLabelLineShift; + return aLabelDirection; +} + +void TickFactory2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const +{ + rPoints.getArray()[0] = { { static_cast(m_aAxisStartScreenPosition2D.getX()), + static_cast(m_aAxisStartScreenPosition2D.getY()) }, + { static_cast(m_aAxisEndScreenPosition2D.getX()), + static_cast(m_aAxisEndScreenPosition2D.getY()) } }; +} + +void TickFactory2D::updateScreenValues( TickInfoArraysType& rAllTickInfos ) const +{ + //get the transformed screen values for all tickmarks in rAllTickInfos + for (auto & tickInfos : rAllTickInfos) + { + for (auto & tickInfo : tickInfos) + { + tickInfo.aTickScreenPosition = + getTickScreenPosition2D(tickInfo.fScaledTickValue); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks.hxx b/chart2/source/view/axes/Tickmarks.hxx new file mode 100644 index 000000000..bb33be504 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks.hxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace chart { struct AxisProperties; } +namespace chart { struct TickmarkProperties; } +namespace com::sun::star::chart2 { class XScaling; } +namespace com::sun::star::drawing { class XShape; } + +namespace chart { + +struct TickInfo +{ + double fScaledTickValue; + css::uno::Reference xInverseScaling; + rtl::Reference xTextShape; + OUString aText;//used only for complex categories so far + ::basegfx::B2DVector aTickScreenPosition; + sal_Int32 nFactorForLimitedTextWidth;//categories in higher levels of complex categories can have more place than a single simple category + bool bPaintIt; + +//methods: + TickInfo() = delete; + explicit TickInfo( const css::uno::Reference& xInverse ); + + /** + * Return a value associated with the tick mark. It's normally an original + * value from the data source, or 1-based integer index in case the axis + * is a category axis. + */ + double getUnscaledTickValue() const; + sal_Int32 getScreenDistanceBetweenTicks( const TickInfo& rOherTickInfo ) const; +}; + +typedef std::vector TickInfoArrayType; +typedef std::vector TickInfoArraysType; + +class TickIter +{ +public: + virtual ~TickIter() {} + virtual TickInfo* firstInfo() = 0; + virtual TickInfo* nextInfo() = 0; +}; + +class PureTickIter : public TickIter +{ +public: + explicit PureTickIter( TickInfoArrayType& rTickInfoVector ); + virtual ~PureTickIter() override; + virtual TickInfo* firstInfo() override; + virtual TickInfo* nextInfo() override; + +private: + TickInfoArrayType& m_rTickVector; + TickInfoArrayType::iterator m_aTickIter; +}; + +class TickFactory +{ +public: + TickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + virtual ~TickFactory(); + + void getAllTicks( TickInfoArraysType& rAllTickInfos ) const; + void getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const; + +private: //methods + bool isDateAxis() const; + +protected: //member + ExplicitScaleData m_rScale; + ExplicitIncrementData m_rIncrement; + css::uno::Reference< css::chart2::XScaling > m_xInverseScaling; + + //minimum and maximum of the visible range after scaling + double m_fScaledVisibleMin; + double m_fScaledVisibleMax; +}; + +class TickFactory2D final : public TickFactory +{ +public: + TickFactory2D( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement + , const ::basegfx::B2DVector& rStartScreenPos, const ::basegfx::B2DVector& rEndScreenPos + , const ::basegfx::B2DVector& rAxisLineToLabelLineShift ); + + virtual ~TickFactory2D() override; + + static sal_Int32 getTickScreenDistance( TickIter& rIter ); + + void createPointSequenceForAxisMainLine( css::drawing::PointSequenceSequence& rPoints ) const; + void addPointSequenceForTickLine( css::drawing::PointSequenceSequence& rPoints + , sal_Int32 nSequenceIndex + , double fScaledLogicTickValue, double fInnerDirectionSign + , const TickmarkProperties& rTickmarkProperties, bool bPlaceAtLabels ) const; + ::basegfx::B2DVector getDistanceAxisTickToText( const AxisProperties& rAxisProperties + , bool bIncludeFarAwayDistanceIfSo = false + , bool bIncludeSpaceBetweenTickAndText = true ) const; + + /** + * Determine the screen positions of all ticks based on their numeric values. + */ + void updateScreenValues( TickInfoArraysType& rAllTickInfos ) const; + + bool isHorizontalAxis() const; + bool isVerticalAxis() const; + + const ::basegfx::B2DVector & getXaxisStartPos() const + { + return m_aAxisStartScreenPosition2D; + } + + const ::basegfx::B2DVector & getXaxisEndPos() const + { + return m_aAxisEndScreenPosition2D; + } + +private: + ::basegfx::B2DVector getTickScreenPosition2D( double fScaledLogicTickValue ) const; + + ::basegfx::B2DVector m_aAxisStartScreenPosition2D; + ::basegfx::B2DVector m_aAxisEndScreenPosition2D; + + //labels might be positioned high or low on the border of the diagram far away from the axis + //add this vector to go from the axis line to the label line (border of the diagram) + ::basegfx::B2DVector m_aAxisLineToLabelLineShift; + + double m_fStretch_LogicToScreen; + double m_fOffset_LogicToScreen; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks_Dates.cxx b/chart2/source/view/axes/Tickmarks_Dates.cxx new file mode 100644 index 000000000..854e661f6 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Dates.cxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Tickmarks_Dates.hxx" +#include "DateScaling.hxx" +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; +using ::com::sun::star::chart::TimeUnit::DAY; +using ::com::sun::star::chart::TimeUnit::MONTH; +using ::com::sun::star::chart::TimeUnit::YEAR; + +DateTickFactory::DateTickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_aScale( rScale ) + , m_aIncrement( rIncrement ) +{ + //@todo: make sure that the scale is valid for the scaling + + if( m_aScale.Scaling.is() ) + { + m_xInverseScaling = m_aScale.Scaling->getInverseScaling(); + OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return an inverse Scaling" ); + } +} + +DateTickFactory::~DateTickFactory() +{ +} + +void DateTickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos, bool bShifted ) const +{ + rAllTickInfos.resize(2); + TickInfoArrayType& rMajorTicks = rAllTickInfos[0]; + TickInfoArrayType& rMinorTicks = rAllTickInfos[1]; + rMajorTicks.clear(); + rMinorTicks.clear(); + + Date aNull(m_aScale.NullDate); + + Date aDate = aNull + static_cast(::rtl::math::approxFloor(m_aScale.Minimum)); + Date aMaxDate = aNull + static_cast(::rtl::math::approxFloor(m_aScale.Maximum)); + + uno::Reference< chart2::XScaling > xScaling(m_aScale.Scaling); + uno::Reference< chart2::XScaling > xInverseScaling(m_xInverseScaling); + if( bShifted ) + { + xScaling = new DateScaling(aNull,m_aScale.TimeResolution,true/*bShifted*/); + xInverseScaling = xScaling->getInverseScaling(); + } + + //create major date tickinfos + while( aDate<= aMaxDate ) + { + if( bShifted && aDate==aMaxDate ) + break; + + TickInfo aNewTick(xInverseScaling); aNewTick.fScaledTickValue = aDate - aNull; + + if( xInverseScaling.is() ) + aNewTick.fScaledTickValue = xScaling->doScaling(aNewTick.fScaledTickValue); + rMajorTicks.push_back( aNewTick ); + + if(m_aIncrement.MajorTimeInterval.Number<=0) + break; + + //find next major date + switch( m_aIncrement.MajorTimeInterval.TimeUnit ) + { + case DAY: + aDate.AddDays( m_aIncrement.MajorTimeInterval.Number ); + break; + case YEAR: + aDate = DateHelper::GetDateSomeYearsAway( aDate, m_aIncrement.MajorTimeInterval.Number ); + break; + case MONTH: + default: + aDate = DateHelper::GetDateSomeMonthsAway( aDate, m_aIncrement.MajorTimeInterval.Number ); + break; + } + } + + //create minor date tickinfos + aDate = aNull + static_cast(::rtl::math::approxFloor(m_aScale.Minimum)); + while( aDate<= aMaxDate ) + { + if( bShifted && aDate==aMaxDate ) + break; + + TickInfo aNewTick(xInverseScaling); aNewTick.fScaledTickValue = aDate - aNull; + if( xInverseScaling.is() ) + aNewTick.fScaledTickValue = xScaling->doScaling(aNewTick.fScaledTickValue); + rMinorTicks.push_back( aNewTick ); + + if(m_aIncrement.MinorTimeInterval.Number<=0) + break; + + //find next minor date + switch( m_aIncrement.MinorTimeInterval.TimeUnit ) + { + case DAY: + aDate.AddDays( m_aIncrement.MinorTimeInterval.Number ); + break; + case YEAR: + aDate = DateHelper::GetDateSomeYearsAway( aDate, m_aIncrement.MinorTimeInterval.Number ); + break; + case MONTH: + default: + aDate = DateHelper::GetDateSomeMonthsAway( aDate, m_aIncrement.MinorTimeInterval.Number ); + break; + } + } +} + +void DateTickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const +{ + getAllTicks( rAllTickInfos, false ); +} + +void DateTickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const +{ + getAllTicks( rAllTickInfos, true ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks_Dates.hxx b/chart2/source/view/axes/Tickmarks_Dates.hxx new file mode 100644 index 000000000..0a2140192 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Dates.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "Tickmarks.hxx" + +namespace chart +{ + +class DateTickFactory +{ +public: + DateTickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + ~DateTickFactory(); + + void getAllTicks( TickInfoArraysType& rAllTickInfos ) const; + void getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const; + +private: //methods + void getAllTicks( TickInfoArraysType& rAllTickInfos, bool bShifted ) const; + +private: //member + ExplicitScaleData m_aScale; + ExplicitIncrementData m_aIncrement; + css::uno::Reference< css::chart2::XScaling > + m_xInverseScaling; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks_Equidistant.cxx b/chart2/source/view/axes/Tickmarks_Equidistant.cxx new file mode 100644 index 000000000..11778d694 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Equidistant.cxx @@ -0,0 +1,625 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Tickmarks_Equidistant.hxx" +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using namespace ::rtl::math; + +//static +double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be <= fMin and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMin; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMin, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet > fMin ) + { + if( !approxEqual(fRet, fMin) ) + fRet -= rIncrement.Distance; + } + return fRet; +} +//static +double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement ) +{ + //the returned value will be >= fMax and on a Major Tick given by rIncrement + if(rIncrement.Distance<=0.0) + return fMax; + + double fRet = rIncrement.BaseValue + + floor( approxSub( fMax, rIncrement.BaseValue ) + / rIncrement.Distance) + *rIncrement.Distance; + + if( fRet < fMax ) + { + if( !approxEqual(fRet, fMax) ) + fRet += rIncrement.Distance; + } + return fRet; +} + +EquidistantTickFactory::EquidistantTickFactory( + const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement ) + : m_rScale( rScale ) + , m_rIncrement( rIncrement ) +{ + //@todo: make sure that the scale is valid for the scaling + + m_pfCurrentValues.reset( new double[getTickDepth()] ); + + if( m_rScale.Scaling.is() ) + { + m_xInverseScaling = m_rScale.Scaling->getInverseScaling(); + OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return an inverse Scaling" ); + } + + double fMin = m_fScaledVisibleMin = m_rScale.Minimum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin); + if(m_rIncrement.PostEquidistant ) + fMin = m_fScaledVisibleMin; + } + + double fMax = m_fScaledVisibleMax = m_rScale.Maximum; + if( m_xInverseScaling.is() ) + { + m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax); + if(m_rIncrement.PostEquidistant ) + fMax = m_fScaledVisibleMax; + } + + m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement ); + m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement ); + + m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin; + m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax; + if(m_rIncrement.PostEquidistant || !m_xInverseScaling.is()) + return; + + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + + //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax + //it is assumed here, that the original range in the given Scale is valid + if( !std::isfinite(m_fOuterMajorTickBorderMin_Scaled) ) + { + m_fOuterMajorTickBorderMin += m_rIncrement.Distance; + m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin); + } + if( !std::isfinite(m_fOuterMajorTickBorderMax_Scaled) ) + { + m_fOuterMajorTickBorderMax -= m_rIncrement.Distance; + m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax); + } +} + +EquidistantTickFactory::~EquidistantTickFactory() +{ +} + +sal_Int32 EquidistantTickFactory::getTickDepth() const +{ + return static_cast(m_rIncrement.SubIncrements.size()) + 1; +} + +void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const +{ + EquidistantTickIter aIter( rParentTicks, m_rIncrement, nDepth-1 ); + double* pfNextParentTick = aIter.firstValue(); + if(!pfNextParentTick) + return; + double fLastParentTick = *pfNextParentTick; + pfNextParentTick = aIter.nextValue(); + if(!pfNextParentTick) + return; + + sal_Int32 nMaxSubTickCount = getMaxTickCount( nDepth ); + if(!nMaxSubTickCount) + return; + + uno::Sequence< double > aSubTicks(nMaxSubTickCount); + auto pSubTicks = aSubTicks.getArray(); + sal_Int32 nRealSubTickCount = 0; + sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + double* pValue = nullptr; + for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue()) + { + for( sal_Int32 nPartTick = 1; nPartTick(m_rIncrement.SubIncrements.size())>nDepth) + addSubTicks( nDepth+1, rParentTicks ); +} + +sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const +{ + //return the maximum amount of ticks + //possibly open intervals at the two ends of the region are handled as if they were completely visible + //(this is necessary for calculating the sub ticks at the borders correctly) + + if( nDepth >= getTickDepth() ) + return 0; + if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin ) + return 0; + if( m_rIncrement.Distance<=0.0) + return 0; + + double fSub; + if(m_rIncrement.PostEquidistant ) + fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin ); + else + fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum ); + + if (!std::isfinite(fSub)) + return 0; + + double fIntervalCount = fSub / m_rIncrement.Distance; + if (fIntervalCount > std::numeric_limits::max()) + // Interval count too high! Bail out. + return 0; + + sal_Int32 nIntervalCount = static_cast(fIntervalCount); + + nIntervalCount+=3; + for(sal_Int32 nN=0; nN1 ) + nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + + sal_Int32 nTickCount = nIntervalCount; + if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1) + nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1); + + return nTickCount; +} + +double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const +{ + m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance; + + if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax) + { + if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) ) + return nullptr; + } + if(m_pfCurrentValues[0]doScaling( m_pfCurrentValues[0] ); + + return &m_pfCurrentValues[0]; +} + +double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth + , double fStartParentTick, double fNextParentTick ) const +{ + //check validity of arguments + { + //OSL_ENSURE( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick"); + if(fStartParentTick >= fNextParentTick) + return nullptr; + if(nDepth>static_cast(m_rIncrement.SubIncrements.size()) || nDepth<=0) + return nullptr; + + //subticks are only calculated if they are laying between parent ticks: + if(nTick<=0) + return nullptr; + if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount) + return nullptr; + } + + bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant; + + double fAdaptedStartParent = fStartParentTick; + double fAdaptedNextParent = fNextParentTick; + + if( !bPostEquidistant && m_xInverseScaling.is() ) + { + fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick); + fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick); + } + + double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount; + + m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance; + + //return always the value after scaling + if(!bPostEquidistant && m_xInverseScaling.is() ) + m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] ); + + if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) ) + return nullptr; + + return &m_pfCurrentValues[nDepth]; +} + +bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const +{ + if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled) + return false; + if(fScaledValuem_fScaledVisibleMax) + { + if( !approxEqual(fScaledValue,m_fScaledVisibleMax) ) + return false; + } + if(fScaledValue > aAllTicks(nDepthCount); + auto pAllTicks = aAllTicks.getArray(); + pAllTicks[0].realloc(nMaxMajorTickCount); + auto pAllTicks0 = pAllTicks[0].getArray(); + + sal_Int32 nRealMajorTickCount = 0; + for( sal_Int32 nMajorTick=0; nMajorTick1 ) + nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount; + } + uno::Sequence< double >& rTicks = pAllTicks[nDepth]; + sal_Int32 nCount = rTicks.getLength(); + //check lower border + for( nTick=0; nTicknCount-1-nCheckCount && nTick>=0; nTick--) + { + if( !isVisible( rTicks[nTick] ) ) + nInvisibleAtUpperBorder++; + } + //resize sequence + if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder) + continue; + if( !nInvisibleAtLowerBorder ) + rTicks.realloc(nCount-nInvisibleAtUpperBorder); + else + { + sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder; + if(nNewCount<0) + nNewCount=0; + + uno::Sequence< double > aOldTicks(rTicks); + rTicks.realloc(nNewCount); + auto pTicks = rTicks.getArray(); + for(nTick = 0; nTick >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMaxDepth ) + : m_pSimpleTicks(&rTicks) + , m_pInfoTicks(nullptr) + , m_rIncrement(rIncrement) + , m_nMaxDepth(0) + , m_nTickCount(0) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMaxDepth ); +} + +EquidistantTickIter::EquidistantTickIter( TickInfoArraysType& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMaxDepth ) + : m_pSimpleTicks(nullptr) + , m_pInfoTicks(&rTicks) + , m_rIncrement(rIncrement) + , m_nMaxDepth(0) + , m_nTickCount(0) + , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 ) +{ + initIter( nMaxDepth ); +} + +void EquidistantTickIter::initIter( sal_Int32 nMaxDepth ) +{ + m_nMaxDepth = nMaxDepth; + if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth()) + m_nMaxDepth=getMaxDepth(); + + sal_Int32 nDepth = 0; + for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_nTickCount += getTickCount(nDepth); + + if(!m_nTickCount) + return; + + m_pnPositions.reset( new sal_Int32[m_nMaxDepth+1] ); + + m_pnPreParentCount.reset( new sal_Int32[m_nMaxDepth+1] ); + m_pbIntervalFinished.reset( new bool[m_nMaxDepth+1] ); + m_pnPreParentCount[0] = 0; + m_pbIntervalFinished[0] = false; + double fParentValue = getTickValue(0,0); + for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ ) + { + m_pbIntervalFinished[nDepth] = false; + + sal_Int32 nPreParentCount = 0; + sal_Int32 nCount = getTickCount(nDepth); + for(sal_Int32 nN = 0; nNstatic_cast(m_rIncrement.SubIncrements.size()) || nDepth<0) + return 0; + + if(!nDepth) + return m_nTickCount; + + return m_rIncrement.SubIncrements[nDepth-1].IntervalCount; +} + +bool EquidistantTickIter::isAtLastPartTick() +{ + if(!m_nCurrentDepth) + return false; + sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth ); + if(!nIntervalCount || nIntervalCount == 1) + return true; + if( m_pbIntervalFinished[m_nCurrentDepth] ) + return false; + sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1; + if(m_pnPreParentCount[m_nCurrentDepth]) + nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth]; + bool bRet = nPos && nPos % (nIntervalCount-1) == 0; + if(!nPos && !m_pnPreParentCount[m_nCurrentDepth] + && m_pnPositions[m_nCurrentDepth-1]==-1 ) + bRet = true; + return bRet; +} + +bool EquidistantTickIter::gotoFirst() +{ + if( m_nMaxDepth<0 ) + return false; + if( !m_nTickCount ) + return false; + + for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ ) + m_pnPositions[nDepth] = -1; + + m_nCurrentPos = 0; + m_nCurrentDepth = getStartDepth(); + m_pnPositions[m_nCurrentDepth] = 0; + return true; +} + +bool EquidistantTickIter::gotoNext() +{ + if( m_nCurrentPos < 0 ) + return false; + m_nCurrentPos++; + + if( m_nCurrentPos >= m_nTickCount ) + return false; + + if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() ) + { + do + { + m_pbIntervalFinished[m_nCurrentDepth] = true; + m_nCurrentDepth--; + } + while( m_nCurrentDepth && isAtLastPartTick() ); + } + else if( m_nCurrentDepth( + (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] ) + { + return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]]; + } + return nullptr; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/Tickmarks_Equidistant.hxx b/chart2/source/view/axes/Tickmarks_Equidistant.hxx new file mode 100644 index 000000000..bb6553339 --- /dev/null +++ b/chart2/source/view/axes/Tickmarks_Equidistant.hxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "Tickmarks.hxx" +#include + +#include + +namespace chart +{ + +class EquidistantTickIter : public TickIter +{ +public: + EquidistantTickIter( const css::uno::Sequence< css::uno::Sequence< double > >& rTicks + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMaxDepth ); + EquidistantTickIter( TickInfoArraysType& rTickInfos + , const ExplicitIncrementData& rIncrement + , sal_Int32 nMaxDepth ); + virtual ~EquidistantTickIter() override; + + double* firstValue(); + double* nextValue(); + + virtual TickInfo* firstInfo() override; + virtual TickInfo* nextInfo() override; + +private: //methods + sal_Int32 getIntervalCount( sal_Int32 nDepth ); + bool isAtLastPartTick(); + + void initIter( sal_Int32 nMaxDepth ); + sal_Int32 getStartDepth() const; + + bool gotoFirst(); + bool gotoNext(); + + double getTickValue(sal_Int32 nDepth, sal_Int32 nIndex) const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks)[nDepth][nIndex]; + else + { + if ((*m_pInfoTicks)[nDepth].size() <= o3tl::make_unsigned(nIndex)) + return std::numeric_limits::max(); + return (((*m_pInfoTicks)[nDepth])[nIndex]).fScaledTickValue; + } + } + sal_Int32 getTickCount( sal_Int32 nDepth ) const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks)[nDepth].getLength(); + else + return (*m_pInfoTicks)[nDepth].size(); + } + sal_Int32 getMaxDepth() const + { + if(m_pSimpleTicks) + return (*m_pSimpleTicks).getLength()-1; + else + return (*m_pInfoTicks).size()-1; + } + +private: //member + const css::uno::Sequence< css::uno::Sequence< double > >* m_pSimpleTicks; + TickInfoArraysType* m_pInfoTicks; + const ExplicitIncrementData& m_rIncrement; + sal_Int32 m_nMaxDepth; + sal_Int32 m_nTickCount; + std::unique_ptr + m_pnPositions; //current positions in the different sequences + std::unique_ptr + m_pnPreParentCount; //the tickmarks do not start with a major tick always, + //the PreParentCount states for each depth how many subtickmarks are available in front of the first parent tickmark + std::unique_ptr + m_pbIntervalFinished; + sal_Int32 m_nCurrentDepth; + sal_Int32 m_nCurrentPos; + double m_fCurrentValue; +}; + +class EquidistantTickFactory +{ +public: + EquidistantTickFactory( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + ~EquidistantTickFactory(); + + void getAllTicks( TickInfoArraysType& rAllTickInfos ) const; + void getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const; + + static double getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement ); + static double getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement ); + +private: //methods + void addSubTicks( sal_Int32 nDepth, + css::uno::Sequence< css::uno::Sequence< double > >& rParentTicks ) const; + double* getMajorTick( sal_Int32 nTick ) const; + double* getMinorTick( sal_Int32 nTick, sal_Int32 nDepth + , double fStartParentTick, double fNextParentTick ) const; + sal_Int32 getMaxTickCount( sal_Int32 nDepth ) const; + sal_Int32 getTickDepth() const; + + bool isVisible( double fValue ) const; + bool isWithinOuterBorder( double fScaledValue ) const; //all within the outer major tick marks + +private: //member + ExplicitScaleData m_rScale; + ExplicitIncrementData m_rIncrement; + css::uno::Reference< css::chart2::XScaling > m_xInverseScaling; + + //minimum and maximum of the visible range after scaling + double m_fScaledVisibleMin; + double m_fScaledVisibleMax; + + std::unique_ptr + m_pfCurrentValues; + //major-tick positions that may lay outside the visible range but complete partly visible intervals at the borders + double m_fOuterMajorTickBorderMin; + double m_fOuterMajorTickBorderMax; + double m_fOuterMajorTickBorderMin_Scaled; + double m_fOuterMajorTickBorderMax_Scaled; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisBase.cxx b/chart2/source/view/axes/VAxisBase.cxx new file mode 100644 index 000000000..ace362a9b --- /dev/null +++ b/chart2/source/view/axes/VAxisBase.cxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VAxisBase.hxx" +#include +#include +#include "Tickmarks.hxx" +#include +#include +#include + +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VAxisBase::VAxisBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_xNumberFormatsSupplier( xNumberFormatsSupplier ) + , m_aAxisProperties( rAxisProperties ) + , m_bUseTextLabels( false ) + , m_bReCreateAllTickInfos( true ) + , m_bRecordMaximumTextSize(false) + , m_nMaximumTextWidthSoFar(0) + , m_nMaximumTextHeightSoFar(0) +{ +} + +VAxisBase::~VAxisBase() +{ +} + +void VAxisBase::initAxisLabelProperties( const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels ) +{ + m_aAxisLabelProperties.m_aFontReferenceSize = rFontReferenceSize; + m_aAxisLabelProperties.m_aMaximumSpaceForLabels = rMaximumSpaceForLabels; + + if( !m_aAxisProperties.m_bDisplayLabels ) + return; + + if( m_aAxisProperties.m_nAxisType==AxisType::SERIES ) + { + if( m_aAxisProperties.m_xAxisTextProvider.is() ) + m_aTextLabels = m_aAxisProperties.m_xAxisTextProvider->getTextualData(); + + m_bUseTextLabels = true; + if( m_aTextLabels.getLength() == 1 ) + { + //don't show a single series name + m_aAxisProperties.m_bDisplayLabels = false; + return; + } + } + else if( m_aAxisProperties.m_nAxisType==AxisType::CATEGORY ) + { + if( m_aAxisProperties.m_pExplicitCategoriesProvider ) + m_aTextLabels = m_aAxisProperties.m_pExplicitCategoriesProvider->getSimpleCategories(); + + m_bUseTextLabels = true; + } + + m_aAxisLabelProperties.m_nNumberFormatKey = m_aAxisProperties.m_nNumberFormatKey; + m_aAxisLabelProperties.init(m_aAxisProperties.m_xAxisModel); + if( m_aAxisProperties.m_bComplexCategories && m_aAxisProperties.m_nAxisType == AxisType::CATEGORY ) + m_aAxisLabelProperties.m_eStaggering = AxisLabelStaggering::SideBySide; +} + +bool VAxisBase::isDateAxis() const +{ + return m_aScale.AxisType == AxisType::DATE; +} +bool VAxisBase::isComplexCategoryAxis() const +{ + return m_aAxisProperties.m_bComplexCategories && m_bUseTextLabels; +} + +void VAxisBase::recordMaximumTextSize( SvxShape& xShape, double fRotationAngleDegree ) +{ + if( m_bRecordMaximumTextSize ) + { + awt::Size aSize( ShapeFactory::getSizeAfterRotation( + xShape, fRotationAngleDegree ) ); + + m_nMaximumTextWidthSoFar = std::max( m_nMaximumTextWidthSoFar, aSize.Width ); + m_nMaximumTextHeightSoFar = std::max( m_nMaximumTextHeightSoFar, aSize.Height ); + } +} + +sal_Int32 VAxisBase::estimateMaximumAutoMainIncrementCount() +{ + return 10; +} + +void VAxisBase::setExtraLinePositionAtOtherAxis( double fCrossingAt ) +{ + m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis = fCrossingAt; +} + +sal_Int32 VAxisBase::getDimensionCount() const +{ + return m_nDimension; +} + +bool VAxisBase::isAnythingToDraw() +{ + if( !m_aAxisProperties.m_xAxisModel.is() ) + return false; + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"Axis is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return false; + + if( m_aAxisProperties.m_xAxisModel.is() ) + { + bool bShow = false; + m_aAxisProperties.m_xAxisModel->getPropertyValue( "Show" ) >>= bShow; + if( !bShow ) + return false; + } + return true; +} + +void VAxisBase::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) +{ + m_bReCreateAllTickInfos = true; + m_aScale = rScale; + m_aIncrement = rIncrement; +} + +void VAxisBase::createAllTickInfos( TickInfoArraysType& rAllTickInfos ) +{ + std::unique_ptr< TickFactory > apTickFactory( createTickFactory() ); + if( m_aScale.m_bShiftedCategoryPosition ) + apTickFactory->getAllTicksShifted( rAllTickInfos ); + else + apTickFactory->getAllTicks( rAllTickInfos ); +} + +bool VAxisBase::prepareShapeCreation() +{ + //returns true if all is ready for further shape creation and any shapes need to be created + if( !isAnythingToDraw() ) + return false; + + if( m_bReCreateAllTickInfos ) + { + //create all scaled tickmark values + removeTextShapesFromTicks(); + + createAllTickInfos(m_aAllTickInfos); + m_bReCreateAllTickInfos = false; + } + + if( m_xGroupShape_Shapes.is() ) + return true; + + //create named group shape + m_xGroupShape_Shapes = createGroupShape( m_xLogicTarget, m_nDimension==2 ? m_aCID : ""); + + if( m_aAxisProperties.m_bDisplayLabels ) + m_xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget, m_aCID ); + + return true; +} + +size_t VAxisBase::getIndexOfLongestLabel( const uno::Sequence& rLabels ) +{ + sal_Int32 nRet = 0; + sal_Int32 nLength = 0; + sal_Int32 nN = 0; + for( nN=0; nN nLength ) + { + nLength = rLabels[nN].getLength(); + nRet = nN; + } + } + + assert(nRet >= 0); + return nRet; +} + +void VAxisBase::removeTextShapesFromTicks() +{ + if( !m_xTextTarget.is() ) + return; + + for (auto & tickInfos : m_aAllTickInfos) + { + for (auto & tickInfo : tickInfos) + { + if(tickInfo.xTextShape.is()) + { + m_xTextTarget->remove(tickInfo.xTextShape); + tickInfo.xTextShape = nullptr; + } + } + } +} + +void VAxisBase::updateUnscaledValuesAtTicks( TickIter& rIter ) +{ + Reference< XScaling > xInverseScaling; + if( m_aScale.Scaling.is() ) + xInverseScaling = m_aScale.Scaling->getInverseScaling(); + + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo; pTickInfo = rIter.nextInfo() ) + { + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisBase.hxx b/chart2/source/view/axes/VAxisBase.hxx new file mode 100644 index 000000000..31badb749 --- /dev/null +++ b/chart2/source/view/axes/VAxisBase.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VAxisOrGridBase.hxx" +#include "VAxisProperties.hxx" +#include "Tickmarks.hxx" + +namespace com::sun::star::util { class XNumberFormatsSupplier; } + +namespace chart +{ + +class VAxisBase : public VAxisOrGridBase +{ +public: + VAxisBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier ); + virtual ~VAxisBase() override; + + /** + * Return the number of dimensions the diagram has. 2 for x and y, and 3 + * for x, y, and z. + */ + sal_Int32 getDimensionCount() const; + + virtual void createMaximumLabels()=0; + virtual void createLabels()=0; + virtual void updatePositions()=0; + + virtual bool isAnythingToDraw(); + virtual void initAxisLabelProperties( + const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels ); + + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) override; + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount(); + virtual void createAllTickInfos( TickInfoArraysType& rAllTickInfos ); + + void setExtraLinePositionAtOtherAxis( double fCrossingAt ); + +protected: //methods + static size_t getIndexOfLongestLabel( const css::uno::Sequence& rLabels ); + void removeTextShapesFromTicks(); + void updateUnscaledValuesAtTicks( TickIter& rIter ); + + virtual bool prepareShapeCreation(); + void recordMaximumTextSize( SvxShape& xShape, double fRotationAngleDegree ); + + bool isDateAxis() const; + bool isComplexCategoryAxis() const; + +protected: //member + css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormatsSupplier; + AxisProperties m_aAxisProperties; + AxisLabelProperties m_aAxisLabelProperties; + css::uno::Sequence< OUString > m_aTextLabels; + bool m_bUseTextLabels; + + rtl::Reference< SvxShapeGroupAnyD > m_xGroupShape_Shapes; + rtl::Reference< SvxShapeGroupAnyD > m_xTextTarget; + + /** + * This typically consists of 2 TickInfo vectors (i.e. the outer vector + * has 2 child vector elements) for normal axis. The first vector + * corresponds with the major ticks while the second corresponds with the + * minor ticks. + * + * It may have more than 2 TickInfo vectors for complex category axis + * which has multi-level axis labels. + */ + TickInfoArraysType m_aAllTickInfos; + bool m_bReCreateAllTickInfos; + + bool m_bRecordMaximumTextSize; + sal_Int32 m_nMaximumTextWidthSoFar; + sal_Int32 m_nMaximumTextHeightSoFar; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisOrGridBase.cxx b/chart2/source/view/axes/VAxisOrGridBase.cxx new file mode 100644 index 000000000..290f3a368 --- /dev/null +++ b/chart2/source/view/axes/VAxisOrGridBase.cxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VAxisOrGridBase.hxx" +#include +#include "Tickmarks.hxx" + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VAxisOrGridBase::VAxisOrGridBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) + : PlotterBase( nDimensionCount ) + , m_nDimensionIndex( nDimensionIndex ) + , m_eLeftWallPos(CuboidPlanePosition_Left) + , m_eBackWallPos(CuboidPlanePosition_Back) + , m_eBottomPos(CuboidPlanePosition_Bottom) +{ +} + +VAxisOrGridBase::~VAxisOrGridBase() +{ +} + +void VAxisOrGridBase::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) +{ + m_aScale = rScale; + m_aIncrement = rIncrement; +} + +void VAxisOrGridBase::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix ) +{ + m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix); + PlotterBase::setTransformationSceneToScreen( rMatrix); +} + +void VAxisOrGridBase::set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ) +{ + m_eLeftWallPos = eLeftWallPos; + m_eBackWallPos = eBackWallPos; + m_eBottomPos = eBottomPos; +} + +TickFactory* VAxisOrGridBase::createTickFactory() +{ + return new TickFactory( m_aScale, m_aIncrement ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisOrGridBase.hxx b/chart2/source/view/axes/VAxisOrGridBase.hxx new file mode 100644 index 000000000..1defc154a --- /dev/null +++ b/chart2/source/view/axes/VAxisOrGridBase.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +#include + +namespace com::sun::star::drawing { struct HomogenMatrix; } + +namespace chart +{ + +class TickFactory; + +class VAxisOrGridBase : public PlotterBase +{ +public: + VAxisOrGridBase( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + virtual ~VAxisOrGridBase() override; + + virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix ) override; + /// @throws css::uno::RuntimeException + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ); + void set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ); + + virtual TickFactory* createTickFactory(); + +protected: //member + ExplicitScaleData m_aScale; + ExplicitIncrementData m_aIncrement; + sal_Int32 m_nDimensionIndex; + + ::basegfx::B3DHomMatrix m_aMatrixScreenToScene; + + CuboidPlanePosition m_eLeftWallPos; + CuboidPlanePosition m_eBackWallPos; + CuboidPlanePosition m_eBottomPos; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisProperties.cxx b/chart2/source/view/axes/VAxisProperties.cxx new file mode 100644 index 000000000..f8f177936 --- /dev/null +++ b/chart2/source/view/axes/VAxisProperties.cxx @@ -0,0 +1,392 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VAxisProperties.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart { + +AxisLabelAlignment::AxisLabelAlignment() : + mfLabelDirection(1.0), + mfInnerTickDirection(1.0), + meAlignment(LABEL_ALIGN_RIGHT_TOP) {} + +static sal_Int32 lcl_calcTickLengthForDepth(sal_Int32 nDepth,sal_Int32 nTickmarkStyle) +{ + sal_Int32 const nWidth = AXIS2D_TICKLENGTH; //@maybefuturetodo this length could be offered by the model + double fPercent = 1.0; + switch(nDepth) + { + case 0: + fPercent = 1.0; + break; + case 1: + fPercent = 0.75;//percentage like in the old chart + break; + case 2: + fPercent = 0.5; + break; + default: + fPercent = 0.3; + break; + } + if(nTickmarkStyle==3)//inner and outer tickmarks + fPercent*=2.0; + return static_cast(nWidth*fPercent); +} + +static double lcl_getTickOffset(sal_Int32 nLength,sal_Int32 nTickmarkStyle) +{ + double fPercent = 0.0; //0<=fPercent<=1 + //0.0: completely inner + //1.0: completely outer + //0.5: half and half + + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + switch(nTickmarkStyle) + { + case 1: + fPercent = 0.0; + break; + case 2: + fPercent = 1.0; + break; + default: + fPercent = 0.5; + break; + } + return fPercent*nLength; +} + +TickmarkProperties AxisProperties::makeTickmarkProperties( + sal_Int32 nDepth ) const +{ + /* + nTickmarkStyle: + 1: inner tickmarks + 2: outer tickmarks + 3: inner and outer tickmarks + */ + sal_Int32 nTickmarkStyle = 1; + if(nDepth==0) + { + nTickmarkStyle = m_nMajorTickmarks; + if(!nTickmarkStyle) + { + //create major tickmarks as if they were minor tickmarks + nDepth = 1; + nTickmarkStyle = m_nMinorTickmarks; + } + } + else if( nDepth==1) + { + nTickmarkStyle = m_nMinorTickmarks; + } + + if (maLabelAlignment.mfInnerTickDirection == 0.0) + { + if( nTickmarkStyle != 0 ) + nTickmarkStyle = 3; //inner and outer tickmarks + } + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = lcl_calcTickLengthForDepth(nDepth,nTickmarkStyle); + aTickmarkProperties.RelativePos = static_cast(lcl_getTickOffset(aTickmarkProperties.Length,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = makeLinePropertiesForDepth(); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::makeTickmarkPropertiesForComplexCategories( + sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis ) const +{ + sal_Int32 nTickmarkStyle = (maLabelAlignment.mfLabelDirection == maLabelAlignment.mfInnerTickDirection) ? 2/*outside*/ : 1/*inside*/; + + TickmarkProperties aTickmarkProperties; + aTickmarkProperties.Length = nTickLength;// + nTextLevel*( lcl_calcTickLengthForDepth(0,nTickmarkStyle) ); + aTickmarkProperties.RelativePos = static_cast(lcl_getTickOffset(aTickmarkProperties.Length+nTickStartDistanceToAxis,nTickmarkStyle)); + aTickmarkProperties.aLineProperties = makeLinePropertiesForDepth(); + return aTickmarkProperties; +} + +TickmarkProperties AxisProperties::getBiggestTickmarkProperties() +{ + TickmarkProperties aTickmarkProperties; + sal_Int32 nTickmarkStyle = 3;//inner and outer tickmarks + aTickmarkProperties.Length = lcl_calcTickLengthForDepth( 0/*nDepth*/,nTickmarkStyle ); + aTickmarkProperties.RelativePos = static_cast( lcl_getTickOffset( aTickmarkProperties.Length, nTickmarkStyle ) ); + return aTickmarkProperties; +} + +AxisProperties::AxisProperties( const rtl::Reference< Axis >& xAxisModel + , ExplicitCategoriesProvider* pExplicitCategoriesProvider ) + : m_xAxisModel(xAxisModel) + , m_nDimensionIndex(0) + , m_bIsMainAxis(true) + , m_bSwapXAndY(false) + , m_eCrossoverType( css::chart::ChartAxisPosition_ZERO ) + , m_eLabelPos( css::chart::ChartAxisLabelPosition_NEAR_AXIS ) + , m_eTickmarkPos( css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ) + , m_bCrossingAxisHasReverseDirection(false) + , m_bCrossingAxisIsCategoryAxes(false) + , m_bDisplayLabels( true ) + , m_bTryStaggeringFirst( false ) + , m_nNumberFormatKey(0) + , m_nMajorTickmarks(1) + , m_nMinorTickmarks(1) + , m_nAxisType(AxisType::REALNUMBER) + , m_bComplexCategories(false) + , m_pExplicitCategoriesProvider(pExplicitCategoriesProvider) + , m_bLimitSpaceForLabels(false) +{ +} + +static LabelAlignment lcl_getLabelAlignmentForZAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +static LabelAlignment lcl_getLabelAlignmentForYAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_RIGHT ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_LEFT; + return aRet; +} + +static LabelAlignment lcl_getLabelAlignmentForXAxis( const AxisProperties& rAxisProperties ) +{ + LabelAlignment aRet( LABEL_ALIGN_BOTTOM ); + if (rAxisProperties.maLabelAlignment.mfLabelDirection < 0) + aRet = LABEL_ALIGN_TOP; + return aRet; +} + +void AxisProperties::initAxisPositioning( const uno::Reference< beans::XPropertySet >& xAxisProp ) +{ + if( !xAxisProp.is() ) + return; + try + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + xAxisProp->getPropertyValue("CrossoverPosition") >>= m_eCrossoverType; + if( m_eCrossoverType == css::chart::ChartAxisPosition_VALUE ) + { + double fValue = 0.0; + xAxisProp->getPropertyValue("CrossoverValue") >>= fValue; + + if( m_bCrossingAxisIsCategoryAxes ) + fValue = ::rtl::math::round(fValue); + m_pfMainLinePositionAtOtherAxis = fValue; + } + else if( m_eCrossoverType == css::chart::ChartAxisPosition_ZERO ) + m_pfMainLinePositionAtOtherAxis = 0.0; + + xAxisProp->getPropertyValue("LabelPosition") >>= m_eLabelPos; + xAxisProp->getPropertyValue("MarkPosition") >>= m_eTickmarkPos; + } + else + { + m_eCrossoverType = css::chart::ChartAxisPosition_START; + if( m_bIsMainAxis == m_bCrossingAxisHasReverseDirection ) + m_eCrossoverType = css::chart::ChartAxisPosition_END; + m_eLabelPos = css::chart::ChartAxisLabelPosition_NEAR_AXIS; + m_eTickmarkPos = css::chart::ChartAxisMarkPosition_AT_LABELS; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void AxisProperties::init( bool bCartesian ) +{ + if( !m_xAxisModel.is() ) + return; + + if( m_nDimensionIndex<2 ) + initAxisPositioning( m_xAxisModel ); + + ScaleData aScaleData = m_xAxisModel->getScaleData(); + if( m_nDimensionIndex==0 ) + AxisHelper::checkDateAxis( aScaleData, m_pExplicitCategoriesProvider, bCartesian ); + m_nAxisType = aScaleData.AxisType; + + if( bCartesian ) + { + if( m_nDimensionIndex == 0 && m_nAxisType == AxisType::CATEGORY + && m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->hasComplexCategories() ) + m_bComplexCategories = true; + + if( m_eCrossoverType == css::chart::ChartAxisPosition_END ) + maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? 1.0 : -1.0; + else + maLabelAlignment.mfInnerTickDirection = m_bCrossingAxisHasReverseDirection ? -1.0 : 1.0; + + if( m_eLabelPos == css::chart::ChartAxisLabelPosition_NEAR_AXIS ) + maLabelAlignment.mfLabelDirection = maLabelAlignment.mfInnerTickDirection; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE ) + maLabelAlignment.mfLabelDirection = -maLabelAlignment.mfInnerTickDirection; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START ) + maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? -1 : 1; + else if( m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + maLabelAlignment.mfLabelDirection = m_bCrossingAxisHasReverseDirection ? 1 : -1; + + if( m_nDimensionIndex==2 ) + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForZAxis(*this); + else + { + bool bIsYAxisPosition = (m_nDimensionIndex==1 && !m_bSwapXAndY) + || (m_nDimensionIndex==0 && m_bSwapXAndY); + if( bIsYAxisPosition ) + { + maLabelAlignment.mfLabelDirection *= -1.0; + maLabelAlignment.mfInnerTickDirection *= -1.0; + + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForYAxis(*this); + } + else + maLabelAlignment.meAlignment = lcl_getLabelAlignmentForXAxis(*this); + } + } + + try + { + //init LineProperties + m_aLineProperties.initFromPropertySet( m_xAxisModel ); + + //init display labels + m_xAxisModel->getPropertyValue( "DisplayLabels" ) >>= m_bDisplayLabels; + + // Init layout strategy hint for axis labels. + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + m_xAxisModel->getPropertyValue( "TryStaggeringFirst" ) >>= m_bTryStaggeringFirst; + + //init TickmarkProperties + m_xAxisModel->getPropertyValue( "MajorTickmarks" ) >>= m_nMajorTickmarks; + m_xAxisModel->getPropertyValue( "MinorTickmarks" ) >>= m_nMinorTickmarks; + + sal_Int32 nMaxDepth = 0; + if(m_nMinorTickmarks!=0) + nMaxDepth=2; + else if(m_nMajorTickmarks!=0) + nMaxDepth=1; + + m_aTickmarkPropertiesList.clear(); + for( sal_Int32 nDepth=0; nDepth& xAxisModel ) +{ + if(!xAxisModel.is()) + return; + + try + { + xAxisModel->getPropertyValue( "TextBreak" ) >>= m_bLineBreakAllowed; + xAxisModel->getPropertyValue( "TextOverlap" ) >>= m_bOverlapAllowed; + xAxisModel->getPropertyValue( "StackCharacters" ) >>= m_bStackCharacters; + xAxisModel->getPropertyValue( "TextRotation" ) >>= m_fRotationAngleDegree; + + css::chart::ChartAxisArrangeOrderType eArrangeOrder; + xAxisModel->getPropertyValue( "ArrangeOrder" ) >>= eArrangeOrder; + switch(eArrangeOrder) + { + case css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE: + m_eStaggering = AxisLabelStaggering::SideBySide; + break; + case css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN: + m_eStaggering = AxisLabelStaggering::StaggerEven; + break; + case css::chart::ChartAxisArrangeOrderType_STAGGER_ODD: + m_eStaggering = AxisLabelStaggering::StaggerOdd; + break; + default: + m_eStaggering = AxisLabelStaggering::StaggerAuto; + break; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +bool AxisLabelProperties::isStaggered() const +{ + return ( m_eStaggering == AxisLabelStaggering::StaggerOdd || m_eStaggering == AxisLabelStaggering::StaggerEven ); +} + +void AxisLabelProperties::autoRotate45() +{ + m_fRotationAngleDegree = 45; + m_bLineBreakAllowed = false; + m_eStaggering = AxisLabelStaggering::SideBySide; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VAxisProperties.hxx b/chart2/source/view/axes/VAxisProperties.hxx new file mode 100644 index 000000000..4370ccbb6 --- /dev/null +++ b/chart2/source/view/axes/VAxisProperties.hxx @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "TickmarkProperties.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chart { class ExplicitCategoriesProvider; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2::data { class XTextualDataSequence; } + +namespace chart +{ +class Axis; + +//These properties describe how a couple of labels are arranged one to another. +//The couple can contain all labels for all tickmark depth or just the labels for one single depth or +//the labels from a coherent range of tick depths (e.g. the major and first minor tickmarks should be handled together). +//... only allow side by side for different tick depth +enum class AxisLabelStaggering +{ + SideBySide + , StaggerEven + , StaggerOdd + , StaggerAuto +}; + +struct AxisLabelProperties final +{ + AxisLabelProperties(); + + css::awt::Size m_aFontReferenceSize;//reference size to calculate the font height + css::awt::Rectangle m_aMaximumSpaceForLabels;//Labels need to be clipped in order to fit into this rectangle + + sal_Int32 m_nNumberFormatKey; + + AxisLabelStaggering m_eStaggering; + + bool m_bLineBreakAllowed; + bool m_bOverlapAllowed; + + bool m_bStackCharacters; + double m_fRotationAngleDegree; + + sal_Int32 m_nRhythm; //show only each nth label with n==nRhythm + + //methods: + void init( const rtl::Reference< ::chart::Axis >& xAxisModel ); + + bool isStaggered() const; + + void autoRotate45(); +}; + +struct AxisLabelAlignment +{ + double mfLabelDirection; /// which direction the labels are to be drawn. + double mfInnerTickDirection; /// which direction the inner tickmarks are to be drawn. + + LabelAlignment meAlignment; + + AxisLabelAlignment(); +}; + +struct AxisProperties final +{ + rtl::Reference<::chart::Axis> m_xAxisModel; + + sal_Int32 m_nDimensionIndex; + bool m_bIsMainAxis;//not secondary axis + bool m_bSwapXAndY; + + css::chart::ChartAxisPosition m_eCrossoverType; + css::chart::ChartAxisLabelPosition m_eLabelPos; + css::chart::ChartAxisMarkPosition m_eTickmarkPos; + + std::optional m_pfMainLinePositionAtOtherAxis; + std::optional m_pfExrtaLinePositionAtOtherAxis; + + bool m_bCrossingAxisHasReverseDirection; + bool m_bCrossingAxisIsCategoryAxes; + + AxisLabelAlignment maLabelAlignment; + + bool m_bDisplayLabels; + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + // So the default value of this flag for new documents is `false`. + bool m_bTryStaggeringFirst; + + sal_Int32 m_nNumberFormatKey; + + /* + 0: no tickmarks 1: inner tickmarks + 2: outer tickmarks 3: inner and outer tickmarks + */ + sal_Int32 m_nMajorTickmarks; + sal_Int32 m_nMinorTickmarks; + std::vector m_aTickmarkPropertiesList; + + VLineProperties m_aLineProperties; + + //for category axes -> + sal_Int32 m_nAxisType;//REALNUMBER, CATEGORY etc. type css::chart2::AxisType + bool m_bComplexCategories; + ExplicitCategoriesProvider* m_pExplicitCategoriesProvider;/*no ownership here*/ + css::uno::Reference m_xAxisTextProvider; //for categories or series names + //<- category axes + + bool m_bLimitSpaceForLabels; + + //methods: + + AxisProperties( const rtl::Reference< ::chart::Axis >& xAxisModel + , ExplicitCategoriesProvider* pExplicitCategoriesProvider ); + + void init(bool bCartesian=false);//init from model data (m_xAxisModel) + + void initAxisPositioning( const css::uno::Reference< css::beans::XPropertySet >& xAxisProp ); + + static TickmarkProperties getBiggestTickmarkProperties(); + TickmarkProperties makeTickmarkPropertiesForComplexCategories( sal_Int32 nTickLength, sal_Int32 nTickStartDistanceToAxis ) const; + +private: + AxisProperties() = delete; + + TickmarkProperties makeTickmarkProperties( sal_Int32 nDepth ) const; + //@todo get this from somewhere; maybe for each subincrement + //so far the model does not offer different settings for each tick depth + const VLineProperties& makeLinePropertiesForDepth() const { return m_aLineProperties; } +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianAxis.cxx b/chart2/source/view/axes/VCartesianAxis.cxx new file mode 100644 index 000000000..0ea37f9a7 --- /dev/null +++ b/chart2/source/view/axes/VCartesianAxis.cxx @@ -0,0 +1,1971 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VCartesianAxis.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "Tickmarks_Equidistant.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; +using ::basegfx::B2DVector; +using ::basegfx::B2DPolygon; +using ::basegfx::B2DPolyPolygon; + +namespace chart { + +VCartesianAxis::VCartesianAxis( const AxisProperties& rAxisProperties + , const Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , PlottingPositionHelper* pPosHelper )//takes ownership + : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier ) +{ + if( pPosHelper ) + m_pPosHelper = pPosHelper; + else + m_pPosHelper = new PlottingPositionHelper(); +} + +VCartesianAxis::~VCartesianAxis() +{ + delete m_pPosHelper; + m_pPosHelper = nullptr; +} + +static void lcl_ResizeTextShapeToFitAvailableSpace( SvxShapeText& rShape2DText, + const AxisLabelProperties& rAxisLabelProperties, + const OUString& rLabel, + const tNameSequence& rPropNames, + const tAnySequence& rPropValues, + const bool bIsHorizontalAxis ) +{ + bool bTextHorizontal = rAxisLabelProperties.m_fRotationAngleDegree != 0.0; + bool bIsDirectionVertical = bIsHorizontalAxis && bTextHorizontal; + const sal_Int32 nFullSize = bIsDirectionVertical ? rAxisLabelProperties.m_aFontReferenceSize.Height : rAxisLabelProperties.m_aFontReferenceSize.Width; + + if( !nFullSize || !rLabel.getLength() ) + return; + + const sal_Int32 nAvgCharWidth = rShape2DText.getSize().Width / rLabel.getLength(); + + sal_Int32 nMaxLabelsSize = bIsDirectionVertical ? rAxisLabelProperties.m_aMaximumSpaceForLabels.Height : rAxisLabelProperties.m_aMaximumSpaceForLabels.Width; + + awt::Size aSizeAfterRotation = ShapeFactory::getSizeAfterRotation(rShape2DText, rAxisLabelProperties.m_fRotationAngleDegree); + + const sal_Int32 nTextSize = bIsDirectionVertical ? aSizeAfterRotation.Height : aSizeAfterRotation.Width; + + if( !nAvgCharWidth ) + return; + + static const OUStringLiteral sDots = u"..."; + const sal_Int32 nCharsToRemove = ( nTextSize - nMaxLabelsSize ) / nAvgCharWidth + 1; + sal_Int32 nNewLen = rLabel.getLength() - nCharsToRemove - sDots.getLength(); + // Prevent from showing only dots + if (nNewLen < 0) + nNewLen = ( rLabel.getLength() >= sDots.getLength() ) ? sDots.getLength() : rLabel.getLength(); + + bool bCrop = nCharsToRemove > 0; + if( !bCrop ) + return; + + OUString aNewLabel = rLabel.copy( 0, nNewLen ); + if( nNewLen > sDots.getLength() ) + aNewLabel += sDots; + rShape2DText.setString( aNewLabel ); + + PropertyMapper::setMultiProperties( rPropNames, rPropValues, rShape2DText ); +} + +static rtl::Reference createSingleLabel( + const rtl::Reference< SvxShapeGroupAnyD >& xTarget + , const awt::Point& rAnchorScreenPosition2D + , const OUString& rLabel + , const AxisLabelProperties& rAxisLabelProperties + , const AxisProperties& rAxisProperties + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const bool bIsHorizontalAxis + ) +{ + if(rLabel.isEmpty()) + return nullptr; + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(-basegfx::deg2rad(rAxisLabelProperties.m_fRotationAngleDegree)); + uno::Any aATransformation = ShapeFactory::makeTransformation( rAnchorScreenPosition2D, fRotationAnglePi ); + OUString aLabel = ShapeFactory::getStackedString( rLabel, rAxisLabelProperties.m_bStackCharacters ); + + rtl::Reference xShape2DText = + ShapeFactory::createText( xTarget, aLabel, rPropNames, rPropValues, aATransformation ); + + if( rAxisProperties.m_bLimitSpaceForLabels ) + lcl_ResizeTextShapeToFitAvailableSpace(*xShape2DText, rAxisLabelProperties, aLabel, rPropNames, rPropValues, bIsHorizontalAxis); + + LabelPositionHelper::correctPositionForRotation( xShape2DText + , rAxisProperties.maLabelAlignment.meAlignment, rAxisLabelProperties.m_fRotationAngleDegree, rAxisProperties.m_bComplexCategories ); + + return xShape2DText; +} + +static bool lcl_doesShapeOverlapWithTickmark( SvxShape& rShape + , double fRotationAngleDegree + , const basegfx::B2DVector& rTickScreenPosition ) +{ + ::basegfx::B2IRectangle aShapeRect = BaseGFXHelper::makeRectangle(rShape.getPosition(), ShapeFactory::getSizeAfterRotation( rShape, fRotationAngleDegree )); + + basegfx::B2IVector aPosition( + static_cast( rTickScreenPosition.getX() ) + , static_cast( rTickScreenPosition.getY() ) ); + return aShapeRect.isInside(aPosition); +} + +static void lcl_getRotatedPolygon( B2DPolygon &aPoly, const ::basegfx::B2DRectangle &aRect, const awt::Point &aPos, const double fRotationAngleDegree ) +{ + aPoly = basegfx::utils::createPolygonFromRect( aRect ); + + // For rotating the rectangle we use the opposite angle, + // since `B2DHomMatrix` class used for + // representing the transformation, performs rotations in the positive + // direction (from the X axis to the Y axis). However since the coordinate + // system used by the chart has the Y-axis pointing downward, a rotation in + // the positive direction means a clockwise rotation. On the contrary text + // labels are rotated counterclockwise. + // The rotation is performed around the top-left vertex of the rectangle + // which is then moved to its final position by using the top-left + // vertex of the text label bounding box (aPos) as the translation vector. + ::basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(-basegfx::deg2rad(fRotationAngleDegree)); + aMatrix.translate( aPos.X, aPos.Y); + aPoly.transform( aMatrix ); +} + +static bool doesOverlap( const rtl::Reference& xShape1 + , const rtl::Reference& xShape2 + , double fRotationAngleDegree ) +{ + if( !xShape1.is() || !xShape2.is() ) + return false; + + ::basegfx::B2DRectangle aRect1( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape1->getSize())); + ::basegfx::B2DRectangle aRect2( BaseGFXHelper::makeRectangle( awt::Point(0,0), xShape2->getSize())); + + B2DPolygon aPoly1; + B2DPolygon aPoly2; + lcl_getRotatedPolygon( aPoly1, aRect1, xShape1->getPosition(), fRotationAngleDegree ); + lcl_getRotatedPolygon( aPoly2, aRect2, xShape2->getPosition(), fRotationAngleDegree ); + + B2DPolyPolygon aPolyPoly1, aPolyPoly2; + aPolyPoly1.append( aPoly1 ); + aPolyPoly2.append( aPoly2 ); + B2DPolyPolygon overlapPoly = ::basegfx::utils::clipPolyPolygonOnPolyPolygon( aPolyPoly1, aPolyPoly2, true, false ); + + return (overlapPoly.count() > 0); +} + +static void removeShapesAtWrongRhythm( TickIter& rIter + , sal_Int32 nCorrectRhythm + , sal_Int32 nMaxTickToCheck + , const rtl::Reference< SvxShapeGroupAnyD >& xTarget ) +{ + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo && nTick <= nMaxTickToCheck + ; pTickInfo = rIter.nextInfo(), nTick++ ) + { + //remove labels which does not fit into the rhythm + if( nTick%nCorrectRhythm != 0) + { + if(pTickInfo->xTextShape.is()) + { + xTarget->remove(pTickInfo->xTextShape); + pTickInfo->xTextShape = nullptr; + } + } + } +} + +namespace { + +/** + * If the labels are staggered and bInnerLine is true we iterate through + * only those labels that are closer to the diagram. + * + * If the labels are staggered and bInnerLine is false we iterate through + * only those that are farther from the diagram. + * + * If the labels are not staggered we iterate through all labels. + */ +class LabelIterator : public TickIter +{ +public: + LabelIterator( TickInfoArrayType& rTickInfoVector + , const AxisLabelStaggering eAxisLabelStaggering + , bool bInnerLine ); + + virtual TickInfo* firstInfo() override; + virtual TickInfo* nextInfo() override; + +private: //member + PureTickIter m_aPureTickIter; + const AxisLabelStaggering m_eAxisLabelStaggering; + bool m_bInnerLine; +}; + +} + +LabelIterator::LabelIterator( TickInfoArrayType& rTickInfoVector + , const AxisLabelStaggering eAxisLabelStaggering + , bool bInnerLine ) + : m_aPureTickIter( rTickInfoVector ) + , m_eAxisLabelStaggering(eAxisLabelStaggering) + , m_bInnerLine(bInnerLine) +{ +} + +TickInfo* LabelIterator::firstInfo() +{ + TickInfo* pTickInfo = m_aPureTickIter.firstInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ) + pTickInfo = m_aPureTickIter.nextInfo(); + if(!pTickInfo) + return nullptr; + if( (m_eAxisLabelStaggering==AxisLabelStaggering::StaggerEven && m_bInnerLine) + || + (m_eAxisLabelStaggering==AxisLabelStaggering::StaggerOdd && !m_bInnerLine) + ) + { + //skip first label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + } + if(!pTickInfo) + return nullptr; + return pTickInfo; +} + +TickInfo* LabelIterator::nextInfo() +{ + TickInfo* pTickInfo = nullptr; + //get next label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + + if( m_eAxisLabelStaggering==AxisLabelStaggering::StaggerEven + || m_eAxisLabelStaggering==AxisLabelStaggering::StaggerOdd ) + { + //skip one label + do + pTickInfo = m_aPureTickIter.nextInfo(); + while( pTickInfo && !pTickInfo->xTextShape.is() ); + } + return pTickInfo; +} + +static B2DVector lcl_getLabelsDistance( TickIter& rIter, const B2DVector& rDistanceTickToText, double fRotationAngleDegree ) +{ + //calculates the height or width of a line of labels + //thus a following line of labels can be shifted for that distance + + B2DVector aRet(0,0); + + sal_Int32 nDistanceTickToText = static_cast( rDistanceTickToText.getLength() ); + if( nDistanceTickToText==0.0) + return aRet; + + B2DVector aStaggerDirection(rDistanceTickToText); + aStaggerDirection.normalize(); + + sal_Int32 nDistance=0; + rtl::Reference< SvxShapeText > xShape2DText; + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo + ; pTickInfo = rIter.nextInfo() ) + { + xShape2DText = pTickInfo->xTextShape; + if( xShape2DText.is() ) + { + awt::Size aSize = ShapeFactory::getSizeAfterRotation( *xShape2DText, fRotationAngleDegree ); + if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY())) + nDistance = std::max(nDistance,aSize.Width); + else + nDistance = std::max(nDistance,aSize.Height); + } + } + + aRet = aStaggerDirection*nDistance; + + //add extra distance for vertical distance + if(fabs(aStaggerDirection.getX())>fabs(aStaggerDirection.getY())) + aRet += rDistanceTickToText; + + return aRet; +} + +static void lcl_shiftLabels( TickIter& rIter, const B2DVector& rStaggerDistance ) +{ + if(rStaggerDistance.getLength()==0.0) + return; + for( TickInfo* pTickInfo = rIter.firstInfo() + ; pTickInfo + ; pTickInfo = rIter.nextInfo() ) + { + const rtl::Reference& xShape2DText = pTickInfo->xTextShape; + if( xShape2DText.is() ) + { + awt::Point aPos = xShape2DText->getPosition(); + aPos.X += static_cast(rStaggerDistance.getX()); + aPos.Y += static_cast(rStaggerDistance.getY()); + xShape2DText->setPosition( aPos ); + } + } +} + +static bool lcl_hasWordBreak( const rtl::Reference& xShape ) +{ + if (!xShape.is()) + return false; + + SvxTextEditSource* pTextEditSource = dynamic_cast(xShape->GetEditSource()); + if (!pTextEditSource) + return false; + + pTextEditSource->UpdateOutliner(); + SvxTextForwarder* pTextForwarder = pTextEditSource->GetTextForwarder(); + if (!pTextForwarder) + return false; + + sal_Int32 nParaCount = pTextForwarder->GetParagraphCount(); + for ( sal_Int32 nPara = 0; nPara < nParaCount; ++nPara ) + { + sal_Int32 nLineCount = pTextForwarder->GetLineCount( nPara ); + for ( sal_Int32 nLine = 0; nLine < nLineCount; ++nLine ) + { + sal_Int32 nLineStart = 0; + sal_Int32 nLineEnd = 0; + pTextForwarder->GetLineBoundaries( nLineStart, nLineEnd, nPara, nLine ); + assert(nLineStart >= 0); + sal_Int32 nWordStart = 0; + sal_Int32 nWordEnd = 0; + if ( pTextForwarder->GetWordIndices( nPara, nLineStart, nWordStart, nWordEnd ) && + ( nWordStart != nLineStart ) ) + { + return true; + } + } + } + + return false; +} + +static OUString getTextLabelString( + const FixedNumberFormatter& rFixedNumberFormatter, const uno::Sequence* pCategories, + const TickInfo* pTickInfo, bool bComplexCat, Color& rExtraColor, bool& rHasExtraColor ) +{ + if (pCategories) + { + // This is a normal category axis. Get the label string from the + // label string array. + sal_Int32 nIndex = static_cast(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndexgetLength() ) + return (*pCategories)[nIndex]; + + return OUString(); + } + else if (bComplexCat) + { + // This is a complex category axis. The label is stored in the tick. + return pTickInfo->aText; + } + + // This is a numeric axis. Format the original tick value per number format. + return rFixedNumberFormatter.getFormattedString(pTickInfo->getUnscaledTickValue(), rExtraColor, rHasExtraColor); +} + +static void getAxisLabelProperties( + tNameSequence& rPropNames, tAnySequence& rPropValues, const AxisProperties& rAxisProp, + const AxisLabelProperties& rAxisLabelProp, + sal_Int32 nLimitedSpaceForText, bool bLimitedHeight ) +{ + Reference xProps(rAxisProp.m_xAxisModel); + + PropertyMapper::getTextLabelMultiPropertyLists( + xProps, rPropNames, rPropValues, false, nLimitedSpaceForText, bLimitedHeight, false); + + LabelPositionHelper::doDynamicFontResize( + rPropValues, rPropNames, xProps, rAxisLabelProp.m_aFontReferenceSize); + + LabelPositionHelper::changeTextAdjustment( + rPropValues, rPropNames, rAxisProp.maLabelAlignment.meAlignment); +} + +namespace { + +/** + * Iterate through only 3 ticks including the one that has the longest text + * length. When the first tick has the longest text, it iterates through + * the first 3 ticks. Otherwise it iterates through 3 ticks such that the + * 2nd tick is the one with the longest text. + */ +class MaxLabelTickIter : public TickIter +{ +public: + MaxLabelTickIter( TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex ); + + virtual TickInfo* firstInfo() override; + virtual TickInfo* nextInfo() override; + +private: + TickInfoArrayType& m_rTickInfoVector; + std::vector m_aValidIndices; + size_t m_nCurrentIndex; +}; + +} + +MaxLabelTickIter::MaxLabelTickIter( + TickInfoArrayType& rTickInfoVector, size_t nLongestLabelIndex ) : + m_rTickInfoVector(rTickInfoVector), m_nCurrentIndex(0) +{ + assert(!rTickInfoVector.empty()); // should be checked by the caller. + assert(nLongestLabelIndex < rTickInfoVector.size()); + + size_t nMaxIndex = m_rTickInfoVector.size()-1; + if (nLongestLabelIndex >= nMaxIndex-1) + nLongestLabelIndex = 0; + + if (nLongestLabelIndex > 0) + m_aValidIndices.push_back(nLongestLabelIndex-1); + + m_aValidIndices.push_back(nLongestLabelIndex); + + while (m_aValidIndices.size() < 3) + { + ++nLongestLabelIndex; + if (nLongestLabelIndex > nMaxIndex) + break; + + m_aValidIndices.push_back(nLongestLabelIndex); + } +} + +TickInfo* MaxLabelTickIter::firstInfo() +{ + m_nCurrentIndex = 0; + if (m_nCurrentIndex < m_aValidIndices.size()) + return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; + return nullptr; +} + +TickInfo* MaxLabelTickIter::nextInfo() +{ + m_nCurrentIndex++; + if (m_nCurrentIndex < m_aValidIndices.size()) + return &m_rTickInfoVector[m_aValidIndices[m_nCurrentIndex]]; + return nullptr; +} + +bool VCartesianAxis::isBreakOfLabelsAllowed( + const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis) const +{ + if( m_aTextLabels.getLength() > 100 ) + return false; + if( !rAxisLabelProperties.m_bLineBreakAllowed ) + return false; + if( rAxisLabelProperties.m_bStackCharacters ) + return false; + //no break for value axis + if( !m_bUseTextLabels ) + return false; + if( !( rAxisLabelProperties.m_fRotationAngleDegree == 0.0 || + rAxisLabelProperties.m_fRotationAngleDegree == 90.0 || + rAxisLabelProperties.m_fRotationAngleDegree == 270.0 ) ) + return false; + //no break for complex vertical category axis + if( !m_aAxisProperties.m_bSwapXAndY ) + return bIsHorizontalAxis; + else if( m_aAxisProperties.m_bSwapXAndY && !m_aAxisProperties.m_bComplexCategories ) + return bIsVerticalAxis; + else + return false; +} +namespace{ + +bool canAutoAdjustLabelPlacement( + const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis) +{ + // joined prerequisite checks for auto rotate and auto stagger + if( rAxisLabelProperties.m_bOverlapAllowed ) + return false; + if( rAxisLabelProperties.m_bLineBreakAllowed ) // auto line break may conflict with... + return false; + if( rAxisLabelProperties.m_fRotationAngleDegree != 0.0 ) + return false; + // automatic adjusting labels only works for + // horizontal axis with horizontal text + // or vertical axis with vertical text + if( bIsHorizontalAxis ) + return !rAxisLabelProperties.m_bStackCharacters; + if( bIsVerticalAxis ) + return rAxisLabelProperties.m_bStackCharacters; + return false; +} + +bool isAutoStaggeringOfLabelsAllowed( + const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis ) +{ + if( rAxisLabelProperties.m_eStaggering != AxisLabelStaggering::StaggerAuto ) + return false; + return canAutoAdjustLabelPlacement(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis); +} + +// make clear that we check for auto rotation prerequisites +const auto& isAutoRotatingOfLabelsAllowed = canAutoAdjustLabelPlacement; + +} // namespace +void VCartesianAxis::createAllTickInfosFromComplexCategories( TickInfoArraysType& rAllTickInfos, bool bShiftedPosition ) +{ + //no minor tickmarks will be generated! + //order is: inner labels first , outer labels last (that is different to all other TickIter cases) + if(!bShiftedPosition) + { + rAllTickInfos.clear(); + sal_Int32 nLevel=0; + sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + for( ; nLevel* pComplexCategories = + m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel); + + if (!pComplexCategories) + continue; + + sal_Int32 nCatIndex = 0; + + for (auto const& complexCategory : *pComplexCategories) + { + TickInfo aTickInfo(nullptr); + sal_Int32 nCount = complexCategory.Count; + if( nCatIndex + 1.0 + nCount >= m_aScale.Maximum ) + { + nCount = static_cast(m_aScale.Maximum - 1.0 - nCatIndex); + if( nCount <= 0 ) + nCount = 1; + } + aTickInfo.fScaledTickValue = nCatIndex + 1.0 + nCount/2.0; + aTickInfo.nFactorForLimitedTextWidth = nCount; + aTickInfo.aText = complexCategory.Text; + aTickInfoVector.push_back(aTickInfo); + nCatIndex += nCount; + if( nCatIndex + 1.0 >= m_aScale.Maximum ) + break; + } + rAllTickInfos.push_back(aTickInfoVector); + } + } + else //bShiftedPosition==false + { + rAllTickInfos.clear(); + sal_Int32 nLevel=0; + sal_Int32 nLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + for( ; nLevel* pComplexCategories = + m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoriesByLevel(nLevel); + sal_Int32 nCatIndex = 0; + if (pComplexCategories) + { + for (auto const& complexCategory : *pComplexCategories) + { + TickInfo aTickInfo(nullptr); + aTickInfo.fScaledTickValue = nCatIndex + 1.0; + aTickInfoVector.push_back(aTickInfo); + nCatIndex += complexCategory.Count; + if( nCatIndex + 1.0 > m_aScale.Maximum ) + break; + } + } + + //fill up with single ticks until maximum scale + while( nCatIndex + 1.0 < m_aScale.Maximum ) + { + TickInfo aTickInfo(nullptr); + aTickInfo.fScaledTickValue = nCatIndex + 1.0; + aTickInfoVector.push_back(aTickInfo); + nCatIndex ++; + if( nLevel>0 ) + break; + } + //add an additional tick at the end + { + TickInfo aTickInfo(nullptr); + aTickInfo.fScaledTickValue = m_aScale.Maximum; + aTickInfoVector.push_back(aTickInfo); + } + rAllTickInfos.push_back(aTickInfoVector); + } + } +} + +void VCartesianAxis::createAllTickInfos( TickInfoArraysType& rAllTickInfos ) +{ + if( isComplexCategoryAxis() ) + createAllTickInfosFromComplexCategories( rAllTickInfos, false ); + else + VAxisBase::createAllTickInfos(rAllTickInfos); +} + +TickIter* VCartesianAxis::createLabelTickIterator( sal_Int32 nTextLevel ) +{ + if( nTextLevel>=0 && o3tl::make_unsigned(nTextLevel) < m_aAllTickInfos.size() ) + return new PureTickIter( m_aAllTickInfos[nTextLevel] ); + return nullptr; +} + +TickIter* VCartesianAxis::createMaximumLabelTickIterator( sal_Int32 nTextLevel ) +{ + if( isComplexCategoryAxis() || isDateAxis() ) + { + return createLabelTickIterator( nTextLevel ); //mmmm maybe todo: create less than all texts here + } + else + { + if(nTextLevel==0) + { + if( !m_aAllTickInfos.empty() ) + { + size_t nLongestLabelIndex = m_bUseTextLabels ? getIndexOfLongestLabel(m_aTextLabels) : 0; + if (nLongestLabelIndex >= m_aAllTickInfos[0].size()) + return nullptr; + + return new MaxLabelTickIter( m_aAllTickInfos[0], nLongestLabelIndex ); + } + } + } + return nullptr; +} + +sal_Int32 VCartesianAxis::getTextLevelCount() const +{ + sal_Int32 nTextLevelCount = 1; + if( isComplexCategoryAxis() ) + nTextLevelCount = m_aAxisProperties.m_pExplicitCategoriesProvider->getCategoryLevelCount(); + return nTextLevelCount; +} + +bool VCartesianAxis::createTextShapes( + const rtl::Reference< SvxShapeGroupAnyD >& xTarget, TickIter& rTickIter, + AxisLabelProperties& rAxisLabelProperties, TickFactory2D const * pTickFactory, + sal_Int32 nScreenDistanceBetweenTicks ) +{ + const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); + const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); + + if( m_bUseTextLabels && (m_aAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_NEAR_AXIS || + m_aAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START)) + { + if (bIsHorizontalAxis) + { + rAxisLabelProperties.m_aMaximumSpaceForLabels.Y = pTickFactory->getXaxisStartPos().getY(); + rAxisLabelProperties.m_aMaximumSpaceForLabels.Height = rAxisLabelProperties.m_aFontReferenceSize.Height - rAxisLabelProperties.m_aMaximumSpaceForLabels.Y; + } + else if (bIsVerticalAxis) + { + rAxisLabelProperties.m_aMaximumSpaceForLabels.X = 0; + rAxisLabelProperties.m_aMaximumSpaceForLabels.Width = pTickFactory->getXaxisStartPos().getX(); + } + } + + bool bIsBreakOfLabelsAllowed = isBreakOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ); + if (!bIsBreakOfLabelsAllowed && + !isAutoStaggeringOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) && + !rAxisLabelProperties.isStaggered()) + { + return createTextShapesSimple(xTarget, rTickIter, rAxisLabelProperties, pTickFactory); + } + + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.m_nNumberFormatKey ); + + bool bIsStaggered = rAxisLabelProperties.isStaggered(); + B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true); + sal_Int32 nLimitedSpaceForText = -1; + + if (bIsBreakOfLabelsAllowed) + { + if (!m_aAxisProperties.m_bLimitSpaceForLabels) + { + basegfx::B2DVector nDeltaVector = pTickFactory->getXaxisEndPos() - pTickFactory->getXaxisStartPos(); + nLimitedSpaceForText = nDeltaVector.getX(); + } + if (nScreenDistanceBetweenTicks > 0) + nLimitedSpaceForText = nScreenDistanceBetweenTicks; + + if( bIsStaggered ) + nLimitedSpaceForText *= 2; + + if( nLimitedSpaceForText > 0 ) + { //reduce space for a small amount to have a visible distance between the labels: + sal_Int32 nReduce = (nLimitedSpaceForText*5)/100; + if(!nReduce) + nReduce = 1; + nLimitedSpaceForText -= nReduce; + } + + // recalculate the nLimitedSpaceForText in case of 90 and 270 degree if the text break is true + if ( rAxisLabelProperties.m_fRotationAngleDegree == 90.0 || rAxisLabelProperties.m_fRotationAngleDegree == 270.0 ) + { + nLimitedSpaceForText = rAxisLabelProperties.m_aMaximumSpaceForLabels.Height; + m_aAxisProperties.m_bLimitSpaceForLabels = false; + } + + // recalculate the nLimitedSpaceForText in case of vertical category axis if the text break is true + if ( m_aAxisProperties.m_bSwapXAndY && bIsVerticalAxis && rAxisLabelProperties.m_fRotationAngleDegree == 0.0 ) + { + nLimitedSpaceForText = pTickFactory->getXaxisStartPos().getX(); + m_aAxisProperties.m_bLimitSpaceForLabels = false; + } + } + + // Stores an array of text label strings in case of a normal + // (non-complex) category axis. + const uno::Sequence* pCategories = nullptr; + if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories ) + pCategories = &m_aTextLabels; + + bool bLimitedHeight; + if( !m_aAxisProperties.m_bSwapXAndY ) + bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + else + bLimitedHeight = fabs(aTextToTickDistance.getX()) < fabs(aTextToTickDistance.getY()); + //prepare properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, nLimitedSpaceForText, bLimitedHeight); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,u"CharColor"); + Color nColor = COL_AUTO; + if(pColorAny) + *pColorAny >>= nColor; + + uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight); + + const TickInfo* pPreviousVisibleTickInfo = nullptr; + const TickInfo* pPREPreviousVisibleTickInfo = nullptr; + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + const TickInfo* pLastVisibleNeighbourTickInfo = bIsStaggered ? + pPREPreviousVisibleTickInfo : pPreviousVisibleTickInfo; + + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.m_nRhythm != 0 ) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.m_bOverlapAllowed ) + { + // Overlapping is not allowed. If the label overlaps with its + // neighboring label, try increasing the tick interval (or rhythm + // as it's called) and start over. + + if( lcl_doesShapeOverlapWithTickmark( *pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.m_fRotationAngleDegree + , pTickInfo->aTickScreenPosition ) ) + { + // This tick overlaps with its neighbor. Try to stagger (if + // auto staggering is allowed) to avoid overlapping. + + bool bOverlapsAfterAutoStagger = true; + if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) ) + { + bIsStaggered = true; + rAxisLabelProperties.m_eStaggering = AxisLabelStaggering::StaggerEven; + pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo; + if( !pLastVisibleNeighbourTickInfo || + !lcl_doesShapeOverlapWithTickmark( *pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.m_fRotationAngleDegree + , pTickInfo->aTickScreenPosition ) ) + bOverlapsAfterAutoStagger = false; + } + + if (bOverlapsAfterAutoStagger) + { + // Still overlaps with its neighbor even after staggering. + // Increment the visible tick intervals (if that's + // allowed) and start over. + + rAxisLabelProperties.m_nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.m_nRhythm, nTick, xTarget ); + return false; + } + } + } + + bool bHasExtraColor=false; + Color nExtraColor; + + OUString aLabel = getTextLabelString( + aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(), + nExtraColor, bHasExtraColor); + + if(pColorAny) + *pColorAny <<= bHasExtraColor?nExtraColor:nColor; + if(pLimitedSpaceAny) + *pLimitedSpaceAny <<= sal_Int32(nLimitedSpaceForText*pTickInfo->nFactorForLimitedTextWidth); + + B2DVector aTickScreenPos2D = pTickInfo->aTickScreenPosition; + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast(aTickScreenPos2D.getX()) + ,static_cast(aTickScreenPos2D.getY())); + + //create single label + if(!pTickInfo->xTextShape.is()) + { + pTickInfo->xTextShape = createSingleLabel( xTarget + , aAnchorScreenPosition2D, aLabel + , rAxisLabelProperties, m_aAxisProperties + , aPropNames, aPropValues, bIsHorizontalAxis ); + } + if(!pTickInfo->xTextShape.is()) + continue; + + recordMaximumTextSize( *pTickInfo->xTextShape, rAxisLabelProperties.m_fRotationAngleDegree ); + + // Label has multiple lines and the words are broken + if (nLimitedSpaceForText > 0 + && !rAxisLabelProperties.m_bOverlapAllowed + && rAxisLabelProperties.m_fRotationAngleDegree == 0.0 + && nTick > 0 + && lcl_hasWordBreak(pTickInfo->xTextShape)) + { + // Label has multiple lines and belongs to a complex category + // axis. Rotate 90 degrees to try to avoid overlaps. + if ( m_aAxisProperties.m_bComplexCategories ) + { + rAxisLabelProperties.m_fRotationAngleDegree = 90; + } + rAxisLabelProperties.m_bLineBreakAllowed = false; + m_aAxisLabelProperties.m_fRotationAngleDegree = rAxisLabelProperties.m_fRotationAngleDegree; + removeTextShapesFromTicks(); + return false; + } + + //if NO OVERLAP -> remove overlapping shapes + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.m_bOverlapAllowed ) + { + // Check if the label still overlaps with its neighbor. + if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.m_fRotationAngleDegree ) ) + { + // It overlaps. Check if staggering helps. + bool bOverlapsAfterAutoStagger = true; + if( !bIsStaggered && isAutoStaggeringOfLabelsAllowed( rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis ) ) + { + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + if( !isAutoRotatingOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) + || m_aAxisProperties.m_bTryStaggeringFirst ) + { + bIsStaggered = true; + rAxisLabelProperties.m_eStaggering = AxisLabelStaggering::StaggerEven; + pLastVisibleNeighbourTickInfo = pPREPreviousVisibleTickInfo; + if( !pLastVisibleNeighbourTickInfo || + !lcl_doesShapeOverlapWithTickmark( *pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.m_fRotationAngleDegree + , pTickInfo->aTickScreenPosition ) ) + bOverlapsAfterAutoStagger = false; + } + } + + if (bOverlapsAfterAutoStagger) + { + // Staggering didn't solve the overlap. + if( isAutoRotatingOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) ) + { + // Try auto-rotating the labels at 45 degrees and + // start over. This rotation angle will be stored for + // all future text shape creation runs. + // The nRhythm parameter is reset to 1 since the layout + // used for text labels is changed. + rAxisLabelProperties.autoRotate45(); + m_aAxisLabelProperties.m_fRotationAngleDegree = rAxisLabelProperties.m_fRotationAngleDegree; // Store it for future runs. + removeTextShapesFromTicks(); + rAxisLabelProperties.m_nRhythm = 1; + return false; + } + + // Try incrementing the tick interval and start over. + rAxisLabelProperties.m_nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.m_nRhythm, nTick, xTarget ); + return false; + } + } + } + + pPREPreviousVisibleTickInfo = pPreviousVisibleTickInfo; + pPreviousVisibleTickInfo = pTickInfo; + } + return true; +} + +bool VCartesianAxis::createTextShapesSimple( + const rtl::Reference< SvxShapeGroupAnyD >& xTarget, TickIter& rTickIter, + AxisLabelProperties& rAxisLabelProperties, TickFactory2D const * pTickFactory ) +{ + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.m_nNumberFormatKey ); + + const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis(); + const bool bIsVerticalAxis = pTickFactory->isVerticalAxis(); + B2DVector aTextToTickDistance = pTickFactory->getDistanceAxisTickToText(m_aAxisProperties, true); + + // Stores an array of text label strings in case of a normal + // (non-complex) category axis. + const uno::Sequence* pCategories = nullptr; + if( m_bUseTextLabels && !m_aAxisProperties.m_bComplexCategories ) + pCategories = &m_aTextLabels; + + bool bLimitedHeight = fabs(aTextToTickDistance.getX()) > fabs(aTextToTickDistance.getY()); + + //prepare properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + getAxisLabelProperties(aPropNames, aPropValues, m_aAxisProperties, rAxisLabelProperties, -1, bLimitedHeight); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,u"CharColor"); + Color nColor = COL_AUTO; + if(pColorAny) + *pColorAny >>= nColor; + + uno::Any* pLimitedSpaceAny = PropertyMapper::getValuePointerForLimitedSpace(aPropValues,aPropNames,bLimitedHeight); + + const TickInfo* pPreviousVisibleTickInfo = nullptr; + sal_Int32 nTick = 0; + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + const TickInfo* pLastVisibleNeighbourTickInfo = pPreviousVisibleTickInfo; + + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.m_nRhythm != 0 ) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.m_bOverlapAllowed ) + { + // Overlapping is not allowed. If the label overlaps with its + // neighboring label, try increasing the tick interval (or rhythm + // as it's called) and start over. + + if( lcl_doesShapeOverlapWithTickmark( *pLastVisibleNeighbourTickInfo->xTextShape + , rAxisLabelProperties.m_fRotationAngleDegree + , pTickInfo->aTickScreenPosition ) ) + { + // This tick overlaps with its neighbor. Increment the visible + // tick intervals (if that's allowed) and start over. + + rAxisLabelProperties.m_nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.m_nRhythm, nTick, xTarget ); + return false; + } + } + + bool bHasExtraColor=false; + Color nExtraColor; + + OUString aLabel = getTextLabelString( + aFixedNumberFormatter, pCategories, pTickInfo, isComplexCategoryAxis(), + nExtraColor, bHasExtraColor); + + if(pColorAny) + *pColorAny <<= bHasExtraColor?nExtraColor:nColor; + if(pLimitedSpaceAny) + *pLimitedSpaceAny <<= sal_Int32(-1*pTickInfo->nFactorForLimitedTextWidth); + + B2DVector aTickScreenPos2D = pTickInfo->aTickScreenPosition; + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast(aTickScreenPos2D.getX()) + ,static_cast(aTickScreenPos2D.getY())); + + //create single label + if(!pTickInfo->xTextShape.is()) + pTickInfo->xTextShape = createSingleLabel( xTarget + , aAnchorScreenPosition2D, aLabel + , rAxisLabelProperties, m_aAxisProperties + , aPropNames, aPropValues, bIsHorizontalAxis ); + if(!pTickInfo->xTextShape.is()) + continue; + + recordMaximumTextSize( *pTickInfo->xTextShape, rAxisLabelProperties.m_fRotationAngleDegree ); + + //if NO OVERLAP -> remove overlapping shapes + if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.m_bOverlapAllowed ) + { + // Check if the label still overlaps with its neighbor. + if( doesOverlap( pLastVisibleNeighbourTickInfo->xTextShape, pTickInfo->xTextShape, rAxisLabelProperties.m_fRotationAngleDegree ) ) + { + // It overlaps. + if( isAutoRotatingOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) ) + { + // Try auto-rotating the labels at 45 degrees and + // start over. This rotation angle will be stored for + // all future text shape creation runs. + // The nRhythm parameter is reset to 1 since the layout + // used for text labels is changed. + rAxisLabelProperties.autoRotate45(); + m_aAxisLabelProperties.m_fRotationAngleDegree = rAxisLabelProperties.m_fRotationAngleDegree; // Store it for future runs. + removeTextShapesFromTicks(); + rAxisLabelProperties.m_nRhythm = 1; + return false; + } + + // Try incrementing the tick interval and start over. + rAxisLabelProperties.m_nRhythm++; + removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.m_nRhythm, nTick, xTarget ); + return false; + } + } + + pPreviousVisibleTickInfo = pTickInfo; + } + return true; +} + +double VCartesianAxis::getAxisIntersectionValue() const +{ + if (m_aAxisProperties.m_pfMainLinePositionAtOtherAxis) + return *m_aAxisProperties.m_pfMainLinePositionAtOtherAxis; + + double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + + return (m_aAxisProperties.m_eCrossoverType == css::chart::ChartAxisPosition_END) ? fMax : fMin; +} + +double VCartesianAxis::getLabelLineIntersectionValue() const +{ + if (m_aAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_START) + return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + + if (m_aAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END) + return (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + + return getAxisIntersectionValue(); +} + +double VCartesianAxis::getExtraLineIntersectionValue() const +{ + if( !m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis ) + return std::numeric_limits::quiet_NaN(); + + double fMin = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMinY(); + double fMax = (m_nDimensionIndex==1) ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMaxY(); + + if( *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis <= fMin + || *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis >= fMax ) + return std::numeric_limits::quiet_NaN(); + + return *m_aAxisProperties.m_pfExrtaLinePositionAtOtherAxis; +} + +B2DVector VCartesianAxis::getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const +{ + B2DVector aRet(0,0); + + if( m_pPosHelper ) + { + drawing::Position3D aScenePos = m_pPosHelper->transformLogicToScene( fLogicX, fLogicY, fLogicZ, true ); + if(m_nDimension==3) + { + if (m_xLogicTarget.is()) + { + tPropertyNameMap aDummyPropertyNameMap; + rtl::Reference xShape3DAnchor = ShapeFactory::createCube( m_xLogicTarget + , aScenePos,drawing::Direction3D(1,1,1), 0, nullptr, aDummyPropertyNameMap); + awt::Point a2DPos = xShape3DAnchor->getPosition(); //get 2D position from xShape3DAnchor + m_xLogicTarget->remove(xShape3DAnchor); + aRet.setX( a2DPos.X ); + aRet.setY( a2DPos.Y ); + } + else + { + OSL_FAIL("cannot calculate screen position in VCartesianAxis::getScreenPosition"); + } + } + else + { + aRet.setX( aScenePos.PositionX ); + aRet.setY( aScenePos.PositionY ); + } + } + + return aRet; +} + +VCartesianAxis::ScreenPosAndLogicPos VCartesianAxis::getScreenPosAndLogicPos( double fLogicX_, double fLogicY_, double fLogicZ_ ) const +{ + ScreenPosAndLogicPos aRet; + aRet.fLogicX = fLogicX_; + aRet.fLogicY = fLogicY_; + aRet.fLogicZ = fLogicZ_; + aRet.aScreenPos = getScreenPosition( fLogicX_, fLogicY_, fLogicZ_ ); + return aRet; +} + +typedef std::vector< VCartesianAxis::ScreenPosAndLogicPos > tScreenPosAndLogicPosList; + +namespace { + +struct lcl_LessXPos +{ + bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 ) + { + return ( rPos1.aScreenPos.getX() < rPos2.aScreenPos.getX() ); + } +}; + +struct lcl_GreaterYPos +{ + bool operator() ( const VCartesianAxis::ScreenPosAndLogicPos& rPos1, const VCartesianAxis::ScreenPosAndLogicPos& rPos2 ) + { + return ( rPos1.aScreenPos.getY() > rPos2.aScreenPos.getY() ); + } +}; + +} + +void VCartesianAxis::get2DAxisMainLine( + B2DVector& rStart, B2DVector& rEnd, AxisLabelAlignment& rAlignment, double fCrossesOtherAxis ) const +{ + //m_aAxisProperties might get updated and changed here because + // the label alignment and inner direction sign depends exactly of the choice of the axis line position which is made here in this method + + double const fMinX = m_pPosHelper->getLogicMinX(); + double const fMinY = m_pPosHelper->getLogicMinY(); + double const fMinZ = m_pPosHelper->getLogicMinZ(); + double const fMaxX = m_pPosHelper->getLogicMaxX(); + double const fMaxY = m_pPosHelper->getLogicMaxY(); + double const fMaxZ = m_pPosHelper->getLogicMaxZ(); + + double fXOnXPlane = fMinX; + double fXOther = fMaxX; + int nDifferentValue = !m_pPosHelper->isMathematicalOrientationX() ? -1 : 1; + if( !m_pPosHelper->isSwapXAndY() ) + nDifferentValue *= (m_eLeftWallPos != CuboidPlanePosition_Left) ? -1 : 1; + else + nDifferentValue *= (m_eBottomPos != CuboidPlanePosition_Bottom) ? -1 : 1; + if( nDifferentValue<0 ) + { + fXOnXPlane = fMaxX; + fXOther = fMinX; + } + + double fYOnYPlane = fMinY; + double fYOther = fMaxY; + nDifferentValue = !m_pPosHelper->isMathematicalOrientationY() ? -1 : 1; + if( !m_pPosHelper->isSwapXAndY() ) + nDifferentValue *= (m_eBottomPos != CuboidPlanePosition_Bottom) ? -1 : 1; + else + nDifferentValue *= (m_eLeftWallPos != CuboidPlanePosition_Left) ? -1 : 1; + if( nDifferentValue<0 ) + { + fYOnYPlane = fMaxY; + fYOther = fMinY; + } + + double fZOnZPlane = fMaxZ; + double fZOther = fMinZ; + nDifferentValue = !m_pPosHelper->isMathematicalOrientationZ() ? -1 : 1; + nDifferentValue *= (m_eBackWallPos != CuboidPlanePosition_Back) ? -1 : 1; + if( nDifferentValue<0 ) + { + fZOnZPlane = fMinZ; + fZOther = fMaxZ; + } + + double fXStart = fMinX; + double fYStart = fMinY; + double fZStart = fMinZ; + double fXEnd; + double fYEnd; + double fZEnd = fZStart; + + if( m_nDimensionIndex==0 ) //x-axis + { + if( fCrossesOtherAxis < fMinY ) + fCrossesOtherAxis = fMinY; + else if( fCrossesOtherAxis > fMaxY ) + fCrossesOtherAxis = fMaxY; + + fYStart = fYEnd = fCrossesOtherAxis; + fXEnd=m_pPosHelper->getLogicMaxX(); + + if(m_nDimension==3) + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( ::rtl::math::approxEqual( fYOther, fYStart) ) + fZStart = fZEnd = fZOnZPlane; + else + fZStart = fZEnd = fZOther; + } + else + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList { getScreenPosAndLogicPos( fMinX, fYOnYPlane, fZOther ), getScreenPosAndLogicPos( fMinX, fYOther, fZOnZPlane ) }; + + if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + rAlignment.meAlignment = LABEL_ALIGN_LEFT; + //choose most left positions + std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() ); + rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0; + } + else + { + rAlignment.meAlignment = LABEL_ALIGN_BOTTOM; + //choose most bottom positions + std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0; + } + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + fYStart = fYEnd = aBestPos.fLogicY; + fZStart = fZEnd = aBestPos.fLogicZ; + if( !m_pPosHelper->isMathematicalOrientationX() ) + rAlignment.mfLabelDirection *= -1.0; + } + }//end 3D x axis + } + else if( m_nDimensionIndex==1 ) //y-axis + { + if( fCrossesOtherAxis < fMinX ) + fCrossesOtherAxis = fMinX; + else if( fCrossesOtherAxis > fMaxX ) + fCrossesOtherAxis = fMaxX; + + fXStart = fXEnd = fCrossesOtherAxis; + fYEnd=m_pPosHelper->getLogicMaxY(); + + if(m_nDimension==3) + { + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( ::rtl::math::approxEqual( fXOther, fXStart) ) + fZStart = fZEnd = fZOnZPlane; + else + fZStart = fZEnd = fZOther; + } + else + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList { getScreenPosAndLogicPos( fXOnXPlane, fMinY, fZOther ), getScreenPosAndLogicPos( fXOther, fMinY, fZOnZPlane ) }; + + if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + rAlignment.meAlignment = LABEL_ALIGN_LEFT; + //choose most left positions + std::sort( aPosList.begin(), aPosList.end(), lcl_LessXPos() ); + rAlignment.mfLabelDirection = (fDeltaY < 0) ? -1.0 : 1.0; + } + else + { + rAlignment.meAlignment = LABEL_ALIGN_BOTTOM; + //choose most bottom positions + std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0; + } + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + fXStart = fXEnd = aBestPos.fLogicX; + fZStart = fZEnd = aBestPos.fLogicZ; + if( !m_pPosHelper->isMathematicalOrientationY() ) + rAlignment.mfLabelDirection *= -1.0; + } + }//end 3D y axis + } + else //z-axis + { + fZEnd = m_pPosHelper->getLogicMaxZ(); + if( AxisHelper::isAxisPositioningEnabled() ) + { + if( !m_aAxisProperties.m_bSwapXAndY ) + { + if( fCrossesOtherAxis < fMinY ) + fCrossesOtherAxis = fMinY; + else if( fCrossesOtherAxis > fMaxY ) + fCrossesOtherAxis = fMaxY; + fYStart = fYEnd = fCrossesOtherAxis; + + if( ::rtl::math::approxEqual( fYOther, fYStart) ) + fXStart = fXEnd = fXOnXPlane; + else + fXStart = fXEnd = fXOther; + } + else + { + if( fCrossesOtherAxis < fMinX ) + fCrossesOtherAxis = fMinX; + else if( fCrossesOtherAxis > fMaxX ) + fCrossesOtherAxis = fMaxX; + fXStart = fXEnd = fCrossesOtherAxis; + + if( ::rtl::math::approxEqual( fXOther, fXStart) ) + fYStart = fYEnd = fYOnYPlane; + else + fYStart = fYEnd = fYOther; + } + } + else + { + if( !m_pPosHelper->isSwapXAndY() ) + { + fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMaxX() : m_pPosHelper->getLogicMinX(); + fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMinY() : m_pPosHelper->getLogicMaxY(); + } + else + { + fXStart = fXEnd = m_pPosHelper->isMathematicalOrientationX() ? m_pPosHelper->getLogicMinX() : m_pPosHelper->getLogicMaxX(); + fYStart = fYEnd = m_pPosHelper->isMathematicalOrientationY() ? m_pPosHelper->getLogicMaxY() : m_pPosHelper->getLogicMinY(); + } + + if(m_nDimension==3) + { + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + double fDeltaX = rEnd.getX() - rStart.getX(); + + //only those points are candidates which are lying on exactly one wall as these are outer edges + tScreenPosAndLogicPosList aPosList { getScreenPosAndLogicPos( fXOther, fYOnYPlane, fMinZ ), getScreenPosAndLogicPos( fXOnXPlane, fYOther, fMinZ ) }; + + std::sort( aPosList.begin(), aPosList.end(), lcl_GreaterYPos() ); + ScreenPosAndLogicPos aBestPos( aPosList[0] ); + ScreenPosAndLogicPos aNotSoGoodPos( aPosList[1] ); + + //choose most bottom positions + if( fDeltaX != 0.0 ) // prefer left-right alignments + { + if( aBestPos.aScreenPos.getX() > aNotSoGoodPos.aScreenPos.getX() ) + rAlignment.meAlignment = LABEL_ALIGN_RIGHT; + else + rAlignment.meAlignment = LABEL_ALIGN_LEFT; + } + else + { + if( aBestPos.aScreenPos.getY() > aNotSoGoodPos.aScreenPos.getY() ) + rAlignment.meAlignment = LABEL_ALIGN_BOTTOM; + else + rAlignment.meAlignment = LABEL_ALIGN_TOP; + } + + rAlignment.mfLabelDirection = (fDeltaX < 0) ? -1.0 : 1.0; + if( !m_pPosHelper->isMathematicalOrientationZ() ) + rAlignment.mfLabelDirection *= -1.0; + + fXStart = fXEnd = aBestPos.fLogicX; + fYStart = fYEnd = aBestPos.fLogicY; + } + }//end 3D z axis + } + + rStart = getScreenPosition( fXStart, fYStart, fZStart ); + rEnd = getScreenPosition( fXEnd, fYEnd, fZEnd ); + + if(m_nDimension==3 && !AxisHelper::isAxisPositioningEnabled() ) + rAlignment.mfInnerTickDirection = rAlignment.mfLabelDirection;//to behave like before + + if(!(m_nDimension==3 && AxisHelper::isAxisPositioningEnabled()) ) + return; + + double fDeltaX = rEnd.getX() - rStart.getX(); + double fDeltaY = rEnd.getY() - rStart.getY(); + + if( m_nDimensionIndex==2 ) + { + if( m_eLeftWallPos != CuboidPlanePosition_Left ) + { + rAlignment.mfLabelDirection *= -1.0; + rAlignment.mfInnerTickDirection *= -1.0; + } + + rAlignment.meAlignment = + (rAlignment.mfLabelDirection < 0) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + + if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) || + ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) ) + rAlignment.meAlignment = + (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + } + else if( fabs(fDeltaY) > fabs(fDeltaX) ) + { + if( m_eBackWallPos != CuboidPlanePosition_Back ) + { + rAlignment.mfLabelDirection *= -1.0; + rAlignment.mfInnerTickDirection *= -1.0; + } + + rAlignment.meAlignment = + (rAlignment.mfLabelDirection < 0) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + + if( ( fDeltaY<0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) || + ( fDeltaY>0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) ) + rAlignment.meAlignment = + (rAlignment.meAlignment == LABEL_ALIGN_RIGHT) ? + LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + } + else + { + if( m_eBackWallPos != CuboidPlanePosition_Back ) + { + rAlignment.mfLabelDirection *= -1.0; + rAlignment.mfInnerTickDirection *= -1.0; + } + + rAlignment.meAlignment = + (rAlignment.mfLabelDirection < 0) ? + LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + + if( ( fDeltaX>0 && m_aScale.Orientation == chart2::AxisOrientation_REVERSE ) || + ( fDeltaX<0 && m_aScale.Orientation == chart2::AxisOrientation_MATHEMATICAL ) ) + rAlignment.meAlignment = + (rAlignment.meAlignment == LABEL_ALIGN_TOP) ? + LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + } +} + +TickFactory* VCartesianAxis::createTickFactory() +{ + return createTickFactory2D(); +} + +TickFactory2D* VCartesianAxis::createTickFactory2D() +{ + AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment; + B2DVector aStart, aEnd; + get2DAxisMainLine(aStart, aEnd, aLabelAlign, getAxisIntersectionValue()); + + B2DVector aLabelLineStart, aLabelLineEnd; + get2DAxisMainLine(aLabelLineStart, aLabelLineEnd, aLabelAlign, getLabelLineIntersectionValue()); + m_aAxisProperties.maLabelAlignment = aLabelAlign; + + return new TickFactory2D( m_aScale, m_aIncrement, aStart, aEnd, aLabelLineStart-aStart ); +} + +static void lcl_hideIdenticalScreenValues( TickIter& rTickIter ) +{ + TickInfo* pPrevTickInfo = rTickIter.firstInfo(); + if (!pPrevTickInfo) + return; + + pPrevTickInfo->bPaintIt = true; + for( TickInfo* pTickInfo = rTickIter.nextInfo(); pTickInfo; pTickInfo = rTickIter.nextInfo()) + { + pTickInfo->bPaintIt = (pTickInfo->aTickScreenPosition != pPrevTickInfo->aTickScreenPosition); + pPrevTickInfo = pTickInfo; + } +} + +//'hide' tickmarks with identical screen values in aAllTickInfos +void VCartesianAxis::hideIdenticalScreenValues( TickInfoArraysType& rTickInfos ) const +{ + if( isComplexCategoryAxis() || isDateAxis() ) + { + sal_Int32 nCount = rTickInfos.size(); + for( sal_Int32 nN=0; nN(fabs(aEnd.getY()-aStart.getY())); + sal_Int32 nMaxWidth = static_cast(fabs(aEnd.getX()-aStart.getX())); + + sal_Int32 nTotalAvailable = nMaxHeight; + sal_Int32 nSingleNeeded = m_nMaximumTextHeightSoFar; + sal_Int32 nMaxSameLabel = 0; + + // tdf#48041: do not duplicate the value labels because of rounding + if (m_aAxisProperties.m_nAxisType != css::chart2::AxisType::DATE) + { + FixedNumberFormatter aFixedNumberFormatterTest(m_xNumberFormatsSupplier, m_aAxisLabelProperties.m_nNumberFormatKey); + OUString sPreviousValueLabel; + sal_Int32 nSameLabel = 0; + for (auto const & nLabel: m_aAllTickInfos[0]) + { + Color nColor = COL_AUTO; + bool bHasColor = false; + OUString sValueLabel = aFixedNumberFormatterTest.getFormattedString(nLabel.fScaledTickValue, nColor, bHasColor); + if (sValueLabel == sPreviousValueLabel) + { + nSameLabel++; + if (nSameLabel > nMaxSameLabel) + nMaxSameLabel = nSameLabel; + } + else + nSameLabel = 0; + sPreviousValueLabel = sValueLabel; + } + } + //for horizontal axis: + if( (m_nDimensionIndex == 0 && !m_aAxisProperties.m_bSwapXAndY) + || (m_nDimensionIndex == 1 && m_aAxisProperties.m_bSwapXAndY) ) + { + nTotalAvailable = nMaxWidth; + nSingleNeeded = m_nMaximumTextWidthSoFar; + } + + if( nSingleNeeded>0 ) + nRet = nTotalAvailable/nSingleNeeded; + + if ( nMaxSameLabel > 0 ) + { + sal_Int32 nRetNoSameLabel = m_aAllTickInfos[0].size() / (nMaxSameLabel + 1); + if ( nRet > nRetNoSameLabel ) + nRet = nRetNoSameLabel; + } + + return nRet; +} + +void VCartesianAxis::doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties, TickFactory2D const * pTickFactory2D ) +{ + if( !pTickFactory2D ) + return; + + if( isComplexCategoryAxis() ) + { + sal_Int32 nTextLevelCount = getTextLevelCount(); + B2DVector aCumulatedLabelsDistance(0,0); + for( sal_Int32 nTextLevel=0; nTextLevel apTickIter(createLabelTickIterator(nTextLevel)); + if (apTickIter) + { + double fRotationAngleDegree = m_aAxisLabelProperties.m_fRotationAngleDegree; + if( nTextLevel>0 ) + { + lcl_shiftLabels(*apTickIter, aCumulatedLabelsDistance); + //multilevel labels: 0 or 90 by default + if( m_aAxisProperties.m_bSwapXAndY ) + fRotationAngleDegree = 90.0; + else + fRotationAngleDegree = 0.0; + } + aCumulatedLabelsDistance += lcl_getLabelsDistance( + *apTickIter, pTickFactory2D->getDistanceAxisTickToText(m_aAxisProperties), + fRotationAngleDegree); + } + } + } + else if (rAxisLabelProperties.isStaggered()) + { + if( !m_aAllTickInfos.empty() ) + { + LabelIterator aInnerIter( m_aAllTickInfos[0], rAxisLabelProperties.m_eStaggering, true ); + LabelIterator aOuterIter( m_aAllTickInfos[0], rAxisLabelProperties.m_eStaggering, false ); + + lcl_shiftLabels( aOuterIter + , lcl_getLabelsDistance( aInnerIter + , pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties ), 0.0 ) ); + } + } +} + +void VCartesianAxis::createLabels() +{ + if( !prepareShapeCreation() ) + return; + + //create labels + if (!m_aAxisProperties.m_bDisplayLabels) + return; + + std::unique_ptr apTickFactory2D(createTickFactory2D()); // throws on failure + TickFactory2D* pTickFactory2D = apTickFactory2D.get(); + + //get the transformed screen values for all tickmarks in aAllTickInfos + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + //'hide' tickmarks with identical screen values in aAllTickInfos + hideIdenticalScreenValues( m_aAllTickInfos ); + + removeTextShapesFromTicks(); + + //create tick mark text shapes + sal_Int32 nTextLevelCount = getTextLevelCount(); + sal_Int32 nScreenDistanceBetweenTicks = -1; + for( sal_Int32 nTextLevel=0; nTextLevel apTickIter(createLabelTickIterator( nTextLevel )); + if(apTickIter) + { + if(nTextLevel==0) + { + nScreenDistanceBetweenTicks = TickFactory2D::getTickScreenDistance(*apTickIter); + if( nTextLevelCount>1 ) + nScreenDistanceBetweenTicks*=2; //the above used tick iter does contain also the sub ticks -> thus the given distance is only the half + } + + AxisLabelProperties aComplexProps(m_aAxisLabelProperties); + if( m_aAxisProperties.m_bComplexCategories ) + { + aComplexProps.m_bLineBreakAllowed = true; + aComplexProps.m_bOverlapAllowed = aComplexProps.m_fRotationAngleDegree != 0.0; + if( nTextLevel > 0 ) + { + //multilevel labels: 0 or 90 by default + if( m_aAxisProperties.m_bSwapXAndY ) + aComplexProps.m_fRotationAngleDegree = 90.0; + else + aComplexProps.m_fRotationAngleDegree = 0.0; + } + } + AxisLabelProperties& rAxisLabelProperties = m_aAxisProperties.m_bComplexCategories ? aComplexProps : m_aAxisLabelProperties; + while (!createTextShapes(m_xTextTarget, *apTickIter, rAxisLabelProperties, + pTickFactory2D, nScreenDistanceBetweenTicks)) + { + }; + } + } + doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D ); +} + +void VCartesianAxis::createMaximumLabels() +{ + m_bRecordMaximumTextSize = true; + const comphelper::ScopeGuard aGuard([this]() { m_bRecordMaximumTextSize = false; }); + + if( !prepareShapeCreation() ) + return; + + //create labels + if (!m_aAxisProperties.m_bDisplayLabels) + return; + + std::unique_ptr apTickFactory2D(createTickFactory2D()); // throws on failure + TickFactory2D* pTickFactory2D = apTickFactory2D.get(); + + //get the transformed screen values for all tickmarks in aAllTickInfos + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + + //create tick mark text shapes + //@todo: iterate through all tick depth which should be labeled + + AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties ); + if( isAutoStaggeringOfLabelsAllowed( aAxisLabelProperties, pTickFactory2D->isHorizontalAxis(), pTickFactory2D->isVerticalAxis() ) ) + aAxisLabelProperties.m_eStaggering = AxisLabelStaggering::StaggerEven; + + aAxisLabelProperties.m_bOverlapAllowed = true; + aAxisLabelProperties.m_bLineBreakAllowed = false; + sal_Int32 nTextLevelCount = getTextLevelCount(); + for( sal_Int32 nTextLevel=0; nTextLevel apTickIter(createMaximumLabelTickIterator( nTextLevel )); + if(apTickIter) + { + while (!createTextShapes(m_xTextTarget, *apTickIter, aAxisLabelProperties, + pTickFactory2D, -1)) + { + }; + } + } + doStaggeringOfLabels( aAxisLabelProperties, pTickFactory2D ); +} + +void VCartesianAxis::updatePositions() +{ + //update positions of labels + if (!m_aAxisProperties.m_bDisplayLabels) + return; + + std::unique_ptr apTickFactory2D(createTickFactory2D()); // throws on failure + TickFactory2D* pTickFactory2D = apTickFactory2D.get(); + + //update positions of all existing text shapes + pTickFactory2D->updateScreenValues( m_aAllTickInfos ); + + sal_Int32 nDepth=0; + for (auto const& tickInfos : m_aAllTickInfos) + { + for (auto const& tickInfo : tickInfos) + { + const rtl::Reference & xShape2DText(tickInfo.xTextShape); + if( xShape2DText.is() ) + { + B2DVector aTextToTickDistance( pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, true ) ); + B2DVector aTickScreenPos2D(tickInfo.aTickScreenPosition); + aTickScreenPos2D += aTextToTickDistance; + awt::Point aAnchorScreenPosition2D( + static_cast(aTickScreenPos2D.getX()) + ,static_cast(aTickScreenPos2D.getY())); + + double fRotationAngleDegree = m_aAxisLabelProperties.m_fRotationAngleDegree; + if( nDepth > 0 ) + { + //multilevel labels: 0 or 90 by default + if( pTickFactory2D->isHorizontalAxis() ) + fRotationAngleDegree = 0.0; + else + fRotationAngleDegree = 90; + } + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(-basegfx::deg2rad(fRotationAngleDegree)); + uno::Any aATransformation = ShapeFactory::makeTransformation(aAnchorScreenPosition2D, fRotationAnglePi); + + //set new position + try + { + xShape2DText->SvxShape::setPropertyValue( "Transformation", aATransformation ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //correctPositionForRotation + LabelPositionHelper::correctPositionForRotation( xShape2DText + , m_aAxisProperties.maLabelAlignment.meAlignment, fRotationAngleDegree, m_aAxisProperties.m_bComplexCategories ); + } + } + ++nDepth; + } + + doStaggeringOfLabels( m_aAxisLabelProperties, pTickFactory2D ); +} + +void VCartesianAxis::createTickMarkLineShapes( TickInfoArrayType& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory2D const & rTickFactory2D, bool bOnlyAtLabels ) +{ + sal_Int32 nPointCount = rTickInfos.size(); + drawing::PointSequenceSequence aPoints(2*nPointCount); + + sal_Int32 nN = 0; + for (auto const& tickInfo : rTickInfos) + { + if( !tickInfo.bPaintIt ) + continue; + + bool bTicksAtLabels = ( m_aAxisProperties.m_eTickmarkPos != css::chart::ChartAxisMarkPosition_AT_AXIS ); + double fInnerDirectionSign = m_aAxisProperties.maLabelAlignment.mfInnerTickDirection; + if( bTicksAtLabels && m_aAxisProperties.m_eLabelPos == css::chart::ChartAxisLabelPosition_OUTSIDE_END ) + fInnerDirectionSign *= -1.0; + bTicksAtLabels = bTicksAtLabels || bOnlyAtLabels; + //add ticks at labels: + rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, tickInfo.fScaledTickValue + , fInnerDirectionSign , rTickmarkProperties, bTicksAtLabels ); + //add ticks at axis (without labels): + if( !bOnlyAtLabels && m_aAxisProperties.m_eTickmarkPos == css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS ) + rTickFactory2D.addPointSequenceForTickLine( aPoints, nN++, tickInfo.fScaledTickValue + , m_aAxisProperties.maLabelAlignment.mfInnerTickDirection, rTickmarkProperties, !bTicksAtLabels ); + } + aPoints.realloc(nN); + ShapeFactory::createLine2D( m_xGroupShape_Shapes, aPoints + , &rTickmarkProperties.aLineProperties ); +} + +void VCartesianAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + //create line shapes + if(m_nDimension==2) + { + std::unique_ptr apTickFactory2D(createTickFactory2D()); // throws on failure + TickFactory2D* pTickFactory2D = apTickFactory2D.get(); + + //create extra long ticks to separate complex categories (create them only there where the labels are) + if( isComplexCategoryAxis() ) + { + TickInfoArraysType aComplexTickInfos; + createAllTickInfosFromComplexCategories( aComplexTickInfos, true ); + pTickFactory2D->updateScreenValues( aComplexTickInfos ); + hideIdenticalScreenValues( aComplexTickInfos ); + + std::vector aTickmarkPropertiesList; + static const bool bIncludeSpaceBetweenTickAndText = false; + sal_Int32 nOffset = static_cast(pTickFactory2D->getDistanceAxisTickToText( m_aAxisProperties, false, bIncludeSpaceBetweenTickAndText ).getLength()); + sal_Int32 nTextLevelCount = getTextLevelCount(); + for( sal_Int32 nTextLevel=0; nTextLevel apTickIter(createLabelTickIterator( nTextLevel )); + if( apTickIter ) + { + double fRotationAngleDegree = m_aAxisLabelProperties.m_fRotationAngleDegree; + if( nTextLevel > 0 ) + { + //Multi-level Labels: default to 0 or 90 + if( m_aAxisProperties.m_bSwapXAndY ) + fRotationAngleDegree = 90.0; + else + fRotationAngleDegree = 0.0; + } + B2DVector aLabelsDistance(lcl_getLabelsDistance( + *apTickIter, pTickFactory2D->getDistanceAxisTickToText(m_aAxisProperties), + fRotationAngleDegree)); + sal_Int32 nCurrentLength = static_cast(aLabelsDistance.getLength()); + aTickmarkPropertiesList.push_back( m_aAxisProperties.makeTickmarkPropertiesForComplexCategories( nOffset + nCurrentLength, 0 ) ); + nOffset += nCurrentLength; + } + } + + sal_Int32 nTickmarkPropertiesCount = aTickmarkPropertiesList.size(); + TickInfoArraysType::iterator aDepthIter = aComplexTickInfos.begin(); + const TickInfoArraysType::const_iterator aDepthEnd = aComplexTickInfos.end(); + for( sal_Int32 nDepth=0; aDepthIter != aDepthEnd && nDepth < nTickmarkPropertiesCount; ++aDepthIter, nDepth++ ) + { + if(nDepth==0 && !m_aAxisProperties.m_nMajorTickmarks) + continue; + createTickMarkLineShapes( *aDepthIter, aTickmarkPropertiesList[nDepth], *pTickFactory2D, true /*bOnlyAtLabels*/ ); + } + } + //create normal ticks for major and minor intervals + { + TickInfoArraysType aUnshiftedTickInfos; + if( m_aScale.m_bShiftedCategoryPosition )// if m_bShiftedCategoryPosition==true the tickmarks in m_aAllTickInfos are shifted + { + pTickFactory2D->getAllTicks( aUnshiftedTickInfos ); + pTickFactory2D->updateScreenValues( aUnshiftedTickInfos ); + hideIdenticalScreenValues( aUnshiftedTickInfos ); + } + TickInfoArraysType& rAllTickInfos = m_aScale.m_bShiftedCategoryPosition ? aUnshiftedTickInfos : m_aAllTickInfos; + + if (rAllTickInfos.empty()) + return; + + sal_Int32 nDepth = 0; + sal_Int32 nTickmarkPropertiesCount = m_aAxisProperties.m_aTickmarkPropertiesList.size(); + for( auto& rTickInfos : rAllTickInfos ) + { + if (nDepth == nTickmarkPropertiesCount) + break; + + createTickMarkLineShapes( rTickInfos, m_aAxisProperties.m_aTickmarkPropertiesList[nDepth], *pTickFactory2D, false /*bOnlyAtLabels*/ ); + nDepth++; + } + } + //create axis main lines + //it serves also as the handle shape for the axis selection + { + drawing::PointSequenceSequence aPoints(1); + apTickFactory2D->createPointSequenceForAxisMainLine( aPoints ); + rtl::Reference xShape = ShapeFactory::createLine2D( + m_xGroupShape_Shapes, aPoints + , &m_aAxisProperties.m_aLineProperties ); + //because of this name this line will be used for marking the axis + ::chart::ShapeFactory::setShapeName( xShape, "MarkHandles" ); + } + //create an additional line at NULL + if( !AxisHelper::isAxisPositioningEnabled() ) + { + double fExtraLineCrossesOtherAxis = getExtraLineIntersectionValue(); + if (!std::isnan(fExtraLineCrossesOtherAxis)) + { + B2DVector aStart, aEnd; + AxisLabelAlignment aLabelAlign = m_aAxisProperties.maLabelAlignment; + get2DAxisMainLine(aStart, aEnd, aLabelAlign, fExtraLineCrossesOtherAxis); + m_aAxisProperties.maLabelAlignment = aLabelAlign; + drawing::PointSequenceSequence aPoints{{ + {static_cast(aStart.getX()), static_cast(aStart.getY())}, + {static_cast(aEnd.getX()), static_cast(aEnd.getY())} }}; + ShapeFactory::createLine2D( + m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties ); + } + } + } + + createLabels(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianAxis.hxx b/chart2/source/view/axes/VCartesianAxis.hxx new file mode 100644 index 000000000..94e9b2ab9 --- /dev/null +++ b/chart2/source/view/axes/VCartesianAxis.hxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VAxisBase.hxx" +#include + +namespace chart +{ + +class VCartesianAxis : public VAxisBase +{ + // public methods +public: + VCartesianAxis( const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , PlottingPositionHelper* pPosHelper = nullptr //takes ownership + ); + + virtual ~VCartesianAxis() override; + + virtual void createMaximumLabels() override; + virtual void createLabels() override; + virtual void updatePositions() override; + + virtual void createShapes() override; + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount() override; + virtual void createAllTickInfos( TickInfoArraysType& rAllTickInfos ) override; + void createAllTickInfosFromComplexCategories( TickInfoArraysType& rAllTickInfos, bool bShiftedPosition ); + + TickIter* createLabelTickIterator( sal_Int32 nTextLevel ); + TickIter* createMaximumLabelTickIterator( sal_Int32 nTextLevel ); + sal_Int32 getTextLevelCount() const; + + virtual TickFactory* createTickFactory() override; + + /** + * Get the value at which the other axis crosses. + */ + double getAxisIntersectionValue() const; + + /** + * Get the value at which label line crosses the other axis. + */ + double getLabelLineIntersectionValue() const; + + /** + * Get the value at which extra line crosses the other axis. + * + * @return a NaN if the line doesn't cross the other axis, a non-NaN value + * otherwise. + */ + double getExtraLineIntersectionValue() const; + + void get2DAxisMainLine( + basegfx::B2DVector& rStart, basegfx::B2DVector& rEnd, AxisLabelAlignment& rLabelAlignment, + double fCrossesOtherAxis ) const; + + //Layout interface for cartesian axes: + + //the returned value describes the minimum size that is necessary + //for the text labels in the direction orthogonal to the axis + //(for an y-axis a width is returned; in case of an x-axis the value describes a height) + //the return value is measured in screen dimension + //As an example the MinimumOrthogonalSize of an x-axis equals the + //Font Height if the label properties allow for labels parallel to the axis. +// sal_Int32 calculateMinimumOrthogonalSize( /*... parallel...*/ ); + //Minimum->Preferred + + //returns true if the MinimumOrthogonalSize can be calculated + //with the creation of at most one text shape + //(this is e.g. true if the parameters allow for labels parallel to the axis.) +// sal_bool canQuicklyCalculateMinimumOrthogonalSize(); + + struct ScreenPosAndLogicPos + { + double fLogicX; + double fLogicY; + double fLogicZ; + + ::basegfx::B2DVector aScreenPos; + }; + +private: //methods + /** + * Go through all tick label positions and decide which labels to display + * based on the text shape geometry, overlap setting, tick interval, + * auto-stagger setting etc. + * + * When the auto-stagger setting is on, try to avoid overlaps by + * staggering labels or set the labels at an angle. This method may + * change the axis label properties especially when the auto staggering is + * performed. But the screen label positions will not be shifted in this + * method; it will be done in the doStaggeringOfLabels method. + * + * @return true if the text shapes have been successfully created, + * otherwise false. Returning false means the AxisLabelProperties + * have changed during the call, and the caller needs to call this + * method once again to get the text shapes created. + */ + bool createTextShapes( + const rtl::Reference< SvxShapeGroupAnyD >& xTarget, + TickIter& rTickIter, AxisLabelProperties& rAxisLabelProperties, + TickFactory2D const * pTickFactory, sal_Int32 nScreenDistanceBetweenTicks ); + + /** + * Variant of createTextShapes where none of auto-staggering and + * link-breaking are allowed in case of overlaps. Overlaps of text shapes + * are to be resolved only by adjusting the label tick interval. + */ + bool createTextShapesSimple( + const rtl::Reference< SvxShapeGroupAnyD >& xTarget, + TickIter& rTickIter, AxisLabelProperties& rAxisLabelProperties, + TickFactory2D const * pTickFactory ); + + void createTickMarkLineShapes( TickInfoArrayType& rTickInfos, const TickmarkProperties& rTickmarkProperties, TickFactory2D const & rTickFactory2D, bool bOnlyAtLabels ); + + TickFactory2D* createTickFactory2D(); + void hideIdenticalScreenValues( TickInfoArraysType& rTickInfos ) const; + + /** + * Shift the screen positions of the tick labels according to the stagger + * settings. Final stagger setting is decided during the createTextShapes + * call, but this method does the physical shifting of the label + * positions based on the final stagger setting. + */ + void doStaggeringOfLabels( const AxisLabelProperties& rAxisLabelProperties + , TickFactory2D const * pTickFactory2D ); + + /** + * @return true if we can break a single line label text into multiple + * lines for better fitting, otherwise false. + */ + bool isBreakOfLabelsAllowed( const AxisLabelProperties& rAxisLabelProperties, bool bIsHorizontalAxis, bool bIsVerticalAxis ) const; + + ::basegfx::B2DVector getScreenPosition( double fLogicX, double fLogicY, double fLogicZ ) const; + ScreenPosAndLogicPos getScreenPosAndLogicPos( double fLogicX, double fLogicY, double fLogicZ ) const; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.cxx b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx new file mode 100644 index 000000000..1257ff6f4 --- /dev/null +++ b/chart2/source/view/axes/VCartesianCoordinateSystem.cxx @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VCartesianCoordinateSystem.hxx" +#include "VCartesianGrid.hxx" +#include "VCartesianAxis.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +namespace { + +class TextualDataProvider : public ::cppu::WeakImplHelper< + css::chart2::data::XTextualDataSequence + > +{ +public: + explicit TextualDataProvider( const uno::Sequence< OUString >& rTextSequence ) + : m_aTextSequence( rTextSequence ) + { + } + + //XTextualDataSequence + virtual uno::Sequence< OUString > SAL_CALL getTextualData() override + { + return m_aTextSequence; + } + +private: //member + uno::Sequence< OUString > m_aTextSequence; +}; + +} + +VCartesianCoordinateSystem::VCartesianCoordinateSystem( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) + : VCoordinateSystem(xCooSys) +{ +} + +VCartesianCoordinateSystem::~VCartesianCoordinateSystem() +{ +} + +void VCartesianCoordinateSystem::createGridShapes() +{ + if(!m_xLogicTargetForGrids.is() || !m_xFinalTarget.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for( sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + sal_Int32 nAxisIndex = MAIN_AXIS_INDEX; + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, nAxisIndex, m_xCooSysModel ); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + VCartesianGrid aGrid(nDimensionIndex,nDimensionCount, getGridListFromAxis( xAxis )); + aGrid.setExplicitScaleAndIncrement( getExplicitScale(nDimensionIndex,nAxisIndex) + , getExplicitIncrement(nDimensionIndex,nAxisIndex) ); + aGrid.set3DWallPositions( m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + aGrid.initPlotter(m_xLogicTargetForGrids,m_xFinalTarget + , createCIDForGrid( nDimensionIndex,nAxisIndex ) ); + if(nDimensionCount==2) + aGrid.setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + aGrid.setScales( getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + aGrid.createShapes(); + } +} + +void VCartesianCoordinateSystem::createVAxisList( + const rtl::Reference<::chart::ChartModel> & xChartDoc + , const awt::Size& rFontReferenceSize + , const awt::Rectangle& rMaximumSpaceForLabels + , bool bLimitSpaceForLabels + ) +{ + // note: using xChartDoc itself as XNumberFormatsSupplier would cause + // a leak from VCartesianAxis due to cyclic reference + uno::Reference const xNumberFormatsSupplier( + dynamic_cast(*xChartDoc).getNumberFormatsSupplier()); + + m_aAxisMap.clear(); + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + if(nDimensionCount<=0) + return; + + sal_Int32 nDimensionIndex = 0; + + // dimension index -> x, y or z axis. + for( nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + // axis index -> primary or secondary axis. + sal_Int32 nMaxAxisIndex = m_xCooSysModel->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + rtl::Reference< Axis > xAxis = getAxisByDimension(nDimensionIndex,nAxisIndex); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + AxisProperties aAxisProperties(xAxis,getExplicitCategoriesProvider()); + aAxisProperties.m_nDimensionIndex = nDimensionIndex; + aAxisProperties.m_bSwapXAndY = bSwapXAndY; + aAxisProperties.m_bIsMainAxis = (nAxisIndex==0); + aAxisProperties.m_bLimitSpaceForLabels = bLimitSpaceForLabels; + rtl::Reference< Axis > xCrossingMainAxis = AxisHelper::getCrossingMainAxis( xAxis, m_xCooSysModel ); + if( xCrossingMainAxis.is() ) + { + ScaleData aCrossingScale( xCrossingMainAxis->getScaleData() ); + aAxisProperties.m_bCrossingAxisHasReverseDirection = (aCrossingScale.Orientation==AxisOrientation_REVERSE); + + if( aCrossingScale.AxisType == AxisType::CATEGORY ) + aAxisProperties.m_bCrossingAxisIsCategoryAxes = true; + } + + if( nDimensionIndex == 2 ) + { + aAxisProperties.m_xAxisTextProvider = new TextualDataProvider( m_aSeriesNamesForZAxis ); + + //for the z axis copy the positioning properties from the x axis (or from the y axis for swapped coordinate systems) + rtl::Reference< Axis > xSisterAxis = AxisHelper::getCrossingMainAxis( xCrossingMainAxis, m_xCooSysModel ); + aAxisProperties.initAxisPositioning( xSisterAxis ); + } + aAxisProperties.init(true); + if(aAxisProperties.m_bDisplayLabels) + aAxisProperties.m_nNumberFormatKey = getNumberFormatKeyForAxis(xAxis, xChartDoc); + + auto apVAxis = std::make_shared(aAxisProperties,xNumberFormatsSupplier,nDimensionIndex,nDimensionCount); + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aAxisMap[aFullAxisIndex] = apVAxis; + apVAxis->set3DWallPositions( m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + apVAxis->initAxisLabelProperties(rFontReferenceSize,rMaximumSpaceForLabels); + } + } +} + +void VCartesianCoordinateSystem::initVAxisInList() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for (auto const& [nIndexPair, pVAxis] : m_aAxisMap) + { + if (pVAxis) + { + auto [nDimensionIndex, nAxisIndex] = nIndexPair; + pVAxis->setExplicitScaleAndIncrement( getExplicitScale( nDimensionIndex, nAxisIndex ), getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + pVAxis->initPlotter(m_xLogicTargetForAxes, m_xFinalTarget, createCIDForAxis( nDimensionIndex, nAxisIndex ) ); + if(nDimensionCount==2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + } + } +} + +void VCartesianCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for (auto const& [nIndexPair, pVAxis] : m_aAxisMap) + { + if (pVAxis) + { + auto [nDimensionIndex, nAxisIndex] = nIndexPair; + + pVAxis->setExplicitScaleAndIncrement( getExplicitScale( nDimensionIndex, nAxisIndex ), getExplicitIncrement( nDimensionIndex, nAxisIndex ) ); + if(nDimensionCount==2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( getExplicitScales(nDimensionIndex,nAxisIndex), bSwapXAndY ); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianCoordinateSystem.hxx b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx new file mode 100644 index 000000000..e9d684821 --- /dev/null +++ b/chart2/source/view/axes/VCartesianCoordinateSystem.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class VCartesianCoordinateSystem : public VCoordinateSystem +{ +public: + VCartesianCoordinateSystem() = delete; + explicit VCartesianCoordinateSystem( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + virtual ~VCartesianCoordinateSystem() override; + + virtual void createVAxisList( + const rtl::Reference<::chart::ChartModel> &ChartDoc + , const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels + , bool bLimitSpaceForLabels ) override; + + virtual void initVAxisInList() override; + virtual void updateScalesAndIncrementsOnAxes() override; + + virtual void createGridShapes() override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianGrid.cxx b/chart2/source/view/axes/VCartesianGrid.cxx new file mode 100644 index 000000000..a5c44c22b --- /dev/null +++ b/chart2/source/view/axes/VCartesianGrid.cxx @@ -0,0 +1,309 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VCartesianGrid.hxx" +#include "Tickmarks.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; + +namespace { + +struct GridLinePoints +{ + Sequence< double > P0; + Sequence< double > P1; + Sequence< double > P2; + + GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex + , CuboidPlanePosition eLeftWallPos=CuboidPlanePosition_Left + , CuboidPlanePosition eBackWallPos=CuboidPlanePosition_Back + , CuboidPlanePosition eBottomPos=CuboidPlanePosition_Bottom ); + void update( double fScaledTickValue ); + + sal_Int32 m_nDimensionIndex; +}; + +} + +GridLinePoints::GridLinePoints( const PlottingPositionHelper* pPosHelper, sal_Int32 nDimensionIndex + , CuboidPlanePosition eLeftWallPos + , CuboidPlanePosition eBackWallPos + , CuboidPlanePosition eBottomPos ) + : m_nDimensionIndex(nDimensionIndex) +{ + double MinX = pPosHelper->getLogicMinX(); + double MinY = pPosHelper->getLogicMinY(); + double MinZ = pPosHelper->getLogicMinZ(); + double MaxX = pPosHelper->getLogicMaxX(); + double MaxY = pPosHelper->getLogicMaxY(); + double MaxZ = pPosHelper->getLogicMaxZ(); + + pPosHelper->doLogicScaling( &MinX,&MinY,&MinZ ); + pPosHelper->doLogicScaling( &MaxX,&MaxY,&MaxZ ); + + if(!pPosHelper->isMathematicalOrientationX()) + { + double fHelp = MinX; + MinX = MaxX; + MaxX = fHelp; + } + if(!pPosHelper->isMathematicalOrientationY()) + { + double fHelp = MinY; + MinY = MaxY; + MaxY = fHelp; + } + if(pPosHelper->isMathematicalOrientationZ())//z axis in draw is reverse to mathematical + { + double fHelp = MinZ; + MinZ = MaxZ; + MaxZ = fHelp; + } + bool bSwapXY = pPosHelper->isSwapXAndY(); + + //P0: point on 'back' wall, not on 'left' wall + //P1: point on both walls + //P2: point on 'left' wall not on 'back' wall + + const double v0 = (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MinX : MaxX; + const double v1 = (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MinY : MaxY; + const double v2 = (eBackWallPos == CuboidPlanePosition_Back) ? MinZ : MaxZ; + P0 = P1 = P2 = { v0, v1, v2 }; + + if(m_nDimensionIndex==0) + { + P0.getArray()[1] = (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MaxY : MinY; + P2.getArray()[2]= (eBackWallPos == CuboidPlanePosition_Back) ? MaxZ : MinZ; + if( eBottomPos != CuboidPlanePosition_Bottom && !bSwapXY ) + P2=P1; + } + else if(m_nDimensionIndex==1) + { + P0.getArray()[0]= (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MaxX : MinX; + P2.getArray()[2]= (eBackWallPos == CuboidPlanePosition_Back) ? MaxZ : MinZ; + if( eBottomPos != CuboidPlanePosition_Bottom && bSwapXY ) + P2=P1; + } + else if(m_nDimensionIndex==2) + { + P0.getArray()[0]= (eLeftWallPos == CuboidPlanePosition_Left || bSwapXY) ? MaxX : MinX; + P2.getArray()[1]= (eLeftWallPos == CuboidPlanePosition_Left || !bSwapXY) ? MaxY : MinY; + if( eBottomPos != CuboidPlanePosition_Bottom ) + { + if( !bSwapXY ) + P0=P1; + else + P2=P1; + } + } +} + +void GridLinePoints::update( double fScaledTickValue ) +{ + P0.getArray()[m_nDimensionIndex] = P1.getArray()[m_nDimensionIndex] = P2.getArray()[m_nDimensionIndex] = fScaledTickValue; +} + +static void addLine2D( drawing::PointSequenceSequence& rPoints, sal_Int32 nIndex + , const GridLinePoints& rScaledLogicPoints + , const XTransformation2& rTransformation + ) +{ + drawing::Position3D aPA = rTransformation.transform( SequenceToPosition3D(rScaledLogicPoints.P0) ); + drawing::Position3D aPB = rTransformation.transform( SequenceToPosition3D(rScaledLogicPoints.P1) ); + + rPoints.getArray()[nIndex] + = { { static_cast(aPA.PositionX), static_cast(aPA.PositionY) }, + { static_cast(aPB.PositionX), static_cast(aPB.PositionY) } }; +} + +static void addLine3D( std::vector>& rPoints, sal_Int32 nIndex + , const GridLinePoints& rBasePoints + , const XTransformation2 & rTransformation ) +{ + drawing::Position3D aPoint =rTransformation.transform( rBasePoints.P0 ); + AddPointToPoly( rPoints, aPoint, nIndex ); + aPoint = rTransformation.transform( rBasePoints.P1 ); + AddPointToPoly( rPoints, aPoint, nIndex ); + aPoint = rTransformation.transform( rBasePoints.P2 ); + AddPointToPoly( rPoints, aPoint, nIndex ); +} + +VCartesianGrid::VCartesianGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , const std::vector< Reference< beans::XPropertySet > > aGridPropertiesList ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_aGridPropertiesList( std::move(aGridPropertiesList) ) +{ + m_pPosHelper = new PlottingPositionHelper(); +} + +VCartesianGrid::~VCartesianGrid() +{ + delete m_pPosHelper; + m_pPosHelper = nullptr; +} + +void VCartesianGrid::fillLinePropertiesFromGridModel( std::vector& rLinePropertiesList + , const std::vector< Reference< beans::XPropertySet > > & rGridPropertiesList ) +{ + rLinePropertiesList.clear(); + if( rGridPropertiesList.empty() ) + return; + + VLineProperties aLineProperties; + for( const auto & rxPropSet : rGridPropertiesList ) + { + if(!AxisHelper::isGridVisible( rxPropSet )) + aLineProperties.LineStyle <<= drawing::LineStyle_NONE; + else + aLineProperties.initFromPropertySet( rxPropSet ); + rLinePropertiesList.push_back(aLineProperties); + } +}; + +void VCartesianGrid::createShapes() +{ + if(m_aGridPropertiesList.empty()) + return; + //somehow equal to axis tickmarks + + //create named group shape + rtl::Reference< SvxShapeGroupAnyD > xGroupShape_Shapes( + createGroupShape( m_xLogicTarget, m_aCID ) ); + + if(!xGroupShape_Shapes.is()) + return; + + std::vector aLinePropertiesList; + fillLinePropertiesFromGridModel( aLinePropertiesList, m_aGridPropertiesList ); + + //create all scaled tickmark values + std::unique_ptr< TickFactory > apTickFactory( createTickFactory() ); + TickFactory& aTickFactory = *apTickFactory; + TickInfoArraysType aAllTickInfos; + aTickFactory.getAllTicks( aAllTickInfos ); + + //create tick mark line shapes + + if(aAllTickInfos.empty())//no tickmarks at all + return; + + TickInfoArraysType::iterator aDepthIter = aAllTickInfos.begin(); + const TickInfoArraysType::const_iterator aDepthEnd = aAllTickInfos.end(); + + sal_Int32 nLinePropertiesCount = aLinePropertiesList.size(); + for( sal_Int32 nDepth=0 + ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount + ; ++aDepthIter, nDepth++ ) + { + if( !aLinePropertiesList[nDepth].isLineVisible() ) + continue; + + rtl::Reference< SvxShapeGroupAnyD > xTarget( xGroupShape_Shapes ); + if( nDepth > 0 ) + { + xTarget = createGroupShape( m_xLogicTarget + , ObjectIdentifier::addChildParticle( m_aCID, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_SUBGRID, nDepth-1 ) ) + ); + if(!xTarget.is()) + xTarget = xGroupShape_Shapes; + } + + if(m_nDimension==2) + { + + GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex ); + + sal_Int32 nPointCount = (*aDepthIter).size(); + drawing::PointSequenceSequence aPoints(nPointCount); + + sal_Int32 nRealPointCount = 0; + for (auto const& tick : *aDepthIter) + { + if( !tick.bPaintIt ) + continue; + aGridLinePoints.update( tick.fScaledTickValue ); + addLine2D( aPoints, nRealPointCount, aGridLinePoints, *m_pPosHelper->getTransformationScaledLogicToScene() ); + nRealPointCount++; + } + aPoints.realloc(nRealPointCount); + ShapeFactory::createLine2D( xTarget, aPoints, &aLinePropertiesList[nDepth] ); + + //prepare polygon for handle shape: + drawing::PointSequenceSequence aHandlesPoints(1); + auto pHandlesPoints = aHandlesPoints.getArray(); + pHandlesPoints[0].realloc(nRealPointCount); + auto pHandlesPoints0 = pHandlesPoints[0].getArray(); + for( sal_Int32 nN = 0; nN xHandleShape = + ShapeFactory::createLine2D( xTarget, aHandlesPoints, &aHandleLineProperties ); + ::chart::ShapeFactory::setShapeName( xHandleShape, "HandlesOnly" ); + } + else //if(2!=m_nDimension) + { + GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex, m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); + + sal_Int32 nPointCount = (*aDepthIter).size(); + std::vector> aPoints; + aPoints.resize(nPointCount); + + sal_Int32 nRealPointCount = 0; + sal_Int32 nPolyIndex = 0; + for (auto const& tick : *aDepthIter) + { + if( !tick.bPaintIt ) + { + ++nPolyIndex; + continue; + } + + aGridLinePoints.update( tick.fScaledTickValue ); + addLine3D( aPoints, nPolyIndex, aGridLinePoints, *m_pPosHelper->getTransformationScaledLogicToScene() ); + nRealPointCount+=3; + ++nPolyIndex; + } + aPoints.resize(nRealPointCount); + ShapeFactory::createLine3D( xTarget, aPoints, aLinePropertiesList[nDepth] ); + } + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCartesianGrid.hxx b/chart2/source/view/axes/VCartesianGrid.hxx new file mode 100644 index 000000000..81ba1e16f --- /dev/null +++ b/chart2/source/view/axes/VCartesianGrid.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VAxisOrGridBase.hxx" +#include + +namespace chart { struct VLineProperties; } + +namespace chart +{ + +class VCartesianGrid : public VAxisOrGridBase +{ +// public methods +public: + VCartesianGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , std::vector< + css::uno::Reference< css::beans::XPropertySet > > aGridPropertiesList //main grid, subgrid, subsubgrid etc + ); + virtual ~VCartesianGrid() override; + + virtual void createShapes() override; + + static void fillLinePropertiesFromGridModel( std::vector& rLinePropertiesList + , const std::vector< + css::uno::Reference< css::beans::XPropertySet > >& rGridPropertiesList ); + +private: + std::vector< + css::uno::Reference< css::beans::XPropertySet > > m_aGridPropertiesList; //main grid, subgrid, subsubgrid etc +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VCoordinateSystem.cxx b/chart2/source/view/axes/VCoordinateSystem.cxx new file mode 100644 index 000000000..25a0f5d35 --- /dev/null +++ b/chart2/source/view/axes/VCoordinateSystem.cxx @@ -0,0 +1,576 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "VCartesianCoordinateSystem.hxx" +#include "VPolarCoordinateSystem.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "VAxisBase.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; + +std::unique_ptr VCoordinateSystem::createCoordinateSystem( + const rtl::Reference< BaseCoordinateSystem >& xCooSysModel ) +{ + if( !xCooSysModel.is() ) + return nullptr; + + OUString aViewServiceName = xCooSysModel->getViewServiceName(); + + //@todo: in future the coordinatesystems should be instantiated via service factory + std::unique_ptr pRet; + if( aViewServiceName == CHART2_COOSYSTEM_CARTESIAN_VIEW_SERVICE_NAME ) + pRet.reset( new VCartesianCoordinateSystem(xCooSysModel) ); + else if( aViewServiceName == CHART2_COOSYSTEM_POLAR_VIEW_SERVICE_NAME ) + pRet.reset( new VPolarCoordinateSystem(xCooSysModel) ); + if(!pRet) + pRet.reset( new VCoordinateSystem(xCooSysModel) ); + return pRet; +} + +VCoordinateSystem::VCoordinateSystem( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) + : m_xCooSysModel(xCooSys) + , m_eLeftWallPos(CuboidPlanePosition_Left) + , m_eBackWallPos(CuboidPlanePosition_Back) + , m_eBottomPos(CuboidPlanePosition_Bottom) + , m_aExplicitScales(3) + , m_aExplicitIncrements(3) +{ + if( !m_xCooSysModel.is() || m_xCooSysModel->getDimension()<3 ) + { + m_aExplicitScales[2].Minimum = 1.0; + m_aExplicitScales[2].Maximum = 2.0; + m_aExplicitScales[2].Orientation = AxisOrientation_MATHEMATICAL; + } +} +VCoordinateSystem::~VCoordinateSystem() +{ +} + +void VCoordinateSystem::initPlottingTargets( const rtl::Reference< SvxShapeGroupAnyD >& xLogicTarget + , const rtl::Reference< SvxShapeGroupAnyD >& xFinalTarget + , rtl::Reference& xLogicTargetForSeriesBehindAxis ) +{ + OSL_PRECOND(xLogicTarget.is()&&xFinalTarget.is(),"no proper initialization parameters"); + //is only allowed to be called once + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + //create group shape for grids first thus axes are always painted above grids + if(nDimensionCount==2) + { + //create and add to target + m_xLogicTargetForGrids = ShapeFactory::createGroup2D( xLogicTarget ); + xLogicTargetForSeriesBehindAxis = ShapeFactory::createGroup2D( xLogicTarget ); + m_xLogicTargetForAxes = ShapeFactory::createGroup2D( xLogicTarget ); + } + else + { + //create and added to target + m_xLogicTargetForGrids = ShapeFactory::createGroup3D( xLogicTarget ); + xLogicTargetForSeriesBehindAxis = ShapeFactory::createGroup3D( xLogicTarget ); + m_xLogicTargetForAxes = ShapeFactory::createGroup3D( xLogicTarget ); + } + m_xFinalTarget = xFinalTarget; +} + +void VCoordinateSystem::setParticle( const OUString& rCooSysParticle ) +{ + m_aCooSysParticle = rCooSysParticle; +} + +void VCoordinateSystem::setTransformationSceneToScreen( + const drawing::HomogenMatrix& rMatrix ) +{ + m_aMatrixSceneToScreen = rMatrix; + + //correct transformation for axis + for (auto const& elem : m_aAxisMap) + { + VAxisBase* pVAxis = elem.second.get(); + if( pVAxis ) + { + if(pVAxis->getDimensionCount()==2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + } + } +} + +//better performance for big data +uno::Sequence< sal_Int32 > VCoordinateSystem::getCoordinateSystemResolution( + const awt::Size& rPageSize, const awt::Size& rPageResolution ) +{ + uno::Sequence aResolution( + std::max(m_xCooSysModel->getDimension(), 2)); + auto aResolutionRange = asNonConstRange(aResolution); + for( auto& i : aResolutionRange ) + i = 1000; + + ::basegfx::B3DTuple aScale( BaseGFXHelper::GetScaleFromMatrix( + BaseGFXHelper::HomogenMatrixToB3DHomMatrix( + m_aMatrixSceneToScreen ) ) ); + + double fCoosysWidth = fabs(aScale.getX()*FIXED_SIZE_FOR_3D_CHART_VOLUME); + double fCoosysHeight = fabs(aScale.getY()*FIXED_SIZE_FOR_3D_CHART_VOLUME); + + double fPageWidth = rPageSize.Width; + double fPageHeight = rPageSize.Height; + + //factor 2 to avoid rounding problems + sal_Int32 nXResolution = static_cast(2.0*static_cast(rPageResolution.Width)*fCoosysWidth/fPageWidth); + sal_Int32 nYResolution = static_cast(2.0*static_cast(rPageResolution.Height)*fCoosysHeight/fPageHeight); + + if( nXResolution < 10 ) + nXResolution = 10; + if( nYResolution < 10 ) + nYResolution = 10; + + if( getPropertySwapXAndYAxis() ) + std::swap(nXResolution,nYResolution); + + //2D + if( aResolution.getLength() == 2 ) + { + aResolutionRange[0]=nXResolution; + aResolutionRange[1]=nYResolution; + } + else + { + //this maybe can be optimized further ... + sal_Int32 nMaxResolution = std::max( nXResolution, nYResolution ); + nMaxResolution*=2; + for( auto& i : asNonConstRange(aResolution) ) + i = nMaxResolution; + } + + return aResolution; +} + +rtl::Reference< Axis > VCoordinateSystem::getAxisByDimension( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + if( m_xCooSysModel.is() ) + return m_xCooSysModel->getAxisByDimension2( nDimensionIndex, nAxisIndex ); + return nullptr; +} + +std::vector< Reference< beans::XPropertySet > > VCoordinateSystem::getGridListFromAxis( const rtl::Reference< Axis >& xAxis ) +{ + std::vector< Reference< beans::XPropertySet > > aRet; + + if( xAxis.is() ) + { + aRet.push_back( xAxis->getGridProperties() ); + auto aSubGrids( comphelper::sequenceToContainer > >( xAxis->getSubGridProperties() ) ); + aRet.insert( aRet.end(), aSubGrids.begin(), aSubGrids.end() ); + } + + return aRet; +} + +void VCoordinateSystem::impl_adjustDimension( sal_Int32& rDimensionIndex ) +{ + rDimensionIndex = std::clamp(rDimensionIndex, 0, 2); +} + +void VCoordinateSystem::impl_adjustDimensionAndIndex( sal_Int32& rDimensionIndex, sal_Int32& rAxisIndex ) const +{ + impl_adjustDimension( rDimensionIndex ); + + if( rAxisIndex < 0 || rAxisIndex > getMaximumAxisIndexByDimension(rDimensionIndex) ) + rAxisIndex = 0; +} + +void VCoordinateSystem::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider /*takes ownership*/ ) +{ + m_apExplicitCategoriesProvider.reset(pExplicitCategoriesProvider); +} + +ExplicitCategoriesProvider* VCoordinateSystem::getExplicitCategoriesProvider() +{ + return m_apExplicitCategoriesProvider.get(); +} + +std::vector< ExplicitScaleData > VCoordinateSystem::getExplicitScales( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + std::vector< ExplicitScaleData > aRet(m_aExplicitScales); + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + aRet[nDimensionIndex]=getExplicitScale( nDimensionIndex, nAxisIndex ); + + return aRet; +} + +std::vector< ExplicitIncrementData > VCoordinateSystem::getExplicitIncrements( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + std::vector< ExplicitIncrementData > aRet(m_aExplicitIncrements); + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + aRet[nDimensionIndex]=getExplicitIncrement( nDimensionIndex, nAxisIndex ); + + return aRet; +} + +ExplicitScaleData VCoordinateSystem::getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + ExplicitScaleData aRet; + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + + if( nAxisIndex == 0) + { + aRet = m_aExplicitScales[nDimensionIndex]; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tFullExplicitScaleMap::const_iterator aIt = m_aSecondaryExplicitScales.find( aFullAxisIndex ); + if( aIt != m_aSecondaryExplicitScales.end() ) + aRet = aIt->second; + else + aRet = m_aExplicitScales[nDimensionIndex]; + } + + return aRet; +} + +ExplicitIncrementData VCoordinateSystem::getExplicitIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const +{ + ExplicitIncrementData aRet; + + impl_adjustDimensionAndIndex( nDimensionIndex, nAxisIndex ); + + if( nAxisIndex == 0) + { + aRet = m_aExplicitIncrements[nDimensionIndex]; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + tFullExplicitIncrementMap::const_iterator aIt = m_aSecondaryExplicitIncrements.find( aFullAxisIndex ); + if( aIt != m_aSecondaryExplicitIncrements.end() ) + aRet = aIt->second; + else + aRet = m_aExplicitIncrements[nDimensionIndex]; + } + + return aRet; +} + +OUString VCoordinateSystem::createCIDForAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + OUString aAxisParticle( ObjectIdentifier::createParticleForAxis( nDimensionIndex, nAxisIndex ) ); + return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aAxisParticle ); +} +OUString VCoordinateSystem::createCIDForGrid( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + OUString aGridParticle( ObjectIdentifier::createParticleForGrid( nDimensionIndex, nAxisIndex ) ); + return ObjectIdentifier::createClassifiedIdentifierForParticles( m_aCooSysParticle, aGridParticle ); +} + +sal_Int32 VCoordinateSystem::getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) const +{ + sal_Int32 nRet = 0; + for (auto const& elem : m_aSecondaryExplicitScales) + { + if(elem.first.first==nDimensionIndex) + { + sal_Int32 nLocalIdx = elem.first.second; + if( nRet < nLocalIdx ) + nRet = nLocalIdx; + } + } + return nRet; +} + +void VCoordinateSystem::createVAxisList( + const rtl::Reference<::chart::ChartModel> & /* xChartDoc */ + , const awt::Size& /* rFontReferenceSize */ + , const awt::Rectangle& /* rMaximumSpaceForLabels */ + , bool /* bLimitSpaceForLabels */ + ) +{ +} + +void VCoordinateSystem::initVAxisInList() +{ +} +void VCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ +} + +void VCoordinateSystem::prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) +{ + bool bDateAxisX = (rScaleAutomatism.getScale().AxisType == AxisType::DATE) && (nDimIndex == 0); + if( bDateAxisX ) + { + // This is a date X dimension. Determine proper time resolution. + sal_Int32 nTimeResolution = css::chart::TimeUnit::MONTH; + if( !(rScaleAutomatism.getScale().TimeIncrement.TimeResolution >>= nTimeResolution) ) + { + nTimeResolution = m_aMergedMinMaxSupplier.calculateTimeResolutionOnXAxis(); + rScaleAutomatism.setAutomaticTimeResolution( nTimeResolution ); + } + m_aMergedMinMaxSupplier.setTimeResolutionOnXAxis( nTimeResolution, rScaleAutomatism.getNullDate() ); + } + + double fMin = std::numeric_limits::infinity(); + double fMax = -std::numeric_limits::infinity(); + if( nDimIndex == 0 ) + { + // x dimension + fMin = m_aMergedMinMaxSupplier.getMinimumX(); + fMax = m_aMergedMinMaxSupplier.getMaximumX(); + } + else if( nDimIndex == 1 ) + { + // y dimension + ExplicitScaleData aScale = getExplicitScale( 0, 0 ); + double fMaximum = aScale.Maximum; + if (!aScale.m_bShiftedCategoryPosition && aScale.AxisType == AxisType::DATE) + { + // tdf#146066 Increase maximum date value by one month/year, + // because the automatic scaling of the Y axis was incorrect when the last Y value was the highest value. + Date aMaxDate(aScale.NullDate); + aMaxDate.AddDays(::rtl::math::approxFloor(fMaximum)); + switch (aScale.TimeResolution) + { + case css::chart::TimeUnit::MONTH: + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate, 1); + break; + case css::chart::TimeUnit::YEAR: + aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate, 1); + break; + } + fMaximum = aMaxDate - aScale.NullDate; + } + fMin = m_aMergedMinMaxSupplier.getMinimumYInRange(aScale.Minimum,aScale.Maximum, nAxisIndex); + fMax = m_aMergedMinMaxSupplier.getMaximumYInRange(aScale.Minimum, fMaximum, nAxisIndex); + } + else if( nDimIndex == 2 ) + { + // z dimension + fMin = m_aMergedMinMaxSupplier.getMinimumZ(); + fMax = m_aMergedMinMaxSupplier.getMaximumZ(); + } + + //merge our values with those already contained in rScaleAutomatism + rScaleAutomatism.expandValueRange( fMin, fMax ); + + rScaleAutomatism.setAutoScalingOptions( + m_aMergedMinMaxSupplier.isExpandBorderToIncrementRhythm( nDimIndex ), + m_aMergedMinMaxSupplier.isExpandIfValuesCloseToBorder( nDimIndex ), + m_aMergedMinMaxSupplier.isExpandWideValuesToZero( nDimIndex ), + m_aMergedMinMaxSupplier.isExpandNarrowValuesTowardZero( nDimIndex ) ); + + if (bDateAxisX) + return; + + VAxisBase* pVAxis = getVAxis(nDimIndex, nAxisIndex); + if( pVAxis ) + rScaleAutomatism.setMaximumAutoMainIncrementCount( pVAxis->estimateMaximumAutoMainIncrementCount() ); +} + +VAxisBase* VCoordinateSystem::getVAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + VAxisBase* pRet = nullptr; + + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + + tVAxisMap::const_iterator aIt = m_aAxisMap.find( aFullAxisIndex ); + if (aIt != m_aAxisMap.cend()) + pRet = aIt->second.get(); + + return pRet; +} + +void VCoordinateSystem::setExplicitScaleAndIncrement( + sal_Int32 nDimensionIndex + , sal_Int32 nAxisIndex + , const ExplicitScaleData& rExplicitScale + , const ExplicitIncrementData& rExplicitIncrement ) +{ + impl_adjustDimension( nDimensionIndex ); + + if( nAxisIndex==0 ) + { + m_aExplicitScales[nDimensionIndex]=rExplicitScale; + m_aExplicitIncrements[nDimensionIndex]=rExplicitIncrement; + } + else + { + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aSecondaryExplicitScales[aFullAxisIndex] = rExplicitScale; + m_aSecondaryExplicitIncrements[aFullAxisIndex] = rExplicitIncrement; + } +} + +void VCoordinateSystem::set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ) +{ + m_eLeftWallPos = eLeftWallPos; + m_eBackWallPos = eBackWallPos; + m_eBottomPos = eBottomPos; +} + +void VCoordinateSystem::createMaximumAxesLabels() +{ + for (auto const&[unused, pVAxis] : m_aAxisMap) + { + (void)unused; + if (pVAxis) + { + if (pVAxis->getDimensionCount() == 2) + pVAxis->setTransformationSceneToScreen(m_aMatrixSceneToScreen); + pVAxis->createMaximumLabels(); + } + } +} +void VCoordinateSystem::createAxesLabels() +{ + for (auto const&[unused, pVAxis] : m_aAxisMap) + { + (void)unused; + if (pVAxis) + { + if (pVAxis->getDimensionCount() == 2) + pVAxis->setTransformationSceneToScreen(m_aMatrixSceneToScreen); + pVAxis->createLabels(); + } + } +} + +void VCoordinateSystem::updatePositions() +{ + for (auto const&[unused, pVAxis] : m_aAxisMap) + { + (void)unused; + if (pVAxis) + { + if (pVAxis->getDimensionCount() == 2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->updatePositions(); + } + } +} + +void VCoordinateSystem::createAxesShapes() +{ + for (auto const&[aFullAxisIndex, pVAxis] : m_aAxisMap) + { + if (pVAxis) + { + auto const&[nDimensionIndex, nAxisIndex] = aFullAxisIndex; + + if (pVAxis->getDimensionCount() == 2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + + if (nAxisIndex == 0) + { + if (nDimensionIndex == 0) + { + if( m_aExplicitScales[1].AxisType!=AxisType::CATEGORY ) + pVAxis->setExtraLinePositionAtOtherAxis( + m_aExplicitScales[1].Origin ); + } + else if (nDimensionIndex == 1) + { + if( m_aExplicitScales[0].AxisType!=AxisType::CATEGORY ) + pVAxis->setExtraLinePositionAtOtherAxis( + m_aExplicitScales[0].Origin ); + } + } + + pVAxis->createShapes(); + } + } +} +void VCoordinateSystem::createGridShapes() +{ +} +void VCoordinateSystem::addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + m_aMergedMinMaxSupplier.addMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier); +} + +bool VCoordinateSystem::hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ) +{ + return m_aMergedMinMaxSupplier.hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier); +} + +void VCoordinateSystem::clearMinimumAndMaximumSupplierList() +{ + m_aMergedMinMaxSupplier.clearMinimumAndMaximumSupplierList(); +} + +bool VCoordinateSystem::getPropertySwapXAndYAxis() const +{ + bool bSwapXAndY = false; + if( m_xCooSysModel.is()) try + { + m_xCooSysModel->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return bSwapXAndY; +} + +bool VCoordinateSystem::needSeriesNamesForAxis() const +{ + return ( m_xCooSysModel.is() && m_xCooSysModel->getDimension() == 3 ); +} +void VCoordinateSystem::setSeriesNamesForAxis( const Sequence< OUString >& rSeriesNames ) +{ + m_aSeriesNamesForZAxis = rSeriesNames; +} + +sal_Int32 VCoordinateSystem::getNumberFormatKeyForAxis( + const rtl::Reference< Axis >& xAxis + , const rtl::Reference<::chart::ChartModel>& xChartDoc) +{ + return ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + xAxis, m_xCooSysModel, xChartDoc); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarAngleAxis.cxx b/chart2/source/view/axes/VPolarAngleAxis.cxx new file mode 100644 index 000000000..13f66cec9 --- /dev/null +++ b/chart2/source/view/axes/VPolarAngleAxis.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "VPolarAngleAxis.hxx" +#include "VPolarGrid.hxx" +#include +#include +#include +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VPolarAngleAxis::VPolarAngleAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ) + : VPolarAxis( rAxisProperties, xNumberFormatsSupplier, 0/*nDimensionIndex*/, nDimensionCount ) +{ +} + +VPolarAngleAxis::~VPolarAngleAxis() +{ +} + +void VPolarAngleAxis::createTextShapes_ForAngleAxis( + const rtl::Reference& xTarget + , EquidistantTickIter& rTickIter + , AxisLabelProperties const & rAxisLabelProperties + , double fLogicRadius + , double fLogicZ ) +{ + FixedNumberFormatter aFixedNumberFormatter( + m_xNumberFormatsSupplier, rAxisLabelProperties.m_nNumberFormatKey ); + + //prepare text properties for multipropertyset-interface of shape + tNameSequence aPropNames; + tAnySequence aPropValues; + + uno::Reference< beans::XPropertySet > xProps( m_aAxisProperties.m_xAxisModel ); + PropertyMapper::getTextLabelMultiPropertyLists( xProps, aPropNames, aPropValues, false, -1, false, false ); + LabelPositionHelper::doDynamicFontResize( aPropValues, aPropNames, xProps + , rAxisLabelProperties.m_aFontReferenceSize ); + + uno::Any* pColorAny = PropertyMapper::getValuePointer(aPropValues,aPropNames,u"CharColor"); + Color nColor = COL_AUTO; + if(pColorAny) + *pColorAny >>= nColor; + + const uno::Sequence< OUString >* pLabels = m_bUseTextLabels? &m_aTextLabels : nullptr; + + //TickInfo* pLastVisibleNeighbourTickInfo = NULL; + sal_Int32 nTick = 0; + + for( TickInfo* pTickInfo = rTickIter.firstInfo() + ; pTickInfo + ; pTickInfo = rTickIter.nextInfo(), nTick++ ) + { + //don't create labels which does not fit into the rhythm + if( nTick%rAxisLabelProperties.m_nRhythm != 0) + continue; + + //don't create labels for invisible ticks + if( !pTickInfo->bPaintIt ) + continue; + + //if NO OVERLAP -> don't create labels where the + //anchor position is the same as for the last label + //@todo + + if(!pTickInfo->xTextShape.is()) + { + //create single label + bool bHasExtraColor=false; + Color nExtraColor; + + OUString aLabel; + if(pLabels) + { + sal_Int32 nIndex = static_cast< sal_Int32 >(pTickInfo->getUnscaledTickValue()) - 1; //first category (index 0) matches with real number 1.0 + if( nIndex>=0 && nIndexgetLength() ) + aLabel = (*pLabels)[nIndex]; + } + else + aLabel = aFixedNumberFormatter.getFormattedString( pTickInfo->getUnscaledTickValue(), nExtraColor, bHasExtraColor ); + + if(pColorAny) + *pColorAny <<= bHasExtraColor?nExtraColor:nColor; + + double fLogicAngle = pTickInfo->getUnscaledTickValue(); + + LabelAlignment eLabelAlignment(LABEL_ALIGN_CENTER); + PolarLabelPositionHelper aPolarLabelPositionHelper(m_pPosHelper.get(), 2/*nDimensionCount*/, xTarget); + sal_Int32 nScreenValueOffsetInRadiusDirection = m_aAxisLabelProperties.m_aMaximumSpaceForLabels.Height/15; + awt::Point aAnchorScreenPosition2D( aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues( + eLabelAlignment, fLogicAngle, fLogicRadius, fLogicZ, nScreenValueOffsetInRadiusDirection )); + LabelPositionHelper::changeTextAdjustment( aPropValues, aPropNames, eLabelAlignment ); + + // #i78696# use mathematically correct rotation now + const double fRotationAnglePi(-basegfx::deg2rad(rAxisLabelProperties.m_fRotationAngleDegree)); + + uno::Any aATransformation = ShapeFactory::makeTransformation( aAnchorScreenPosition2D, fRotationAnglePi ); + OUString aStackedLabel = ShapeFactory::getStackedString( aLabel, rAxisLabelProperties.m_bStackCharacters ); + + pTickInfo->xTextShape = ShapeFactory::createText( xTarget, aStackedLabel, aPropNames, aPropValues, aATransformation ); + } + + //if NO OVERLAP -> remove overlapping shapes + //@todo + } +} + +void VPolarAngleAxis::createMaximumLabels() +{ + if( !prepareShapeCreation() ) + return; + + createLabels(); +} + +void VPolarAngleAxis::updatePositions() +{ + //todo: really only update the positions + + if( !prepareShapeCreation() ) + return; + + createLabels(); +} + +void VPolarAngleAxis::createLabels() +{ + if( !prepareShapeCreation() ) + return; + + double fLogicRadius = m_pPosHelper->getOuterLogicRadius(); + + if( !m_aAxisProperties.m_bDisplayLabels ) + return; + + //create tick mark text shapes + //@todo: iterate through all tick depth which should be labeled + + EquidistantTickIter aTickIter( m_aAllTickInfos, m_aIncrement, 0 ); + updateUnscaledValuesAtTicks( aTickIter ); + + removeTextShapesFromTicks(); + + AxisLabelProperties aAxisLabelProperties( m_aAxisLabelProperties ); + aAxisLabelProperties.m_bOverlapAllowed = true; + double const fLogicZ = 1.0;//as defined + createTextShapes_ForAngleAxis( m_xTextTarget, aTickIter + , aAxisLabelProperties + , fLogicRadius, fLogicZ + ); + + //no staggering for polar angle axis +} + +void VPolarAngleAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + double fLogicRadius = m_pPosHelper->getOuterLogicRadius(); + double const fLogicZ = 1.0;//as defined + + //create axis main lines + drawing::PointSequenceSequence aPoints(1); + VPolarGrid::createLinePointSequence_ForAngleAxis( aPoints, m_aAllTickInfos, m_aIncrement, m_aScale, m_pPosHelper.get(), fLogicRadius, fLogicZ ); + rtl::Reference xShape = ShapeFactory::createLine2D( + m_xGroupShape_Shapes, aPoints, &m_aAxisProperties.m_aLineProperties ); + //because of this name this line will be used for marking the axis + ::chart::ShapeFactory::setShapeName( xShape, "MarkHandles" ); + + //create labels + createLabels(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarAngleAxis.hxx b/chart2/source/view/axes/VPolarAngleAxis.hxx new file mode 100644 index 000000000..0e0774e9e --- /dev/null +++ b/chart2/source/view/axes/VPolarAngleAxis.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VPolarAxis.hxx" +#include "Tickmarks_Equidistant.hxx" + +namespace chart +{ + +class VPolarAngleAxis : public VPolarAxis +{ +public: + VPolarAngleAxis( const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ); + virtual ~VPolarAngleAxis() override; + + virtual void createMaximumLabels() override; + virtual void createLabels() override; + virtual void updatePositions() override; + + virtual void createShapes() override; + +private: //methods + void createTextShapes_ForAngleAxis( + const rtl::Reference& xTarget + , EquidistantTickIter& rTickIter + , AxisLabelProperties const & rAxisLabelProperties + , double fLogicRadius, double fLogicZ ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarAxis.cxx b/chart2/source/view/axes/VPolarAxis.cxx new file mode 100644 index 000000000..d9dfe08ec --- /dev/null +++ b/chart2/source/view/axes/VPolarAxis.cxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VPolarAxis.hxx" +#include "VPolarAngleAxis.hxx" +#include "VPolarRadiusAxis.hxx" +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +std::shared_ptr VPolarAxis::createAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) +{ + if( nDimensionIndex==0 ) + return std::make_shared( rAxisProperties, xNumberFormatsSupplier, nDimensionCount ); + return std::make_shared( rAxisProperties, xNumberFormatsSupplier, nDimensionCount ); +} + +VPolarAxis::VPolarAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ) + : VAxisBase( nDimensionIndex, nDimensionCount, rAxisProperties, xNumberFormatsSupplier ) + , m_pPosHelper( new PolarPlottingPositionHelper() ) +{ + PlotterBase::m_pPosHelper = m_pPosHelper.get(); +} + +VPolarAxis::~VPolarAxis() +{ +} + +void VPolarAxis::setIncrements( std::vector< ExplicitIncrementData >&& rIncrements ) +{ + m_aIncrements = std::move(rIncrements); +} + +bool VPolarAxis::isAnythingToDraw() +{ + return ( m_nDimension==2 && VAxisBase::isAnythingToDraw() ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarAxis.hxx b/chart2/source/view/axes/VPolarAxis.hxx new file mode 100644 index 000000000..42e22ae7d --- /dev/null +++ b/chart2/source/view/axes/VPolarAxis.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VAxisBase.hxx" +#include + +namespace chart +{ + +class PolarPlottingPositionHelper; + +class VPolarAxis : public VAxisBase +{ +public: + static std::shared_ptr createAxis( const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + + void setIncrements( std::vector< ExplicitIncrementData >&& rIncrements ); + + virtual bool isAnythingToDraw() override; + + virtual ~VPolarAxis() override; + +protected: + VPolarAxis( const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount ); + +protected: //member + std::unique_ptr m_pPosHelper; + std::vector< ExplicitIncrementData > m_aIncrements; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.cxx b/chart2/source/view/axes/VPolarCoordinateSystem.cxx new file mode 100644 index 000000000..e287120f9 --- /dev/null +++ b/chart2/source/view/axes/VPolarCoordinateSystem.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VPolarCoordinateSystem.hxx" +#include "VPolarGrid.hxx" +#include "VPolarAxis.hxx" +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VPolarCoordinateSystem::VPolarCoordinateSystem( const rtl::Reference< BaseCoordinateSystem >& xCooSys ) + : VCoordinateSystem(xCooSys) +{ +} + +VPolarCoordinateSystem::~VPolarCoordinateSystem() +{ +} + +//better performance for big data +uno::Sequence< sal_Int32 > VPolarCoordinateSystem::getCoordinateSystemResolution( + const awt::Size& rPageSize, const awt::Size& rPageResolution ) +{ + uno::Sequence< sal_Int32 > aResolution( VCoordinateSystem::getCoordinateSystemResolution( rPageSize, rPageResolution) ); + + if( aResolution.getLength() >= 2 ) + { + auto pResolution = aResolution.getArray(); + if( getPropertySwapXAndYAxis() ) + { + pResolution[0]/=2;//radius + pResolution[1]*=4;//outer circle resolution + } + else + { + pResolution[0]*=4;//outer circle resolution + pResolution[1]/=2;//radius + } + } + + return aResolution; +} + +void VPolarCoordinateSystem::createVAxisList( + const rtl::Reference<::chart::ChartModel> & xChartDoc + , const awt::Size& rFontReferenceSize + , const awt::Rectangle& rMaximumSpaceForLabels + , bool //bLimitSpaceForLabels + ) +{ + // note: using xChartDoc itself as XNumberFormatsSupplier would cause + // a leak from VPolarAxis due to cyclic reference + uno::Reference const xNumberFormatsSupplier( + dynamic_cast(*xChartDoc).getNumberFormatsSupplier()); + + m_aAxisMap.clear(); + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + sal_Int32 nDimensionIndex = 0; + + //create angle axis (dimension index 0) + for( nDimensionIndex = 0; nDimensionIndex < nDimensionCount; nDimensionIndex++ ) + { + sal_Int32 nMaxAxisIndex = m_xCooSysModel->getMaximumAxisIndexByDimension(nDimensionIndex); + for( sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; nAxisIndex++ ) + { + rtl::Reference< Axis > xAxis = getAxisByDimension(nDimensionIndex,nAxisIndex); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + AxisProperties aAxisProperties(xAxis,getExplicitCategoriesProvider()); + aAxisProperties.init(); + if(aAxisProperties.m_bDisplayLabels) + aAxisProperties.m_nNumberFormatKey = getNumberFormatKeyForAxis(xAxis, xChartDoc); + + std::shared_ptr< VAxisBase > apVAxis( VPolarAxis::createAxis( aAxisProperties,xNumberFormatsSupplier,nDimensionIndex,nDimensionCount) ); + tFullAxisIndex aFullAxisIndex( nDimensionIndex, nAxisIndex ); + m_aAxisMap[aFullAxisIndex] = apVAxis; + + apVAxis->initAxisLabelProperties(rFontReferenceSize,rMaximumSpaceForLabels); + } + } +} + +void VPolarCoordinateSystem::initVAxisInList() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for (auto const& elem : m_aAxisMap) + { + VAxisBase* pVAxis = elem.second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = elem.first.first; + sal_Int32 nAxisIndex = elem.first.second; + pVAxis->setExplicitScaleAndIncrement( getExplicitScale( nDimensionIndex, nAxisIndex ), getExplicitIncrement(nDimensionIndex, nAxisIndex) ); + pVAxis->initPlotter(m_xLogicTargetForAxes,m_xFinalTarget + , createCIDForAxis( nDimensionIndex, nAxisIndex ) ); + VPolarAxis* pVPolarAxis = dynamic_cast< VPolarAxis* >( pVAxis ); + if( pVPolarAxis ) + pVPolarAxis->setIncrements( getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + if(nDimensionCount==2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( getExplicitScales( nDimensionIndex, nAxisIndex ), bSwapXAndY ); + } + } +} + +void VPolarCoordinateSystem::updateScalesAndIncrementsOnAxes() +{ + if(!m_xLogicTargetForAxes.is() || !m_xFinalTarget.is() || !m_xCooSysModel.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for (auto const& elem : m_aAxisMap) + { + VAxisBase* pVAxis = elem.second.get(); + if( pVAxis ) + { + sal_Int32 nDimensionIndex = elem.first.first; + sal_Int32 nAxisIndex = elem.first.second; + pVAxis->setExplicitScaleAndIncrement( getExplicitScale( nDimensionIndex, nAxisIndex ), getExplicitIncrement(nDimensionIndex, nAxisIndex) ); + VPolarAxis* pVPolarAxis = dynamic_cast< VPolarAxis* >( pVAxis ); + if( pVPolarAxis ) + pVPolarAxis->setIncrements( getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + if(nDimensionCount==2) + pVAxis->setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + pVAxis->setScales( getExplicitScales( nDimensionIndex, nAxisIndex ), bSwapXAndY ); + } + } +} + +void VPolarCoordinateSystem::createGridShapes() +{ + if(!m_xLogicTargetForGrids.is() || !m_xFinalTarget.is() ) + return; + + sal_Int32 nDimensionCount = m_xCooSysModel->getDimension(); + bool bSwapXAndY = getPropertySwapXAndYAxis(); + + for( sal_Int32 nDimensionIndex=0; nDimensionIndex<3; nDimensionIndex++) + { + sal_Int32 nAxisIndex = MAIN_AXIS_INDEX; + + rtl::Reference< Axis > xAxis = AxisHelper::getAxis( nDimensionIndex, nAxisIndex, m_xCooSysModel ); + if(!xAxis.is() || !AxisHelper::shouldAxisBeDisplayed( xAxis, m_xCooSysModel )) + continue; + + VPolarGrid aGrid(nDimensionIndex,nDimensionCount,getGridListFromAxis( xAxis )); + aGrid.setIncrements( getExplicitIncrements( nDimensionIndex, nAxisIndex ) ); + aGrid.initPlotter(m_xLogicTargetForGrids,m_xFinalTarget + , createCIDForGrid( nDimensionIndex, nAxisIndex ) ); + if(nDimensionCount==2) + aGrid.setTransformationSceneToScreen( m_aMatrixSceneToScreen ); + aGrid.setScales( getExplicitScales( nDimensionIndex, nAxisIndex), bSwapXAndY ); + aGrid.createShapes(); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarCoordinateSystem.hxx b/chart2/source/view/axes/VPolarCoordinateSystem.hxx new file mode 100644 index 000000000..9659660a5 --- /dev/null +++ b/chart2/source/view/axes/VPolarCoordinateSystem.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ + +class VPolarCoordinateSystem : public VCoordinateSystem +{ +public: + VPolarCoordinateSystem() = delete; + explicit VPolarCoordinateSystem( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + virtual ~VPolarCoordinateSystem() override; + + //better performance for big data + virtual css::uno::Sequence< sal_Int32 > getCoordinateSystemResolution( const css::awt::Size& rPageSize + , const css::awt::Size& rPageResolution ) override; + + virtual void createVAxisList( + const rtl::Reference<::chart::ChartModel> & xChartDoc + , const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels + , bool bLimitSpaceForLabels ) override; + + virtual void initVAxisInList() override; + virtual void updateScalesAndIncrementsOnAxes() override; + + virtual void createGridShapes() override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarGrid.cxx b/chart2/source/view/axes/VPolarGrid.cxx new file mode 100644 index 000000000..e876c83b2 --- /dev/null +++ b/chart2/source/view/axes/VPolarGrid.cxx @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VPolarGrid.hxx" +#include "VCartesianGrid.hxx" +#include "Tickmarks.hxx" +#include +#include +#include +#include +#include +#include "Tickmarks_Equidistant.hxx" + +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; + +VPolarGrid::VPolarGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , std::vector< Reference< beans::XPropertySet > > aGridPropertiesList ) + : VAxisOrGridBase( nDimensionIndex, nDimensionCount ) + , m_aGridPropertiesList( std::move(aGridPropertiesList) ) + , m_pPosHelper( new PolarPlottingPositionHelper() ) +{ + PlotterBase::m_pPosHelper = m_pPosHelper.get(); +} + +VPolarGrid::~VPolarGrid() +{ +} + +void VPolarGrid::setIncrements( std::vector< ExplicitIncrementData >&& rIncrements ) +{ + m_aIncrements = std::move(rIncrements); +} + +void VPolarGrid::getAllTickInfos( sal_Int32 nDimensionIndex, TickInfoArraysType& rAllTickInfos ) const +{ + const std::vector& rScales = m_pPosHelper->getScales(); + TickFactory aTickFactory(rScales[nDimensionIndex], m_aIncrements[nDimensionIndex]); + aTickFactory.getAllTicks( rAllTickInfos ); +} + +void VPolarGrid::createLinePointSequence_ForAngleAxis( + drawing::PointSequenceSequence& rPoints + , TickInfoArraysType& rAllTickInfos + , const ExplicitIncrementData& rIncrement + , const ExplicitScaleData& rScale + , PolarPlottingPositionHelper const * pPosHelper + , double fLogicRadius, double fLogicZ ) +{ + Reference< XScaling > xInverseScaling; + if( rScale.Scaling.is() ) + xInverseScaling = rScale.Scaling->getInverseScaling(); + + sal_Int32 nTick = 0; + EquidistantTickIter aIter( rAllTickInfos, rIncrement, 0 ); + auto pPoints = rPoints.getArray(); + for( TickInfo* pTickInfo = aIter.firstInfo() + ; pTickInfo + ; pTickInfo = aIter.nextInfo(), nTick++ ) + { + if(nTick>=rPoints[0].getLength()) + pPoints[0].realloc(rPoints[0].getLength()+30); + auto pPoints0 = pPoints[0].getArray(); + + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + double fLogicAngle = pTickInfo->getUnscaledTickValue(); + + drawing::Position3D aScenePosition3D( pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicRadius, fLogicZ ) ); + pPoints0[nTick].X = static_cast(aScenePosition3D.PositionX); + pPoints0[nTick].Y = static_cast(aScenePosition3D.PositionY); + } + if(rPoints[0].getLength()>1) + { + pPoints[0].realloc(nTick+1); + auto pPoints0 = pPoints[0].getArray(); + pPoints0[nTick].X = rPoints[0][0].X; + pPoints0[nTick].Y = rPoints[0][0].Y; + } + else + pPoints[0].realloc(0); +} +#ifdef NOTYET +void VPolarGrid::create2DAngleGrid( const Reference< drawing::XShapes >& xLogicTarget + , TickInfoArraysType& /* rRadiusTickInfos */ + , TickInfoArraysType& rAngleTickInfos + , const std::vector& rLinePropertiesList ) +{ + Reference< drawing::XShapes > xMainTarget( + createGroupShape( xLogicTarget, m_aCID ) ); + + const std::vector& rScales = m_pPosHelper->getScales(); + const ExplicitScaleData& rAngleScale = rScales[0]; + Reference< XScaling > xInverseScaling( NULL ); + if( rAngleScale.Scaling.is() ) + xInverseScaling = rAngleScale.Scaling->getInverseScaling(); + + double fLogicInnerRadius = m_pPosHelper->getInnerLogicRadius(); + double fLogicOuterRadius = m_pPosHelper->getOuterLogicRadius(); + + sal_Int32 nLinePropertiesCount = rLinePropertiesList.size(); + if(nLinePropertiesCount) + { + double fLogicZ = 1.0;//as defined + sal_Int32 nDepth=0; + //create axis main lines + drawing::PointSequenceSequence aAllPoints; + for (auto const& tick : rAngleTickInfos[0]) + { + if( !tick.bPaintIt ) + continue; + + //xxxxx rTickInfo.updateUnscaledValue( xInverseScaling ); + double fLogicAngle = tick.getUnscaledTickValue(); + + drawing::PointSequenceSequence aPoints(1); + aPoints[0].realloc(2); + drawing::Position3D aScenePositionStart( m_pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicInnerRadius, fLogicZ ) ); + drawing::Position3D aScenePositionEnd( m_pPosHelper->transformAngleRadiusToScene( fLogicAngle, fLogicOuterRadius, fLogicZ ) ); + aPoints[0][0].X = static_cast(aScenePositionStart.PositionX); + aPoints[0][0].Y = static_cast(aScenePositionStart.PositionY); + aPoints[0][1].X = static_cast(aScenePositionEnd.PositionX); + aPoints[0][1].Y = static_cast(aScenePositionEnd.PositionY); + appendPointSequence( aAllPoints, aPoints ); + } + + rtl::Reference xShape = ShapeFactory::createLine2D( + xMainTarget, aAllPoints, &rLinePropertiesList[nDepth] ); + //because of this name this line will be used for marking + m_pShapeFactory->setShapeName( xShape, "MarkHandles" ); + } +} +#endif + +void VPolarGrid::create2DRadiusGrid( const rtl::Reference& xLogicTarget + , TickInfoArraysType& rRadiusTickInfos + , TickInfoArraysType& rAngleTickInfos + , const std::vector& rLinePropertiesList ) +{ + rtl::Reference xMainTarget = + createGroupShape( xLogicTarget, m_aCID ); + + const std::vector& rScales = m_pPosHelper->getScales(); + const ExplicitScaleData& rRadiusScale = rScales[1]; + const ExplicitScaleData& rAngleScale = rScales[0]; + const ExplicitIncrementData& rAngleIncrement = m_aIncrements[0]; + Reference< XScaling > xInverseRadiusScaling; + if( rRadiusScale.Scaling.is() ) + xInverseRadiusScaling = rRadiusScale.Scaling->getInverseScaling(); + + sal_Int32 nLinePropertiesCount = rLinePropertiesList.size(); + TickInfoArraysType::iterator aDepthIter = rRadiusTickInfos.begin(); + const TickInfoArraysType::const_iterator aDepthEnd = rRadiusTickInfos.end(); + for( sal_Int32 nDepth=0 + ; aDepthIter != aDepthEnd && nDepth < nLinePropertiesCount + ; ++aDepthIter, nDepth++ ) + { + if( !rLinePropertiesList[nDepth].isLineVisible() ) + continue; + + rtl::Reference xTarget( xMainTarget ); + if( nDepth > 0 ) + { + xTarget = createGroupShape( xLogicTarget + , ObjectIdentifier::addChildParticle( m_aCID, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_SUBGRID, nDepth-1 ) ) + ); + if(!xTarget.is()) + xTarget = xMainTarget; + } + + //create axis main lines + drawing::PointSequenceSequence aAllPoints; + for (auto const& tick : *aDepthIter) + { + if( !tick.bPaintIt ) + continue; + + //xxxxx rTickInfo.updateUnscaledValue( xInverseRadiusScaling ); + double fLogicRadius = tick.getUnscaledTickValue(); + double const fLogicZ = 1.0;//as defined + + drawing::PointSequenceSequence aPoints(1); + VPolarGrid::createLinePointSequence_ForAngleAxis( aPoints, rAngleTickInfos + , rAngleIncrement, rAngleScale, m_pPosHelper.get(), fLogicRadius, fLogicZ ); + if(aPoints[0].getLength()) + appendPointSequence( aAllPoints, aPoints ); + } + + rtl::Reference xShape = ShapeFactory::createLine2D( + xTarget, aAllPoints, &rLinePropertiesList[nDepth] ); + //because of this name this line will be used for marking + ::chart::ShapeFactory::setShapeName( xShape, "MarkHandles" ); + } +} + +void VPolarGrid::createShapes() +{ + OSL_PRECOND(m_xLogicTarget.is()&&m_xFinalTarget.is(),"Axis is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + if(m_aGridPropertiesList.empty()) + return; + + //create all scaled tickmark values + TickInfoArraysType aAngleTickInfos; + TickInfoArraysType aRadiusTickInfos; + getAllTickInfos( 0, aAngleTickInfos ); + getAllTickInfos( 1, aRadiusTickInfos ); + + std::vector aLinePropertiesList; + VCartesianGrid::fillLinePropertiesFromGridModel( aLinePropertiesList, m_aGridPropertiesList ); + + //create tick mark line shapes + if(m_nDimension==2) + { + if(m_nDimensionIndex==1) + create2DRadiusGrid( m_xLogicTarget, aRadiusTickInfos, aAngleTickInfos, aLinePropertiesList ); + //else //no Angle Grid so far as this equals exactly the y axis positions + // create2DAngleGrid( m_xLogicTarget, aRadiusTickInfos, aAngleTickInfos, aLinePropertiesList ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarGrid.hxx b/chart2/source/view/axes/VPolarGrid.hxx new file mode 100644 index 000000000..9b15d0e5b --- /dev/null +++ b/chart2/source/view/axes/VPolarGrid.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VAxisOrGridBase.hxx" +#include "Tickmarks.hxx" +#include +#include + +namespace chart { struct VLineProperties; } + +namespace chart +{ + +class PolarPlottingPositionHelper; + +class VPolarGrid : public VAxisOrGridBase +{ +// public methods +public: + VPolarGrid( sal_Int32 nDimensionIndex, sal_Int32 nDimensionCount + , std::vector< + css::uno::Reference< css::beans::XPropertySet > > aGridPropertiesList //main grid, subgrid, subsubgrid etc + ); + virtual ~VPolarGrid() override; + + virtual void createShapes() override; + + void setIncrements( std::vector< ExplicitIncrementData >&& rIncrements ); + + static void createLinePointSequence_ForAngleAxis( + css::drawing::PointSequenceSequence& rPoints + , TickInfoArraysType& rAllTickInfos + , const ExplicitIncrementData& rIncrement + , const ExplicitScaleData& rScale + , PolarPlottingPositionHelper const * pPosHelper + , double fLogicRadius, double fLogicZ ); + +private: //member + std::vector< + css::uno::Reference< css::beans::XPropertySet > > m_aGridPropertiesList;//main grid, subgrid, subsubgrid etc + std::unique_ptr m_pPosHelper; + std::vector< ExplicitIncrementData > m_aIncrements; + + void getAllTickInfos( sal_Int32 nDimensionIndex, TickInfoArraysType& rAllTickInfos ) const; + + void create2DRadiusGrid( const rtl::Reference& xLogicTarget + , TickInfoArraysType& rRadiusTickInfos + , TickInfoArraysType& rAngleTickInfos + , const std::vector& rLinePropertiesList ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarRadiusAxis.cxx b/chart2/source/view/axes/VPolarRadiusAxis.cxx new file mode 100644 index 000000000..f93315410 --- /dev/null +++ b/chart2/source/view/axes/VPolarRadiusAxis.cxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VPolarRadiusAxis.hxx" +#include "VCartesianAxis.hxx" +#include +#include +#include +#include "Tickmarks_Equidistant.hxx" + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VPolarRadiusAxis::VPolarRadiusAxis( const AxisProperties& rAxisProperties + , const uno::Reference< util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ) + : VPolarAxis( rAxisProperties, xNumberFormatsSupplier, 1/*nDimensionIndex*/, nDimensionCount ) +{ + m_aAxisProperties.maLabelAlignment.mfLabelDirection = 0.0; + m_aAxisProperties.maLabelAlignment.mfInnerTickDirection = 0.0; + m_aAxisProperties.maLabelAlignment.meAlignment = LABEL_ALIGN_RIGHT; + m_aAxisProperties.m_bIsMainAxis=false; + m_aAxisProperties.init(); + + m_apAxisWithLabels.reset( new VCartesianAxis( + m_aAxisProperties,xNumberFormatsSupplier,1/*nDimensionIndex*/,nDimensionCount + ,new PolarPlottingPositionHelper() ) ); +} + +VPolarRadiusAxis::~VPolarRadiusAxis() +{ +} + +void VPolarRadiusAxis::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + VPolarAxis::setTransformationSceneToScreen( rMatrix ); + m_apAxisWithLabels->setTransformationSceneToScreen( rMatrix ); +} + +void VPolarRadiusAxis::setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) +{ + VPolarAxis::setExplicitScaleAndIncrement( rScale, rIncrement ); + m_apAxisWithLabels->setExplicitScaleAndIncrement( rScale, rIncrement ); +} + +void VPolarRadiusAxis::initPlotter( const rtl::Reference& xLogicTarget + , const rtl::Reference& xFinalTarget + , const OUString& rCID ) +{ + VPolarAxis::initPlotter( xLogicTarget, xFinalTarget, rCID ); + m_apAxisWithLabels->initPlotter( xLogicTarget, xFinalTarget, rCID ); +} + +void VPolarRadiusAxis::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) +{ + VPolarAxis::setScales( std::vector(rScales), bSwapXAndYAxis ); + m_apAxisWithLabels->setScales( std::move(rScales), bSwapXAndYAxis ); +} + +void VPolarRadiusAxis::initAxisLabelProperties( const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels ) +{ + VPolarAxis::initAxisLabelProperties( rFontReferenceSize, rMaximumSpaceForLabels ); + m_apAxisWithLabels->initAxisLabelProperties( rFontReferenceSize, rMaximumSpaceForLabels ); +} + +sal_Int32 VPolarRadiusAxis::estimateMaximumAutoMainIncrementCount() +{ + return 2; +} + +bool VPolarRadiusAxis::prepareShapeCreation() +{ + //returns true if all is ready for further shape creation and any shapes need to be created + if( !isAnythingToDraw() ) + return false; + + if( m_xGroupShape_Shapes.is() ) + return true; + + return true; +} + +void VPolarRadiusAxis::createMaximumLabels() +{ + m_apAxisWithLabels->createMaximumLabels(); +} + +void VPolarRadiusAxis::updatePositions() +{ + m_apAxisWithLabels->updatePositions(); +} + +void VPolarRadiusAxis::createLabels() +{ + m_apAxisWithLabels->createLabels(); +} + +void VPolarRadiusAxis::createShapes() +{ + if( !prepareShapeCreation() ) + return; + + const ExplicitScaleData& rAngleScale = m_pPosHelper->getScales()[0]; + const ExplicitIncrementData& rAngleIncrement = m_aIncrements[0]; + + TickInfoArraysType aAngleTickInfos; + TickFactory aAngleTickFactory( rAngleScale, rAngleIncrement ); + aAngleTickFactory.getAllTicks( aAngleTickInfos ); + + uno::Reference< XScaling > xInverseScaling; + if( rAngleScale.Scaling.is() ) + xInverseScaling = rAngleScale.Scaling->getInverseScaling(); + + AxisProperties aAxisProperties(m_aAxisProperties); + + sal_Int32 nTick = 0; + EquidistantTickIter aIter( aAngleTickInfos, rAngleIncrement, 0 ); + for( TickInfo* pTickInfo = aIter.firstInfo() + ; pTickInfo; pTickInfo = aIter.nextInfo(), nTick++ ) + { + if( nTick == 0 ) + { + m_apAxisWithLabels->createShapes(); + continue; + } + + //xxxxx pTickInfo->updateUnscaledValue( xInverseScaling ); + aAxisProperties.m_pfMainLinePositionAtOtherAxis = pTickInfo->getUnscaledTickValue(); + aAxisProperties.m_bDisplayLabels=false; + + VCartesianAxis aAxis(aAxisProperties,m_xNumberFormatsSupplier + ,1,2,new PolarPlottingPositionHelper()); + aAxis.setExplicitScaleAndIncrement( m_aScale, m_aIncrement ); + aAxis.initPlotter(m_xLogicTarget,m_xFinalTarget, m_aCID ); + aAxis.setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( m_aMatrixScreenToScene ) ); + aAxis.setScales( std::vector(m_pPosHelper->getScales()), false ); + aAxis.initAxisLabelProperties(m_aAxisLabelProperties.m_aFontReferenceSize,m_aAxisLabelProperties.m_aMaximumSpaceForLabels); + aAxis.createShapes(); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/axes/VPolarRadiusAxis.hxx b/chart2/source/view/axes/VPolarRadiusAxis.hxx new file mode 100644 index 000000000..b2450e236 --- /dev/null +++ b/chart2/source/view/axes/VPolarRadiusAxis.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "VPolarAxis.hxx" +#include + +namespace chart +{ + +class VCartesianAxis; + +class VPolarRadiusAxis : public VPolarAxis +{ +public: + VPolarRadiusAxis( const AxisProperties& rAxisProperties + , const css::uno::Reference< css::util::XNumberFormatsSupplier >& xNumberFormatsSupplier + , sal_Int32 nDimensionCount ); + virtual ~VPolarRadiusAxis() override; + + virtual void initPlotter( + const rtl::Reference& xLogicTarget + , const rtl::Reference& xFinalTarget + , const OUString& rCID + ) override; + + virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix ) override; + + virtual void setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) override; + + virtual void setExplicitScaleAndIncrement( + const ExplicitScaleData& rScale + , const ExplicitIncrementData& rIncrement ) override; + + virtual void initAxisLabelProperties( + const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels ) override; + + virtual sal_Int32 estimateMaximumAutoMainIncrementCount() override; + + virtual void createMaximumLabels() override; + virtual void createLabels() override; + virtual void updatePositions() override; + + virtual void createShapes() override; + +protected: //methods + virtual bool prepareShapeCreation() override; + +private: //member + std::unique_ptr m_apAxisWithLabels; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx new file mode 100644 index 000000000..9cb2e06ba --- /dev/null +++ b/chart2/source/view/charttypes/AreaChart.cxx @@ -0,0 +1,952 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AreaChart.hxx" +#include +#include +#include +#include +#include +#include "Splines.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +AreaChart::AreaChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bCategoryXAxis + , bool bNoArea + ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount, bCategoryXAxis ) + , m_pMainPosHelper(new PlottingPositionHelper()) + , m_bArea(!bNoArea) + , m_bLine(bNoArea) + , m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) ) + , m_eCurveStyle(CurveStyle_LINES) + , m_nCurveResolution(20) + , m_nSplineOrder(3) +{ + m_pMainPosHelper->AllowShiftXAxisPos(true); + m_pMainPosHelper->AllowShiftZAxisPos(true); + + PlotterBase::m_pPosHelper = m_pMainPosHelper.get(); + VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get(); + + try + { + if( m_xChartTypeModel.is() ) + { + m_xChartTypeModel->getPropertyValue(CHART_UNONAME_CURVE_STYLE) >>= m_eCurveStyle; + m_xChartTypeModel->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) >>= m_nCurveResolution; + m_xChartTypeModel->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) >>= m_nSplineOrder; + } + } + catch( uno::Exception& e ) + { + //the above properties are not supported by all charttypes supported by this class (e.g. area or net chart) + //in that cases this exception is ok + e.Context.is();//to have debug information without compilation warnings + } +} + +AreaChart::~AreaChart() +{ +} + +bool AreaChart::isSeparateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ ) +{ + // no separate stacking in all types of line/area charts + return false; +} + +LegendSymbolStyle AreaChart::getLegendSymbolStyle() +{ + if( m_bArea || m_nDimension == 3 ) + return LegendSymbolStyle::Box; + return LegendSymbolStyle::Line; +} + +uno::Any AreaChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex ) +{ + uno::Any aRet; + + Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex ); + if( pSymbolProperties ) + { + aRet <<= *pSymbolProperties; + } + + return aRet; +} + +drawing::Direction3D AreaChart::getPreferredDiagramAspectRatio() const +{ + drawing::Direction3D aRet(1,-1,1); + if( m_nDimension == 2 ) + aRet = drawing::Direction3D(-1,-1,-1); + else if (m_pPosHelper) + { + drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() ); + aRet.DirectionZ = aScale.DirectionZ*0.2; + if(aRet.DirectionZ>1.0) + aRet.DirectionZ=1.0; + if(aRet.DirectionZ>10) + aRet.DirectionZ=10; + } + return aRet; +} + +void AreaChart::addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) +{ + if( m_bArea && pSeries ) + { + sal_Int32 nMissingValueTreatment = pSeries->getMissingValueTreatment(); + if( nMissingValueTreatment == css::chart::MissingValueTreatment::LEAVE_GAP ) + pSeries->setMissingValueTreatment( css::chart::MissingValueTreatment::USE_ZERO ); + } + if( m_nDimension == 3 && !m_bCategoryXAxis ) + { + //3D xy always deep + OSL_ENSURE( zSlot==-1,"3D xy charts should be deep stacked in model also" ); + zSlot=-1; + xSlot=0; + ySlot=0; + } + VSeriesPlotter::addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); +} + +static void lcl_removeDuplicatePoints( std::vector>& rPolyPoly, PlottingPositionHelper& rPosHelper ) +{ + sal_Int32 nPolyCount = rPolyPoly.size(); + if(!nPolyCount) + return; + + // TODO we could do with without a temporary array + std::vector> aTmp; + aTmp.resize(nPolyCount); + + for( sal_Int32 nPolygonIndex = 0; nPolygonIndex* pOuterSource = &rPolyPoly[nPolygonIndex]; + std::vector* pOuterTarget = &aTmp[nPolygonIndex]; + + sal_Int32 nPointCount = pOuterSource->size(); + if( !nPointCount ) + continue; + + pOuterTarget->resize(nPointCount); + + css::drawing::Position3D* pSource = pOuterSource->data(); + css::drawing::Position3D* pTarget = pOuterTarget->data(); + + //copy first point + *pTarget=*pSource++; + sal_Int32 nTargetPointCount=1; + + for( sal_Int32 nSource=1; nSourcePositionX, pTarget->PositionY, pTarget->PositionZ + , pSource->PositionX, pSource->PositionY, pSource->PositionZ ) ) + { + pTarget++; + *pTarget=*pSource; + nTargetPointCount++; + } + pSource++; + } + + //free unused space + if( nTargetPointCountresize(nTargetPointCount); + } + + pOuterSource->clear(); + } + + //free space + rPolyPoly.resize(nPolyCount); + + rPolyPoly = std::move(aTmp); +} + +bool AreaChart::create_stepped_line( + std::vector> aStartPoly, + chart2::CurveStyle eCurveStyle, + PlottingPositionHelper const * pPosHelper, + std::vector> &aPoly ) +{ + sal_uInt32 nOuterCount = aStartPoly.size(); + if ( !nOuterCount ) + return false; + + std::vector> aSteppedPoly; + aSteppedPoly.resize(nOuterCount); + + auto pSequence = aSteppedPoly.data(); + + for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( aStartPoly[nOuter].size() <= 1 ) + continue; //we need at least two points + + sal_uInt32 nMaxIndexPoints = aStartPoly[nOuter].size()-1; // is >1 + sal_uInt32 nNewIndexPoints = 0; + if ( eCurveStyle==CurveStyle_STEP_START || eCurveStyle==CurveStyle_STEP_END) + nNewIndexPoints = nMaxIndexPoints * 2 + 1; + else + nNewIndexPoints = nMaxIndexPoints * 3 + 1; + + const css::drawing::Position3D* pOld = aStartPoly[nOuter].data(); + + pSequence[nOuter].resize( nNewIndexPoints ); + + css::drawing::Position3D* pNew = pSequence[nOuter].data(); + + pNew[0] = pOld[0]; + for( sal_uInt32 oi = 0; oi < nMaxIndexPoints; oi++ ) + { + switch ( eCurveStyle ) + { + case CurveStyle_STEP_START: + /** O + | + | + | + O-----+ + */ + // create the intermediate point + pNew[1+oi*2].PositionX = pOld[oi+1].PositionX; + pNew[1+oi*2].PositionY = pOld[oi].PositionY; + pNew[1+oi*2].PositionZ = pOld[oi].PositionZ; + // and now the normal one + pNew[1+oi*2+1] = pOld[oi+1]; + break; + case CurveStyle_STEP_END: + /** +------O + | + | + | + O + */ + // create the intermediate point + pNew[1+oi*2].PositionX = pOld[oi].PositionX; + pNew[1+oi*2].PositionY = pOld[oi+1].PositionY; + pNew[1+oi*2].PositionZ = pOld[oi].PositionZ; + // and now the normal one + pNew[1+oi*2+1] = pOld[oi+1]; + break; + case CurveStyle_STEP_CENTER_X: + /** +--O + | + | + | + O--+ + */ + // create the first intermediate point + pNew[1+oi*3].PositionX = (pOld[oi].PositionX + pOld[oi+1].PositionX) / 2; + pNew[1+oi*3].PositionY = pOld[oi].PositionY; + pNew[1+oi*3].PositionZ = pOld[oi].PositionZ; + // create the second intermediate point + pNew[1+oi*3+1].PositionX = (pOld[oi].PositionX + pOld[oi+1].PositionX) / 2; + pNew[1+oi*3+1].PositionY = pOld[oi+1].PositionY; + pNew[1+oi*3+1].PositionZ = pOld[oi].PositionZ; + // and now the normal one + pNew[1+oi*3+2] = pOld[oi+1]; + break; + case CurveStyle_STEP_CENTER_Y: + /** O + | + +-----+ + | + O + */ + // create the first intermediate point + pNew[1+oi*3].PositionX = pOld[oi].PositionX; + pNew[1+oi*3].PositionY = (pOld[oi].PositionY + pOld[oi+1].PositionY) / 2; + pNew[1+oi*3].PositionZ = pOld[oi].PositionZ; + // create the second intermediate point + pNew[1+oi*3+1].PositionX = pOld[oi+1].PositionX; + pNew[1+oi*3+1].PositionY = (pOld[oi].PositionY + pOld[oi+1].PositionY) / 2; + pNew[1+oi*3+1].PositionZ = pOld[oi].PositionZ; + // and now the normal one + pNew[1+oi*3+2] = pOld[oi+1]; + break; + default: + // this should never be executed + OSL_FAIL("Unknown curvestyle in AreaChart::create_stepped_line"); + } + } + } + Clipping::clipPolygonAtRectangle( aSteppedPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + + return true; +} + +bool AreaChart::impl_createLine( VDataSeries* pSeries + , std::vector> const * pSeriesPoly + , PlottingPositionHelper* pPosHelper ) +{ + //return true if a line was created successfully + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); + + std::vector> aPoly; + if(m_eCurveStyle==CurveStyle_CUBIC_SPLINES) + { + std::vector> aSplinePoly; + SplineCalculater::CalculateCubicSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution ); + lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper ); + Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + } + else if(m_eCurveStyle==CurveStyle_B_SPLINES) + { + std::vector> aSplinePoly; + SplineCalculater::CalculateBSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution, m_nSplineOrder ); + lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper ); + Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + } + else if (m_eCurveStyle==CurveStyle_STEP_START || + m_eCurveStyle==CurveStyle_STEP_END || + m_eCurveStyle==CurveStyle_STEP_CENTER_Y || + m_eCurveStyle==CurveStyle_STEP_CENTER_X + ) + { + if (!create_stepped_line(*pSeriesPoly, m_eCurveStyle, pPosHelper, aPoly)) + { + return false; + } + } + else + { // default to creating a straight line + SAL_WARN_IF(m_eCurveStyle != CurveStyle_LINES, "chart2.areachart", "Unknown curve style"); + Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + } + + if(!ShapeFactory::hasPolygonAnyLines(aPoly)) + return false; + + //transformation 3) -> 4) + pPosHelper->transformScaledLogicToScene( aPoly ); + + //create line: + rtl::Reference< SvxShape > xShape; + if(m_nDimension==3) + { + double fDepth = getTransformedDepth(); + sal_Int32 nPolyCount = aPoly.size(); + for(sal_Int32 nPoly=0;nPolygetPropertiesOfSeries(), PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), true, 1 ); + } + } + } + else //m_nDimension!=3 + { + xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes, aPoly ); + PropertyMapper::setMappedProperties( *xShape + , pSeries->getPropertiesOfSeries() + , PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + //because of this name this line will be used for marking + ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles"); + } + return true; +} + +bool AreaChart::impl_createArea( VDataSeries* pSeries + , std::vector> const * pSeriesPoly + , std::vector> const * pPreviousSeriesPoly + , PlottingPositionHelper const * pPosHelper ) +{ + //return true if an area was created successfully + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); + double zValue = pSeries->m_fLogicZPos; + + std::vector> aPoly( *pSeriesPoly ); + //add second part to the polygon (grounding points or previous series points) + if(!pPreviousSeriesPoly) + { + double fMinX = pSeries->m_fLogicMinX; + double fMaxX = pSeries->m_fLogicMaxX; + double fY = pPosHelper->getBaseValueY();//logic grounding + if( m_nDimension==3 ) + fY = pPosHelper->getLogicMinY(); + + //clip to scale + if(fMaxXgetLogicMinX() || fMinX>pPosHelper->getLogicMaxX()) + return false;//no visible shape needed + pPosHelper->clipLogicValues( &fMinX, &fY, nullptr ); + pPosHelper->clipLogicValues( &fMaxX, nullptr, nullptr ); + + //apply scaling + { + pPosHelper->doLogicScaling( &fMinX, &fY, &zValue ); + pPosHelper->doLogicScaling( &fMaxX, nullptr, nullptr ); + } + + AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) ); + AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) ); + } + else + { + appendPoly( aPoly, *pPreviousSeriesPoly ); + } + ShapeFactory::closePolygon(aPoly); + + //apply clipping + { + std::vector> aClippedPoly; + Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false ); + ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping + aPoly = aClippedPoly; + } + + if(!ShapeFactory::hasPolygonAnyLines(aPoly)) + return false; + + //transformation 3) -> 4) + pPosHelper->transformScaledLogicToScene( aPoly ); + + //create area: + rtl::Reference< SvxShape > xShape; + if(m_nDimension==3) + { + xShape = ShapeFactory::createArea3D( xSeriesGroupShape_Shapes + , aPoly, getTransformedDepth() ); + } + else //m_nDimension!=3 + { + xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes + , aPoly ); + } + PropertyMapper::setMappedProperties( *xShape + , pSeries->getPropertiesOfSeries() + , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + //because of this name this line will be used for marking + ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles"); + return true; +} + +void AreaChart::impl_createSeriesShapes() +{ + //the polygon shapes for each series need to be created before + + //iterate through all series again to create the series shapes + for( auto const& rZSlot : m_aZSlots ) + { + for( auto const& rXSlot : rZSlot ) + { + std::map< sal_Int32, std::vector>* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex + std::vector>* pSeriesPoly = nullptr; + + //iterate through all series + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + PlottingPositionHelper& rPosHelper = getPlottingPositionHelper(nAttachedAxisIndex); + m_pPosHelper = &rPosHelper; + + createRegressionCurvesShapes( *pSeries, m_xErrorBarTarget, m_xRegressionCurveEquationTarget, + m_pPosHelper->maySkipPointsInRegressionCalculation()); + + pSeriesPoly = &pSeries->m_aPolyPolygonShape3D; + if( m_bArea ) + { + if (!impl_createArea(pSeries.get(), pSeriesPoly, + aPreviousSeriesPolyMap[nAttachedAxisIndex], &rPosHelper)) + continue; + } + if( m_bLine ) + { + if (!impl_createLine(pSeries.get(), pSeriesPoly, &rPosHelper)) + continue; + } + aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly; + }//next series in x slot (next y slot) + }//next x slot + }//next z slot +} + +namespace +{ + +void lcl_reorderSeries( std::vector< std::vector< VDataSeriesGroup > >& rZSlots ) +{ + std::vector< std::vector< VDataSeriesGroup > > aRet; + aRet.reserve( rZSlots.size() ); + + std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() ); + std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() ); + for( ; aZIt != aZEnd; ++aZIt ) + { + std::vector< VDataSeriesGroup > aXSlot; + aXSlot.reserve( aZIt->size() ); + + std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() ); + std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() ); + for( ; aXIt != aXEnd; ++aXIt ) + aXSlot.push_back(std::move(*aXIt)); + + aRet.push_back(std::move(aXSlot)); + } + + rZSlots = std::move(aRet); +} + +//better performance for big data +struct FormerPoint +{ + FormerPoint( double fX, double fY, double fZ ) + : m_fX(fX), m_fY(fY), m_fZ(fZ) + {} + FormerPoint() + : m_fX(std::numeric_limits::quiet_NaN()) + , m_fY(std::numeric_limits::quiet_NaN()) + , m_fZ(std::numeric_limits::quiet_NaN()) + { + } + + double m_fX; + double m_fY; + double m_fZ; +}; + +}//anonymous namespace + +void AreaChart::createShapes() +{ + if( m_aZSlots.empty() ) //no series + return; + + //tdf#127813 Don't reverse the series in OOXML-heavy environments + if( officecfg::Office::Compatibility::View::ReverseSeriesOrderAreaAndNetChart::get() && m_nDimension == 2 && ( m_bArea || !m_bCategoryXAxis ) ) + lcl_reorderSeries( m_aZSlots ); + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"AreaChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //the text labels should be always on top of the other series shapes + //for area chart the error bars should be always on top of the other series shapes + + //therefore create an own group for the texts and the error bars to move them to front + //(because the text group is created after the series group the texts are displayed on top) + m_xSeriesTarget = createGroupShape( m_xLogicTarget ); + if( m_bArea ) + m_xErrorBarTarget = createGroupShape( m_xLogicTarget ); + else + m_xErrorBarTarget = m_xSeriesTarget; + m_xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + m_xRegressionCurveEquationTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + //update/create information for current group + double fLogicZ = 1.0;//as defined + + sal_Int32 nStartIndex = 0; // inclusive ;..todo get somehow from x scale + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + if(nEndIndex<=0) + nEndIndex=1; + + //better performance for big data + std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap; + m_bPointsWereSkipped = false; + sal_Int32 nSkippedPoints = 0; + sal_Int32 nCreatedPoints = 0; + + bool bDateCategory = (m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis()); + + std::vector > aLogicYSumMapByX(nEndIndex);//one for each different nAttachedAxisIndex + for( auto const& rZSlot : m_aZSlots ) + { + //iterate through all x slots in this category to get 100percent sum + for( auto const& rXSlot : rZSlot ) + { + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + if (bDateCategory) + pSeries->doSortByXValues(); + + for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ ) + { + std::map< sal_Int32, double >& rLogicYSumMap = aLogicYSumMapByX[nIndex]; + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + rLogicYSumMap.insert({nAttachedAxisIndex, 0.0}); + + m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex); + + double fAdd = pSeries->getYValue( nIndex ); + if( !std::isnan(fAdd) && !std::isinf(fAdd) ) + rLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd ); + } + } + } + } + + const bool bUseErrorRectangle = ConfigAccess::getUseErrorRectangle(); + + sal_Int32 nZ=1; + for( auto const& rZSlot : m_aZSlots ) + { + //for the area chart there should be at most one x slot (no side by side stacking available) + //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not??? + for( auto const& rXSlot : rZSlot ) + { + std::vector > aLogicYForNextSeriesMapByX(nEndIndex); //one for each different nAttachedAxisIndex + //iterate through all series + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(pSeries.get(), m_xSeriesTarget); + + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + double fXMin, fXMax; + pSeries->getMinMaxXValue(fXMin, fXMax); + PlottingPositionHelper& rPosHelper = getPlottingPositionHelper(nAttachedAxisIndex); + m_pPosHelper = &rPosHelper; + + if(m_nDimension==3) + fLogicZ = nZ+0.5; + pSeries->m_fLogicZPos = fLogicZ; + + for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ ) + { + + /* #i70133# ignore points outside of series length in standard area + charts. Stacked area charts will use missing points as zeros. In + standard charts, pSeriesList contains only one series. */ + if( m_bArea && (rXSlot.m_aSeriesVector.size() == 1) && (nIndex >= pSeries->getTotalPointCount()) ) + continue; + + //collect data point information (logic coordinates, style ): + double fLogicX = pSeries->getXValue(nIndex); + if (bDateCategory) + { + if (std::isnan(fLogicX) || (fLogicX < fXMin || fLogicX > fXMax)) + continue; + + fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution ); + } + double fLogicY = pSeries->getYValue(nIndex); + + if( m_nDimension==3 && m_bArea && rXSlot.m_aSeriesVector.size()!=1 ) + fLogicY = fabs( fLogicY ); + + double fLogicValueForLabeDisplay = fLogicY; + std::map< sal_Int32, double >& rLogicYSumMap = aLogicYSumMapByX[nIndex]; + if (rPosHelper.isPercentY() && rLogicYSumMap[nAttachedAxisIndex] != 0.0) + { + fLogicY = fabs( fLogicY )/rLogicYSumMap[nAttachedAxisIndex]; + } + + if( std::isnan(fLogicX) || std::isinf(fLogicX) + || std::isnan(fLogicY) || std::isinf(fLogicY) + || std::isnan(fLogicZ) || std::isinf(fLogicZ) ) + { + if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP ) + { + std::vector>& rPolygon = pSeries->m_aPolyPolygonShape3D; + sal_Int32& rIndex = pSeries->m_nPolygonIndex; + if( 0<= rIndex && o3tl::make_unsigned(rIndex) < rPolygon.size() ) + { + if( !rPolygon[ rIndex ].empty() ) + rIndex++; //start a new polygon for the next point if the current poly is not empty + } + } + continue; + } + + std::map< sal_Int32, double >& rLogicYForNextSeriesMap = aLogicYForNextSeriesMapByX[nIndex]; + rLogicYForNextSeriesMap.try_emplace(nAttachedAxisIndex, 0.0); + + double fPreviousYValue = rLogicYForNextSeriesMap[nAttachedAxisIndex]; + fLogicY += rLogicYForNextSeriesMap[nAttachedAxisIndex]; + rLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY; + + bool bIsVisible = rPosHelper.isLogicVisible(fLogicX, fLogicY, fLogicZ); + + //remind minimal and maximal x values for area 'grounding' points + //only for filled area + { + double& rfMinX = pSeries->m_fLogicMinX; + if(!nIndex||fLogicXm_fLogicMaxX; + if(!nIndex||fLogicX>rfMaxX) + rfMaxX=fLogicX; + } + + drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ ); + drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition); + rPosHelper.doLogicScaling(aScaledLogicPosition); + + //transformation 3) -> 4) + drawing::Position3D aScenePosition( + rPosHelper.transformLogicToScene(fLogicX, fLogicY, fLogicZ, false)); + + //better performance for big data + FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); + rPosHelper.setCoordinateSystemResolution(m_aCoordinateSystemResolution); + if (!pSeries->isAttributedDataPoint(nIndex) + && rPosHelper.isSameForGivenResolution( + aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ, + aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, + aScaledLogicPosition.PositionZ)) + { + ++nSkippedPoints; + m_bPointsWereSkipped = true; + continue; + } + aSeriesFormerPointMap[pSeries.get()] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ); + + //store point information for series polygon + //for area and/or line (symbols only do not need this) + if( isValidPosition(aScaledLogicPosition) ) + { + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aScaledLogicPosition, pSeries->m_nPolygonIndex ); + } + + //create a single datapoint if point is visible + //apply clipping: + if( !bIsVisible ) + continue; + + bool bCreateYErrorBar = false, bCreateXErrorBar = false; + { + uno::Reference< beans::XPropertySet > xErrorBarProp(pSeries->getYErrorBarProperties(nIndex)); + if( xErrorBarProp.is() ) + { + bool bShowPositive = false; + bool bShowNegative = false; + xErrorBarProp->getPropertyValue("ShowPositiveError") >>= bShowPositive; + xErrorBarProp->getPropertyValue("ShowNegativeError") >>= bShowNegative; + bCreateYErrorBar = bShowPositive || bShowNegative; + } + + xErrorBarProp = pSeries->getXErrorBarProperties(nIndex); + if ( xErrorBarProp.is() ) + { + bool bShowPositive = false; + bool bShowNegative = false; + xErrorBarProp->getPropertyValue("ShowPositiveError") >>= bShowPositive; + xErrorBarProp->getPropertyValue("ShowNegativeError") >>= bShowNegative; + bCreateXErrorBar = bShowPositive || bShowNegative; + } + } + + Symbol* pSymbolProperties = m_bSymbol ? pSeries->getSymbolProperties( nIndex ) : nullptr; + bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE); + + if( !bCreateSymbol && !bCreateYErrorBar && + !bCreateXErrorBar && !pSeries->getDataPointLabelIfLabel(nIndex) ) + continue; + + { + nCreatedPoints++; + + //create data point + drawing::Direction3D aSymbolSize(0,0,0); + if( bCreateSymbol ) + { + if(m_nDimension!=3) + { + //create a group shape for this point and add to the series shape: + OUString aPointCID = ObjectIdentifier::createPointCID( + pSeries->getPointCID_Stub(), nIndex ); + rtl::Reference xPointGroupShape_Shapes; + if (pSymbolProperties->Style == SymbolStyle_STANDARD || pSymbolProperties->Style == SymbolStyle_GRAPHIC) + xPointGroupShape_Shapes = createGroupShape(xSeriesGroupShape_Shapes,aPointCID); + + if (pSymbolProperties->Style != SymbolStyle_NONE) + { + aSymbolSize.DirectionX = pSymbolProperties->Size.Width; + aSymbolSize.DirectionY = pSymbolProperties->Size.Height; + } + + if (pSymbolProperties->Style == SymbolStyle_STANDARD) + { + sal_Int32 nSymbol = pSymbolProperties->StandardSymbol; + ShapeFactory::createSymbol2D( + xPointGroupShape_Shapes, aScenePosition, aSymbolSize, + nSymbol, pSymbolProperties->BorderColor, + pSymbolProperties->FillColor); + } + else if (pSymbolProperties->Style == SymbolStyle_GRAPHIC) + { + ShapeFactory::createGraphic2D(xPointGroupShape_Shapes, + aScenePosition, aSymbolSize, + pSymbolProperties->Graphic); + } + //@todo other symbol styles + } + } + //create error bars or rectangles, depending on configuration + if ( bUseErrorRectangle ) + { + if ( bCreateXErrorBar || bCreateYErrorBar ) + { + createErrorRectangle( + aUnscaledLogicPosition, + *pSeries, + nIndex, + m_xErrorBarTarget, + bCreateXErrorBar, + bCreateYErrorBar ); + } + } + else + { + if (bCreateXErrorBar) + createErrorBar_X( aUnscaledLogicPosition, *pSeries, nIndex, m_xErrorBarTarget ); + + if (bCreateYErrorBar) + createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nIndex, m_xErrorBarTarget, nullptr ); + } + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nIndex) ) + { + LabelAlignment eAlignment = LABEL_ALIGN_TOP; + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( + nIndex, m_xChartTypeModel, rPosHelper.isSwapXAndY()); + + if (m_bArea && nLabelPlacement == css::chart::DataLabelPlacement::CENTER) + { + if (fPreviousYValue) + fLogicY -= (fLogicY - fPreviousYValue) / 2.0; + else + fLogicY = (fLogicY + rPosHelper.getLogicMinY()) / 2.0; + aScenePosition = rPosHelper.transformLogicToScene(fLogicX, fLogicY, fLogicZ, false); + } + + drawing::Position3D aScenePosition3D( aScenePosition.PositionX + , aScenePosition.PositionY + , aScenePosition.PositionZ+getTransformedDepth() ); + + switch(nLabelPlacement) + { + case css::chart::DataLabelPlacement::TOP: + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + case css::chart::DataLabelPlacement::BOTTOM: + aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_BOTTOM; + break; + case css::chart::DataLabelPlacement::LEFT: + aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_LEFT; + break; + case css::chart::DataLabelPlacement::RIGHT: + aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_RIGHT; + break; + case css::chart::DataLabelPlacement::CENTER: + eAlignment = LABEL_ALIGN_CENTER; + break; + default: + OSL_FAIL("this label alignment is not implemented yet"); + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + } + + awt::Point aScreenPosition2D;//get the screen position for the labels + sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent + { + if(eAlignment==LABEL_ALIGN_CENTER || m_nDimension == 3 ) + nOffset = 0; + aScreenPosition2D = LabelPositionHelper(m_nDimension,m_xLogicTarget) + .transformSceneToScreenPosition( aScenePosition3D ); + } + + createDataLabel( m_xTextTarget, *pSeries, nIndex + , fLogicValueForLabeDisplay + , rLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset ); + } + } + } + + }//next series in x slot (next y slot) + }//next x slot + ++nZ; + }//next z slot + + impl_createSeriesShapes(); + + /* @todo remove series shapes if empty + //remove and delete point-group-shape if empty + if(!xSeriesGroupShape_Shapes->getCount()) + { + pSeries->m_xShape.set(NULL); + m_xLogicTarget->remove(xSeriesGroupShape_Shape); + } + */ + + //remove and delete series-group-shape if empty + + //... todo + + SAL_INFO( + "chart2", + "skipped points: " << nSkippedPoints << " created points: " + << nCreatedPoints); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx new file mode 100644 index 000000000..2f7434f3c --- /dev/null +++ b/chart2/source/view/charttypes/AreaChart.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace chart +{ + +class AreaChart : public VSeriesPlotter +{ + // public methods +public: + AreaChart() = delete; + + AreaChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bCategoryXAxis, bool bNoArea=false + ); + virtual ~AreaChart() override; + + virtual void createShapes() override; + virtual void addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + + // MinimumAndMaximumSupplier + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual LegendSymbolStyle getLegendSymbolStyle() override; + virtual css::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex/*-1 for series symbol*/ ) override; + +private: //methods + void impl_createSeriesShapes(); + bool impl_createArea( VDataSeries* pSeries + , std::vector> const * pSeriesPoly + , std::vector> const * pPreviousSeriesPoly + , PlottingPositionHelper const * pPosHelper ); + bool impl_createLine( VDataSeries* pSeries + , std::vector> const * pSeriesPoly + , PlottingPositionHelper* pPosHelper ); + static bool create_stepped_line( std::vector> aStartPoly + , css::chart2::CurveStyle eCurveStyle + , PlottingPositionHelper const * pPosHelper + , std::vector> &aPoly ); + +private: //member + std::unique_ptr + m_pMainPosHelper; + + bool m_bArea;//false -> line or symbol only + bool m_bLine; + bool m_bSymbol; + + //Properties for splines: + css::chart2::CurveStyle m_eCurveStyle; + sal_Int32 m_nCurveResolution; + sal_Int32 m_nSplineOrder; + + rtl::Reference m_xSeriesTarget; + rtl::Reference m_xErrorBarTarget; + rtl::Reference m_xTextTarget; + rtl::Reference m_xRegressionCurveEquationTarget; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx new file mode 100644 index 000000000..b15706d76 --- /dev/null +++ b/chart2/source/view/charttypes/BarChart.cxx @@ -0,0 +1,976 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BarChart.hxx" +#include "BarPositionHelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::rtl::math; +using namespace ::com::sun::star::chart2; + +BarChart::BarChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount ) + , m_pMainPosHelper( new BarPositionHelper() ) +{ + PlotterBase::m_pPosHelper = m_pMainPosHelper.get(); + VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get(); + + try + { + if( m_xChartTypeModel.is() ) + { + m_xChartTypeModel->getPropertyValue( "OverlapSequence" ) >>= m_aOverlapSequence; + m_xChartTypeModel->getPropertyValue( "GapwidthSequence" ) >>= m_aGapwidthSequence; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +BarChart::~BarChart() +{ +} + +PlottingPositionHelper& BarChart::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const +{ + PlottingPositionHelper& rPosHelper = VSeriesPlotter::getPlottingPositionHelper( nAxisIndex ); + BarPositionHelper* pBarPosHelper = dynamic_cast(&rPosHelper); + if( pBarPosHelper && nAxisIndex >= 0 ) + { + if( nAxisIndex < m_aOverlapSequence.getLength() ) + pBarPosHelper->setInnerDistance( -m_aOverlapSequence[nAxisIndex]/100.0 ); + if( nAxisIndex < m_aGapwidthSequence.getLength() ) + pBarPosHelper->setOuterDistance( m_aGapwidthSequence[nAxisIndex]/100.0 ); + } + return rPosHelper; +} + +drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const +{ + drawing::Direction3D aRet(1.0,1.0,1.0); + if( m_nDimension == 3 ) + { + aRet = drawing::Direction3D(1.0,-1.0,1.0); + BarPositionHelper* pPosHelper = dynamic_cast(&( getPlottingPositionHelper( MAIN_AXIS_INDEX) ) ); + if (pPosHelper) + { + drawing::Direction3D aScale( pPosHelper->getScaledLogicWidth() ); + if(aScale.DirectionX!=0.0) + { + double fXSlotCount = 1.0; + if(!m_aZSlots.empty()) + { + fXSlotCount = m_aZSlots.begin()->size(); + } + aRet.DirectionZ = aScale.DirectionZ / + (aScale.DirectionX + aScale.DirectionX * (fXSlotCount-1.0) * pPosHelper->getScaledSlotWidth()); + } + else + { + return VSeriesPlotter::getPreferredDiagramAspectRatio(); + } + } + else + { + return VSeriesPlotter::getPreferredDiagramAspectRatio(); + } + + if(aRet.DirectionZ<0.05) + { + aRet.DirectionZ=0.05; + } + else if(aRet.DirectionZ>10) + { + aRet.DirectionZ=10; + } + if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() ) + { + double fTemp = aRet.DirectionX; + aRet.DirectionX = aRet.DirectionY; + aRet.DirectionY = fTemp; + } + } + else + aRet = drawing::Direction3D(-1,-1,-1); + return aRet; +} + +awt::Point BarChart::getLabelScreenPositionAndAlignment( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement + , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ + , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue + , BarPositionHelper const * pPosHelper + ) const +{ + double fX = fScaledX; + double fY = fScaledUpperYValue; + double fZ = fScaledZ; + bool bReverse = !pPosHelper->isMathematicalOrientationY(); + bool bNormalOutside = (!bReverse == (fBaseValue < fScaledUpperYValue)); + double fDepth = fScaledUpperBarDepth; + + switch(nLabelPlacement) + { + case css::chart::DataLabelPlacement::TOP: + { + if( !pPosHelper->isSwapXAndY() ) + { + fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue; + rAlignment = LABEL_ALIGN_TOP; + if(m_nDimension==3) + fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth); + } + else + { + fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0; + rAlignment = LABEL_ALIGN_CENTER; + OSL_FAIL( "top label placement is not really supported by horizontal bar charts" ); + } + } + break; + case css::chart::DataLabelPlacement::BOTTOM: + { + if(!pPosHelper->isSwapXAndY()) + { + fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue; + rAlignment = LABEL_ALIGN_BOTTOM; + if(m_nDimension==3) + fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth); + } + else + { + fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0; + rAlignment = LABEL_ALIGN_CENTER; + OSL_FAIL( "bottom label placement is not supported by horizontal bar charts" ); + } + } + break; + case css::chart::DataLabelPlacement::LEFT: + { + if( pPosHelper->isSwapXAndY() ) + { + fY = bReverse ? fScaledUpperYValue : fScaledLowerYValue; + rAlignment = LABEL_ALIGN_LEFT; + if(m_nDimension==3) + fDepth = bReverse ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth); + } + else + { + fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0; + rAlignment = LABEL_ALIGN_CENTER; + OSL_FAIL( "left label placement is not supported by column charts" ); + } + } + break; + case css::chart::DataLabelPlacement::RIGHT: + { + if( pPosHelper->isSwapXAndY() ) + { + fY = bReverse ? fScaledLowerYValue : fScaledUpperYValue; + rAlignment = LABEL_ALIGN_RIGHT; + if(m_nDimension==3) + fDepth = bReverse ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth); + } + else + { + fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0; + rAlignment = LABEL_ALIGN_CENTER; + OSL_FAIL( "right label placement is not supported by column charts" ); + } + } + break; + case css::chart::DataLabelPlacement::OUTSIDE: + { + fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue; + if( pPosHelper->isSwapXAndY() ) + // if datapoint value is 0 the label will appear RIGHT in case of Bar Chart + if( fBaseValue == fScaledUpperYValue && fBaseValue == fScaledLowerYValue ) + rAlignment = LABEL_ALIGN_RIGHT; + else + rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + else + // if datapoint value is 0 the label will appear TOP in case of Column Chart + if( fBaseValue == fScaledUpperYValue && fBaseValue == fScaledLowerYValue ) + rAlignment = LABEL_ALIGN_TOP; + else + rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + if(m_nDimension==3) + fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth); + } + break; + case css::chart::DataLabelPlacement::INSIDE: + { + fY = (fBaseValue < fScaledUpperYValue) ? fScaledUpperYValue : fScaledLowerYValue; + if( pPosHelper->isSwapXAndY() ) + rAlignment = bNormalOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + else + rAlignment = bNormalOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + if(m_nDimension==3) + fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledUpperBarDepth) : fabs(fScaledLowerBarDepth); + } + break; + case css::chart::DataLabelPlacement::NEAR_ORIGIN: + { + fY = (fBaseValue < fScaledUpperYValue) ? fScaledLowerYValue : fScaledUpperYValue; + if( pPosHelper->isSwapXAndY() ) + // if datapoint value is 0 the label will appear RIGHT in case of Bar Chart + if( fBaseValue == fScaledUpperYValue && fBaseValue == fScaledLowerYValue ) + rAlignment = LABEL_ALIGN_RIGHT; + else + rAlignment = bNormalOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + else + // if datapoint value is 0 the label will appear TOP in case of Column Chart + if( fBaseValue == fScaledUpperYValue && fBaseValue == fScaledLowerYValue ) + rAlignment = LABEL_ALIGN_TOP; + else + rAlignment = bNormalOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + if(m_nDimension==3) + fDepth = (fBaseValue < fScaledUpperYValue) ? fabs(fScaledLowerBarDepth) : fabs(fScaledUpperBarDepth); + } + break; + case css::chart::DataLabelPlacement::CENTER: + fY -= (fScaledUpperYValue-fScaledLowerYValue)/2.0; + // if datapoint value is 0 the label will appear TOP/RIGHT in case of Column/Bar Charts + if( fBaseValue == fScaledUpperYValue && fBaseValue == fScaledLowerYValue ) + if( pPosHelper->isSwapXAndY() ) + rAlignment = LABEL_ALIGN_RIGHT; + else + rAlignment = LABEL_ALIGN_TOP; + else + rAlignment = LABEL_ALIGN_CENTER; + if(m_nDimension==3) + fDepth = fabs(fScaledUpperBarDepth-fScaledLowerBarDepth)/2.0; + break; + default: + OSL_FAIL("this label alignment is not implemented yet"); + + break; + } + if(m_nDimension==3) + fZ -= fDepth/2.0; + + drawing::Position3D aScenePosition3D( pPosHelper-> + transformScaledLogicToScene( fX, fY, fZ, true ) ); + return LabelPositionHelper(m_nDimension,m_xLogicTarget) + .transformSceneToScreenPosition( aScenePosition3D ); +} + +rtl::Reference< SvxShape > BarChart::createDataPoint3D_Bar( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , const uno::Reference< beans::XPropertySet >& xObjectProperties + , sal_Int32 nGeometry3D ) +{ + bool bRoundedEdges = true; + try + { + if( xObjectProperties.is() ) + { + sal_Int16 nPercentDiagonal = 0; + xObjectProperties->getPropertyValue( "PercentDiagonal" ) >>= nPercentDiagonal; + if( nPercentDiagonal < 5 ) + bRoundedEdges = false; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + rtl::Reference< SvxShape > xShape; + switch( nGeometry3D ) + { + case DataPointGeometry3D::CYLINDER: + xShape = ShapeFactory::createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree ); + break; + case DataPointGeometry3D::CONE: + xShape = ShapeFactory::createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); + break; + case DataPointGeometry3D::PYRAMID: + xShape = ShapeFactory::createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0 + , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + break; + case DataPointGeometry3D::CUBOID: + default: + xShape = ShapeFactory::createCube( xTarget, rPosition, rSize + , nRotateZAngleHundredthDegree, xObjectProperties + , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges ); + return xShape; + } + if( nGeometry3D != DataPointGeometry3D::PYRAMID ) + PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + return xShape; +} + +namespace +{ +bool lcl_hasGeometry3DVariableWidth( sal_Int32 nGeometry3D ) +{ + bool bRet = false; + switch( nGeometry3D ) + { + case DataPointGeometry3D::PYRAMID: + case DataPointGeometry3D::CONE: + bRet = true; + break; + case DataPointGeometry3D::CUBOID: + case DataPointGeometry3D::CYLINDER: + default: + bRet = false; + break; + } + return bRet; +} +}// end anonymous namespace + +void BarChart::addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) +{ + if( !pSeries ) + return; + if(m_nDimension==2) + { + //2ND_AXIS_IN_BARS put series on second scales to different z slot as temporary workaround + //this needs to be redesigned if 3d bars are also able to display secondary axes + + sal_Int32 nAxisIndex = pSeries->getAttachedAxisIndex(); + zSlot = nAxisIndex; + + if( !pSeries->getGroupBarsPerAxis() ) + zSlot = 0; + if(zSlot>=static_cast(m_aZSlots.size())) + m_aZSlots.resize(zSlot+1); + } + VSeriesPlotter::addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); +} + +void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis() +{ + //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature + //thus the different series use the same settings + + VDataSeries* pFirstSeries = getFirstSeries(); + if(!pFirstSeries || pFirstSeries->getGroupBarsPerAxis()) + return; + + sal_Int32 nAxisIndex = pFirstSeries->getAttachedAxisIndex(); + sal_Int32 nN = 0; + sal_Int32 nUseThisIndex = nAxisIndex; + if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() ) + nUseThisIndex = 0; + auto aOverlapSequenceRange = asNonConstRange(m_aOverlapSequence); + for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ ) + { + if(nN!=nUseThisIndex) + aOverlapSequenceRange[nN] = m_aOverlapSequence[nUseThisIndex]; + } + + nUseThisIndex = nAxisIndex; + if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() ) + nUseThisIndex = 0; + auto aGapwidthSequenceRange = asNonConstRange(m_aGapwidthSequence); + for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ ) + { + if(nN!=nUseThisIndex) + aGapwidthSequenceRange[nN] = m_aGapwidthSequence[nUseThisIndex]; + } +} + +void BarChart::createShapes() +{ + if( m_aZSlots.empty() ) //no series + return; + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //the text labels should be always on top of the other series shapes + //therefore create an own group for the texts to move them to front + //(because the text group is created after the series group the texts are displayed on top) + + //the regression curves should always be on top of the bars but beneath the text labels + //to achieve this the regression curve target is created after the series target and before the text target + + rtl::Reference xSeriesTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference xRegressionCurveTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + + rtl::Reference xRegressionCurveEquationTarget = + ShapeFactory::createGroup2D( m_xFinalTarget ); + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + bool bDrawConnectionLines = false; + bool bDrawConnectionLinesInited = false; + + std::unordered_set> aShapeSet; + + const comphelper::ScopeGuard aGuard([aShapeSet]() { + + std::unordered_set aSceneSet; + + for (rtl::Reference const & rShape : aShapeSet) + { + E3dScene* pScene = dynamic_cast(rShape->GetSdrObject()); + if(nullptr != pScene) + { + aSceneSet.insert(pScene->getRootE3dSceneFromE3dObject()); + } + } + for (E3dScene* pScene : aSceneSet) + { + pScene->ResumeReportingDirtyRects(); + pScene->SetAllSceneRectsDirty(); + } + }); + + adaptOverlapAndGapwidthForGroupBarsPerAxis(); + + //better performance for big data + std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap; + m_bPointsWereSkipped = false; + + sal_Int32 nStartIndex = 0; + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + //iterate through all x values per indices + for( sal_Int32 nPointIndex = nStartIndex; nPointIndex < nEndIndex; nPointIndex++ ) + { + //sum up the values for all series in a complete z slot per attached axis + std::map< sal_Int32, double > aLogicYSumMap; + for( auto& rZSlot : m_aZSlots ) + { + for( auto& rXSlot : rZSlot ) + { + sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries(); + aLogicYSumMap.insert({nAttachedAxisIndex, 0.0}); + + const sal_Int32 nSlotPoints = rXSlot.getPointCount(); + if( nPointIndex >= nSlotPoints ) + continue; + + double fMinimumY = 0.0, fMaximumY = 0.0; + rXSlot.calculateYMinAndMaxForCategory( nPointIndex + , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex ); + + if( !std::isnan( fMaximumY ) && fMaximumY > 0) + aLogicYSumMap[nAttachedAxisIndex] += fMaximumY; + if( !std::isnan( fMinimumY ) && fMinimumY < 0) + aLogicYSumMap[nAttachedAxisIndex] += fabs(fMinimumY); + } + } + + sal_Int32 nZ=1; + for( auto& rZSlot : m_aZSlots ) + { + doZSlot(bDrawConnectionLines, bDrawConnectionLinesInited, rZSlot, nZ, nPointIndex, nStartIndex, + xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget, + aShapeSet, aSeriesFormerPointMap, aLogicYSumMap); + ++nZ; + }//next z slot + }//next category + if( bDrawConnectionLines ) + { + for( auto const& rZSlot : m_aZSlots ) + { + BarPositionHelper* pPosHelper = m_pMainPosHelper.get(); + if( !rZSlot.empty() ) + { + sal_Int32 nAttachedAxisIndex = rZSlot.front().getAttachedAxisIndexForFirstSeries(); + //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot + pPosHelper = dynamic_cast(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) ); + if(!pPosHelper) + pPosHelper = m_pMainPosHelper.get(); + } + PlotterBase::m_pPosHelper = pPosHelper; + + //iterate through all x slots in this category + for( auto const& rXSlot : rZSlot ) + { + //iterate through all series in this x slot + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + std::vector>* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D; + if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly)) + continue; + + std::vector> aPoly; + Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + + if(!ShapeFactory::hasPolygonAnyLines(aPoly)) + continue; + + //transformation 3) -> 4) + pPosHelper->transformScaledLogicToScene( aPoly ); + + rtl::Reference xSeriesGroupShape_Shapes( + getSeriesGroupShape(pSeries.get(), xSeriesTarget) ); + rtl::Reference xShape( ShapeFactory::createLine2D( + xSeriesGroupShape_Shapes, aPoly ) ); + PropertyMapper::setMappedProperties( *xShape, pSeries->getPropertiesOfSeries() + , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + } + } + } + } + + /* @todo remove series shapes if empty + */ +} + +void BarChart::doZSlot( + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, + const std::vector< VDataSeriesGroup >& rZSlot, + const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex, + const rtl::Reference& xSeriesTarget, + const rtl::Reference& xRegressionCurveTarget, + const rtl::Reference& xRegressionCurveEquationTarget, + const rtl::Reference& xTextTarget, + std::unordered_set>& aShapeSet, + std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap, + std::map< sal_Int32, double >& aLogicYSumMap) +{ + //iterate through all x slots in this category + double fSlotX=0; + for( auto& rXSlot : rZSlot ) + { + sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries(); + //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot + BarPositionHelper* pPosHelper = dynamic_cast(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) ); + if(!pPosHelper) + pPosHelper = m_pMainPosHelper.get(); + + PlotterBase::m_pPosHelper = pPosHelper; + + //update/create information for current group + pPosHelper->updateSeriesCount( rZSlot.size() ); + double fLogicBaseWidth = pPosHelper->getScaledSlotWidth(); + + // get distance from base value to maximum and minimum + + double fMinimumY = 0.0, fMaximumY = 0.0; + if( nPointIndex < rXSlot.getPointCount()) + rXSlot.calculateYMinAndMaxForCategory( nPointIndex + , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex ); + + double fLogicPositiveYSum = 0.0; + if( !std::isnan( fMaximumY ) ) + fLogicPositiveYSum = fMaximumY; + + double fLogicNegativeYSum = 0.0; + if( !std::isnan( fMinimumY ) ) + fLogicNegativeYSum = fMinimumY; + + if( pPosHelper->isPercentY() ) + { + /* #i70395# fLogicPositiveYSum contains sum of all positive + values, if any, otherwise the highest negative value. + fLogicNegativeYSum contains sum of all negative values, + if any, otherwise the lowest positive value. + Afterwards, fLogicPositiveYSum will contain the maximum + (positive) value that is related to 100%. */ + + // do nothing if there are positive values only + if( fLogicNegativeYSum < 0.0 ) + { + // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum + if( fLogicPositiveYSum < 0.0 ) + fLogicPositiveYSum = -fLogicNegativeYSum; + // otherwise there are positive and negative values, calculate total distance + else + fLogicPositiveYSum -= fLogicNegativeYSum; + } + fLogicNegativeYSum = 0.0; + } + + doXSlot(rXSlot, bDrawConnectionLines, bDrawConnectionLinesInited, nZ, nPointIndex, nStartIndex, + xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget, + aShapeSet, aSeriesFormerPointMap, aLogicYSumMap, + fLogicBaseWidth, fSlotX, pPosHelper, fLogicPositiveYSum, fLogicNegativeYSum, nAttachedAxisIndex); + + fSlotX+=1.0; + }//next x slot +} + + +void BarChart::doXSlot( + const VDataSeriesGroup& rXSlot, + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, + const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex, + const rtl::Reference& xSeriesTarget, + const rtl::Reference& xRegressionCurveTarget, + const rtl::Reference& xRegressionCurveEquationTarget, + const rtl::Reference& xTextTarget, + std::unordered_set>& aShapeSet, + std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap, + std::map< sal_Int32, double >& aLogicYSumMap, + const double fLogicBaseWidth, const double fSlotX, + BarPositionHelper* const pPosHelper, + const double fLogicPositiveYSum, const double fLogicNegativeYSum, + const sal_Int32 nAttachedAxisIndex) +{ + double fBaseValue = 0.0; + if( !pPosHelper->isPercentY() && rXSlot.m_aSeriesVector.size()<=1 ) + fBaseValue = pPosHelper->getBaseValueY(); + double fPositiveLogicYForNextSeries = fBaseValue; + double fNegativeLogicYForNextSeries = fBaseValue; + + //iterate through all series in this x slot + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor"); + + bool bOnlyConnectionLinesForThisPoint = false; + + if(nPointIndex==nStartIndex)//do not create a regression line for each point + createRegressionCurvesShapes( *pSeries, xRegressionCurveTarget, xRegressionCurveEquationTarget, + m_pPosHelper->maySkipPointsInRegressionCalculation()); + + if( !bDrawConnectionLinesInited ) + { + bDrawConnectionLines = pSeries->getConnectBars(); + if( m_nDimension==3 ) + bDrawConnectionLines = false; + if( bDrawConnectionLines && rXSlot.m_aSeriesVector.size()==1 ) + { + //detect whether we have a stacked chart or not: + StackingDirection eDirection = pSeries->getStackingDirection(); + if( eDirection != StackingDirection_Y_STACKING ) + bDrawConnectionLines = false; + } + bDrawConnectionLinesInited = true; + } + + // Use another XShapes for background, so we can avoid needing to set the Z-order on all of them, + // which is expensive in bulk. + rtl::Reference xSeriesGroupShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget)); + rtl::Reference xSeriesBackgroundShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget)); + aShapeSet.insert(xSeriesGroupShape_Shapes); + aShapeSet.insert(xSeriesBackgroundShape_Shapes); + // Suspend setting rects dirty for the duration of this call + E3dScene* pScene = dynamic_cast(xSeriesGroupShape_Shapes->GetSdrObject()); + if (pScene) + pScene->SuspendReportingDirtyRects(); + pScene = dynamic_cast(xSeriesBackgroundShape_Shapes->GetSdrObject()); + if (pScene) + pScene->SuspendReportingDirtyRects(); + + //collect data point information (logic coordinates, style ): + double fUnscaledLogicX = pSeries->getXValue( nPointIndex ); + fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); + if(std::isnan(fUnscaledLogicX)) + continue;//point not visible + if(fUnscaledLogicXgetLogicMinX()) + continue;//point not visible + if(fUnscaledLogicX>pPosHelper->getLogicMaxX()) + continue;//point not visible + if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX()) + continue;//point not visible + double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX ); + + double fLogicBarHeight = pSeries->getYValue( nPointIndex ); + if( std::isnan( fLogicBarHeight )) //no value at this category + continue; + + double fLogicValueForLabeDisplay = fLogicBarHeight; + fLogicBarHeight-=fBaseValue; + + if( pPosHelper->isPercentY() ) + { + if(fLogicPositiveYSum!=0.0) + fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum; + else + fLogicBarHeight = 0.0; + } + + // tdf#114141 to draw the top of the zero height 3D bar + // we set a small positive value, here the smallest one for the type double (DBL_MIN) + if( fLogicBarHeight == 0.0 ) + fLogicBarHeight = DBL_MIN; + + //sort negative and positive values, to display them on different sides of the x axis + bool bPositive = fLogicBarHeight >= 0.0; + double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries; + double fUpperYValue = fLowerYValue+fLogicBarHeight; + if( bPositive ) + fPositiveLogicYForNextSeries += fLogicBarHeight; + else + fNegativeLogicYForNextSeries += fLogicBarHeight; + + double fLogicZ = 1.0;//as defined + if(m_nDimension==3) + fLogicZ = nZ+0.5; + + drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ ); + + //@todo ... start an iteration over the different breaks of the axis + //each subsystem may add an additional shape to form the whole point + //create a group shape for this point and add to the series shape: +// uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) ); +// uno::Reference xPointGroupShape_Shape = +// uno::Reference( xPointGroupShape_Shapes, uno::UNO_QUERY ); + //as long as we do not iterate we do not need to create an additional group for each point + uno::Reference< beans::XPropertySet > xDataPointProperties( pSeries->getPropertiesOfPoint( nPointIndex ) ); + sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID; + if(m_nDimension==3) try + { + xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //@todo iterate through all subsystems to create partial points + { + //@todo select a suitable PositionHelper for this subsystem + BarPositionHelper* pSubPosHelper = pPosHelper; + + double fUnclippedUpperYValue = fUpperYValue; + + //apply clipping to Y + if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) ) + { + if( bDrawConnectionLines ) + bOnlyConnectionLinesForThisPoint = true; + else + continue; + } + //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects + + //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects) + pSubPosHelper->doLogicScaling(nullptr,&fLowerYValue,nullptr); + pSubPosHelper->doLogicScaling(nullptr,&fUpperYValue,nullptr); + //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions + + pSubPosHelper->doLogicScaling(nullptr,&fUnclippedUpperYValue,nullptr); + + //calculate resulting width + double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum; + if( pPosHelper->isPercentY() ) + fCompleteHeight = 1.0; + double fLogicBarWidth = fLogicBaseWidth; + double fTopHeight=approxSub(fCompleteHeight,fUpperYValue); + if(!bPositive) + fTopHeight=approxSub(fCompleteHeight,fLowerYValue); + double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue; + double fMiddleHeight = fUpperYValue-fLowerYValue; + if(!bPositive) + fMiddleHeight*=-1.0; + double fLogicBarDepth = 0.5; + if(m_nDimension==3) + { + if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) + { + double fHeight = fCompleteHeight-fLowerYValue; + if(!bPositive) + fHeight = fCompleteHeight-fUpperYValue; + fLogicBarWidth = fLogicBaseWidth*fHeight/fCompleteHeight; + if(fLogicBarWidth<=0.0) + fLogicBarWidth=fLogicBaseWidth; + fLogicBarDepth = fLogicBarDepth*fHeight/fCompleteHeight; + if(fLogicBarDepth<=0.0) + fLogicBarDepth*=-1.0; + } + } + + //better performance for big data + FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); + pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution ); + if( !pSeries->isAttributedDataPoint(nPointIndex) + && + pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ + , fLogicX, fUpperYValue, fLogicZ ) + && + pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ + , fLogicX, fLowerYValue, fLogicZ ) + ) + { + m_bPointsWereSkipped = true; + continue; + } + aSeriesFormerPointMap[pSeries.get()] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ); + + if( bDrawConnectionLines ) + { + //store point information for connection lines + + drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); + drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); + + if( isValidPosition(aLeftUpperPoint) ) + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aLeftUpperPoint ); + if( isValidPosition(aRightUpperPoint) ) + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aRightUpperPoint ); + } + + if( bOnlyConnectionLinesForThisPoint ) + continue; + + //maybe additional possibility for performance improvement + //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false; + //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ + // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ ); + + //create partial point + if( !approxEqual(fLowerYValue,fUpperYValue) ) + { + rtl::Reference< SvxShape > xShape; + if( m_nDimension==3 ) + { + drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ); + drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0); + drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0); + drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ); + + ::chart::XTransformation2* pTransformation = pSubPosHelper->getTransformationScaledLogicToScene(); + + //transformation 3) -> 4) + drawing::Position3D aTransformedBottom ( pTransformation->transform( aLogicBottom ) ); + drawing::Position3D aTransformedLeftBottomFront ( pTransformation->transform( aLogicLeftBottomFront ) ); + drawing::Position3D aTransformedRightDeepTop ( pTransformation->transform( aLogicRightDeepTop ) ); + drawing::Position3D aTransformedTopTop ( pTransformation->transform( aLogicTopTop ) ); + + drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront; + drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop ); + fTopHeight = aTopSize.DirectionY; + + sal_Int32 nRotateZAngleHundredthDegree = 0; + if( pPosHelper->isSwapXAndY() ) + { + fTopHeight = aTopSize.DirectionX; + nRotateZAngleHundredthDegree = 90*100; + aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ); + } + + if( aSize.DirectionX < 0 ) + aSize.DirectionX *= -1.0; + if( aSize.DirectionZ < 0 ) + aSize.DirectionZ *= -1.0; + if( fTopHeight < 0 ) + fTopHeight *= -1.0; + + xShape = createDataPoint3D_Bar( + xSeriesGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree + , xDataPointProperties, nGeometry3D ); + } + else //m_nDimension!=3 + { + drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ ); + drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ ); + std::vector> aPoly + { + { // inner vector + drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ), + drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ), + aRightUpperPoint, + aLeftUpperPoint, + drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) + } + }; + pPosHelper->transformScaledLogicToScene( aPoly ); + xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes, aPoly ); + PropertyMapper::setMappedProperties( *xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + } + + if(bHasFillColorMapping) + { + double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor"); + if(!std::isnan(nPropVal)) + { + xShape->setPropertyValue("FillColor", uno::Any(static_cast(nPropVal))); + } + } + //set name/classified ObjectID (CID) + ShapeFactory::setShapeName(xShape + , ObjectIdentifier::createPointCID( + pSeries->getPointCID_Stub(),nPointIndex) ); + } + + //create error bar + createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nPointIndex, m_xLogicTarget, &fLogicX ); + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nPointIndex) ) + { + double fLogicSum = aLogicYSumMap[nAttachedAxisIndex]; + + LabelAlignment eAlignment(LABEL_ALIGN_CENTER); + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, pPosHelper->isSwapXAndY() ); + + double fLowerBarDepth = fLogicBarDepth; + double fUpperBarDepth = fLogicBarDepth; + { + if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) + { + double fOuterBarDepth = fLogicBarDepth * fTopHeight/(fabs(fCompleteHeight)); + fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth); + fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth); + } + } + + awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment( + eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ, + fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper); + sal_Int32 nOffset = 0; + if(eAlignment!=LABEL_ALIGN_CENTER) + { + nOffset = 100;//add some spacing //@todo maybe get more intelligent values + if( m_nDimension == 3 ) + nOffset = 260; + } + createDataLabel( + xTextTarget, *pSeries, nPointIndex, + fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset); + } + + }//end iteration through partial points + + }//next series in x slot (next y slot) +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BarChart.hxx b/chart2/source/view/charttypes/BarChart.hxx new file mode 100644 index 000000000..52c3b6177 --- /dev/null +++ b/chart2/source/view/charttypes/BarChart.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace chart +{ +class BarPositionHelper; + +class BarChart : public VSeriesPlotter +{ + // public methods +public: + BarChart() = delete; + + BarChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount ); + virtual ~BarChart() override; + + virtual void createShapes() override; + virtual void addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + +private: //methods + static rtl::Reference< SvxShape > + createDataPoint3D_Bar( + const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , const css::uno::Reference< css::beans::XPropertySet >& xObjectProperties + , sal_Int32 nGeometry3D ); + + css::awt::Point getLabelScreenPositionAndAlignment( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement + , double fScaledX, double fScaledLowerYValue, double fScaledUpperYValue, double fScaledZ + , double fScaledLowerBarDepth, double fScaledUpperBarDepth, double fBaseValue + , BarPositionHelper const * pPosHelper ) const; + + virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const override;//nAxisIndex indicates whether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 ) + + void adaptOverlapAndGapwidthForGroupBarsPerAxis(); + + //better performance for big data + struct FormerBarPoint + { + FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ ) + : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ) + {} + FormerBarPoint() + : m_fX(std::numeric_limits::quiet_NaN()) + , m_fUpperY(std::numeric_limits::quiet_NaN()) + , m_fLowerY(std::numeric_limits::quiet_NaN()) + , m_fZ(std::numeric_limits::quiet_NaN()) + { + } + + double m_fX; + double m_fUpperY; + double m_fLowerY; + double m_fZ; + }; + + void doZSlot( + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, const std::vector< VDataSeriesGroup >& rZSlot, + sal_Int32 nZ, sal_Int32 nPointIndex, sal_Int32 nStartIndex, + const rtl::Reference& xSeriesTarget, + const rtl::Reference& xRegressionCurveTarget, + const rtl::Reference& xRegressionCurveEquationTarget, + const rtl::Reference& xTextTarget, + std::unordered_set>& aShapeSet, + std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap, + std::map< sal_Int32, double >& aLogicYSumMap); + + void doXSlot( + const VDataSeriesGroup& rXSlot, + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, + sal_Int32 nZ, sal_Int32 nPointIndex, sal_Int32 nStartIndex, + const rtl::Reference& xSeriesTarget, + const rtl::Reference& xRegressionCurveTarget, + const rtl::Reference& xRegressionCurveEquationTarget, + const rtl::Reference& xTextTarget, + std::unordered_set>& aShapeSet, + std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap, + std::map< sal_Int32, double >& aLogicYSumMap, + double fLogicBaseWidth, double fSlotX, + BarPositionHelper* const pPosHelper, + double fLogicPositiveYSum, double fLogicNegativeYSum, + sal_Int32 nAttachedAxisIndex); + +private: //member + std::unique_ptr m_pMainPosHelper; + css::uno::Sequence< sal_Int32 > m_aOverlapSequence; + css::uno::Sequence< sal_Int32 > m_aGapwidthSequence; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BarPositionHelper.cxx b/chart2/source/view/charttypes/BarPositionHelper.cxx new file mode 100644 index 000000000..f8ac3e7d6 --- /dev/null +++ b/chart2/source/view/charttypes/BarPositionHelper.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BarPositionHelper.hxx" +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +BarPositionHelper::BarPositionHelper() + : CategoryPositionHelper( 1 ) +{ + AllowShiftXAxisPos(true); + AllowShiftZAxisPos(true); +} + +BarPositionHelper::BarPositionHelper( const BarPositionHelper& rSource ) + : CategoryPositionHelper( rSource ) + , PlottingPositionHelper( rSource ) +{ +} + +BarPositionHelper::~BarPositionHelper() +{ +} + +std::unique_ptr BarPositionHelper::clone() const +{ + return std::make_unique(*this); +} + +void BarPositionHelper::updateSeriesCount( double fSeriesCount ) +{ + m_fSeriesCount = fSeriesCount; +} + +double BarPositionHelper::getScaledSlotPos( double fUnscaledLogicX, double fSeriesNumber ) const +{ + if( m_bDateAxis ) + fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); + double fScaledLogicX(fUnscaledLogicX); + doLogicScaling(&fScaledLogicX,nullptr,nullptr); + fScaledLogicX = CategoryPositionHelper::getScaledSlotPos( fScaledLogicX, fSeriesNumber ); + return fScaledLogicX; + +} + +void BarPositionHelper::setScaledCategoryWidth( double fScaledCategoryWidth ) +{ + m_fScaledCategoryWidth = fScaledCategoryWidth; + CategoryPositionHelper::setCategoryWidth( m_fScaledCategoryWidth ); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BarPositionHelper.hxx b/chart2/source/view/charttypes/BarPositionHelper.hxx new file mode 100644 index 000000000..961ea988f --- /dev/null +++ b/chart2/source/view/charttypes/BarPositionHelper.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "CategoryPositionHelper.hxx" + +namespace chart +{ +class BarPositionHelper : public CategoryPositionHelper, public PlottingPositionHelper +{ +public: + explicit BarPositionHelper(); + BarPositionHelper(const BarPositionHelper& rSource); + virtual ~BarPositionHelper() override; + + virtual std::unique_ptr clone() const override; + + void updateSeriesCount(double fSeriesCount); /*only enter the size of x stacked series*/ + + virtual double getScaledSlotPos(double fCategoryX, double fSeriesNumber) const override; + virtual void setScaledCategoryWidth(double fScaledCategoryWidth) override; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BubbleChart.cxx b/chart2/source/view/charttypes/BubbleChart.cxx new file mode 100644 index 000000000..803cf73b2 --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.cxx @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "BubbleChart.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +BubbleChart::BubbleChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount, false ) + , m_fMaxLogicBubbleSize( 0.0 ) + , m_fBubbleSizeFactorToScreen( 1.0 ) +{ + // We only support 2 dimensional bubble charts + assert(nDimensionCount == 2); + + if( !m_pMainPosHelper ) + m_pMainPosHelper = new PlottingPositionHelper(); + PlotterBase::m_pPosHelper = m_pMainPosHelper; +} + +BubbleChart::~BubbleChart() +{ + delete m_pMainPosHelper; +} + +void BubbleChart::calculateMaximumLogicBubbleSize() +{ + double fMaxSize = 0.0; + + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + for( sal_Int32 nIndex = 0; nIndex < nEndIndex; nIndex++ ) + { + for( auto const& rZSlot : m_aZSlots ) + { + for( auto const& rXSlot : rZSlot ) + { + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + double fSize = pSeries->getBubble_Size( nIndex ); + if( fSize > fMaxSize ) + fMaxSize = fSize; + } + } + } + } + + m_fMaxLogicBubbleSize = fMaxSize; +} + +void BubbleChart::calculateBubbleSizeScalingFactor() +{ + double fLogicZ=1.0; + drawing::Position3D aSceneMinPos( m_pMainPosHelper->transformLogicToScene( m_pMainPosHelper->getLogicMinX(),m_pMainPosHelper->getLogicMinY(),fLogicZ, false ) ); + drawing::Position3D aSceneMaxPos( m_pMainPosHelper->transformLogicToScene( m_pMainPosHelper->getLogicMaxX(),m_pMainPosHelper->getLogicMaxY(),fLogicZ, false ) ); + + awt::Point aScreenMinPos( LabelPositionHelper(m_nDimension,m_xLogicTarget).transformSceneToScreenPosition( aSceneMinPos ) ); + awt::Point aScreenMaxPos( LabelPositionHelper(m_nDimension,m_xLogicTarget).transformSceneToScreenPosition( aSceneMaxPos ) ); + + sal_Int32 nWidth = abs( aScreenMaxPos.X - aScreenMinPos.X ); + sal_Int32 nHeight = abs( aScreenMaxPos.Y - aScreenMinPos.Y ); + + sal_Int32 nMinExtend = std::min( nWidth, nHeight ); + m_fBubbleSizeFactorToScreen = nMinExtend * 0.25;//max bubble size is 25 percent of diagram size +} + +drawing::Direction3D BubbleChart::transformToScreenBubbleSize( double fLogicSize ) +{ + drawing::Direction3D aRet(0,0,0); + + if( std::isnan(fLogicSize) || std::isinf(fLogicSize) ) + return aRet; + + double fMaxSize = m_fMaxLogicBubbleSize; + + double fMaxRadius = sqrt( fMaxSize / M_PI ); + double fRadius = sqrt( fLogicSize / M_PI ); + + aRet.DirectionX = m_fBubbleSizeFactorToScreen * fRadius / fMaxRadius; + aRet.DirectionY = aRet.DirectionX; + + return aRet; +} + +bool BubbleChart::isExpandIfValuesCloseToBorder( sal_Int32 /*nDimensionIndex*/ ) +{ + return true; +} + +bool BubbleChart::isSeparateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ ) +{ + return false; +} + +LegendSymbolStyle BubbleChart::getLegendSymbolStyle() +{ + return LegendSymbolStyle::Circle; +} + +drawing::Direction3D BubbleChart::getPreferredDiagramAspectRatio() const +{ + return drawing::Direction3D(-1,-1,-1); +} + +namespace { + +//better performance for big data +struct FormerPoint +{ + FormerPoint( double fX, double fY, double fZ ) + : m_fX(fX), m_fY(fY), m_fZ(fZ) + {} + FormerPoint() + : m_fX(std::numeric_limits::quiet_NaN()) + , m_fY(std::numeric_limits::quiet_NaN()) + , m_fZ(std::numeric_limits::quiet_NaN()) + { + } + + double m_fX; + double m_fY; + double m_fZ; +}; + +} + +void BubbleChart::createShapes() +{ + if( m_aZSlots.empty() ) //no series + return; + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"BubbleChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //therefore create an own group for the texts and the error bars to move them to front + //(because the text group is created after the series group the texts are displayed on top) + rtl::Reference xSeriesTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference< SvxShapeGroup > xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + + //update/create information for current group + double fLogicZ = 1.0;//as defined + + sal_Int32 const nStartIndex = 0; // inclusive ;..todo get somehow from x scale + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + if(nEndIndex<=0) + nEndIndex=1; + + //better performance for big data + std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap; + m_bPointsWereSkipped = false; + sal_Int32 nSkippedPoints = 0; + sal_Int32 nCreatedPoints = 0; + + calculateMaximumLogicBubbleSize(); + calculateBubbleSizeScalingFactor(); + if( m_fMaxLogicBubbleSize <= 0 || m_fBubbleSizeFactorToScreen <= 0 ) + return; + + //iterate through all x values per indices + for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ ) + { + for( auto const& rZSlot : m_aZSlots ) + { + for( auto const& rXSlot : rZSlot ) + { + //iterate through all series + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor"); + bool bHasBorderColorMapping = pSeries->hasPropertyMapping("LineColor"); + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries.get(), xSeriesTarget); + + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + PlottingPositionHelper& rPosHelper + = getPlottingPositionHelper(nAttachedAxisIndex); + m_pPosHelper = &rPosHelper; + + //collect data point information (logic coordinates, style ): + double fLogicX = pSeries->getXValue(nIndex); + double fLogicY = pSeries->getYValue(nIndex); + double fBubbleSize = pSeries->getBubble_Size( nIndex ); + + if( fBubbleSize<0.0 ) + continue; + + if( fBubbleSize == 0.0 || std::isnan(fBubbleSize) ) + continue; + + if( std::isnan(fLogicX) || std::isinf(fLogicX) + || std::isnan(fLogicY) || std::isinf(fLogicY) ) + continue; + + bool bIsVisible = rPosHelper.isLogicVisible(fLogicX, fLogicY, fLogicZ); + + drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ ); + drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition); + rPosHelper.doLogicScaling(aScaledLogicPosition); + + //transformation 3) -> 4) + drawing::Position3D aScenePosition( + rPosHelper.transformLogicToScene(fLogicX, fLogicY, fLogicZ, false)); + + //better performance for big data + FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); + rPosHelper.setCoordinateSystemResolution(m_aCoordinateSystemResolution); + if (!pSeries->isAttributedDataPoint(nIndex) + && rPosHelper.isSameForGivenResolution( + aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ, + aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, + aScaledLogicPosition.PositionZ)) + { + nSkippedPoints++; + m_bPointsWereSkipped = true; + continue; + } + aSeriesFormerPointMap[pSeries.get()] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ); + + //create a single datapoint if point is visible + if( !bIsVisible ) + continue; + + //create a group shape for this point and add to the series shape: + OUString aPointCID = ObjectIdentifier::createPointCID( + pSeries->getPointCID_Stub(), nIndex ); + rtl::Reference xPointGroupShape_Shapes( + createGroupShape(xSeriesGroupShape_Shapes,aPointCID) ); + + { + nCreatedPoints++; + + //create data point + drawing::Direction3D aSymbolSize = transformToScreenBubbleSize( fBubbleSize ); + rtl::Reference xShape = ShapeFactory::createCircle2D( xPointGroupShape_Shapes + , aScenePosition, aSymbolSize ); + + PropertyMapper::setMappedProperties( *xShape + , pSeries->getPropertiesOfPoint( nIndex ) + , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + + if(bHasFillColorMapping) + { + double nPropVal = pSeries->getValueByProperty(nIndex, "FillColor"); + if(!std::isnan(nPropVal)) + { + xShape->SvxShape::setPropertyValue("FillColor", uno::Any(static_cast(nPropVal))); + } + } + if(bHasBorderColorMapping) + { + double nPropVal = pSeries->getValueByProperty(nIndex, "LineColor"); + if(!std::isnan(nPropVal)) + { + xShape->SvxShape::setPropertyValue("LineColor", uno::Any(static_cast(nPropVal))); + } + } + + ::chart::ShapeFactory::setShapeName( xShape, "MarkHandles" ); + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nIndex) ) + { + LabelAlignment eAlignment = LABEL_ALIGN_TOP; + drawing::Position3D aScenePosition3D( aScenePosition.PositionX + , aScenePosition.PositionY + , aScenePosition.PositionZ+getTransformedDepth() ); + + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( + nIndex, m_xChartTypeModel, rPosHelper.isSwapXAndY()); + + switch(nLabelPlacement) + { + case css::chart::DataLabelPlacement::TOP: + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + case css::chart::DataLabelPlacement::BOTTOM: + aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_BOTTOM; + break; + case css::chart::DataLabelPlacement::LEFT: + aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_LEFT; + break; + case css::chart::DataLabelPlacement::RIGHT: + aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_RIGHT; + break; + case css::chart::DataLabelPlacement::CENTER: + eAlignment = LABEL_ALIGN_CENTER; + break; + default: + OSL_FAIL("this label alignment is not implemented yet"); + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + } + + awt::Point aScreenPosition2D( LabelPositionHelper(m_nDimension,m_xLogicTarget) + .transformSceneToScreenPosition( aScenePosition3D ) ); + sal_Int32 nOffset = 0; + if(eAlignment!=LABEL_ALIGN_CENTER) + nOffset = 100;//add some spacing //@todo maybe get more intelligent values + createDataLabel( xTextTarget, *pSeries, nIndex + , fBubbleSize, fBubbleSize, aScreenPosition2D, eAlignment, nOffset ); + } + } + + //remove PointGroupShape if empty + if(!xPointGroupShape_Shapes->getCount()) + xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shapes); + + }//next series in x slot (next y slot) + }//next x slot + }//next z slot + }//next category + SAL_INFO( + "chart2", + "skipped points: " << nSkippedPoints << " created points: " + << nCreatedPoints); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/BubbleChart.hxx b/chart2/source/view/charttypes/BubbleChart.hxx new file mode 100644 index 000000000..c25e5b634 --- /dev/null +++ b/chart2/source/view/charttypes/BubbleChart.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart +{ + +class BubbleChart : public VSeriesPlotter +{ + // public methods +public: + BubbleChart() = delete; + + BubbleChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount ); + virtual ~BubbleChart() override; + + virtual void createShapes() override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + + // MinimumAndMaximumSupplier + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual LegendSymbolStyle getLegendSymbolStyle() override; + +private: //methods + void calculateMaximumLogicBubbleSize(); + void calculateBubbleSizeScalingFactor(); + + css::drawing::Direction3D transformToScreenBubbleSize( double fLogicSize ); + +private: //member + + double m_fMaxLogicBubbleSize;//calculated values + double m_fBubbleSizeFactorToScreen;//calculated values +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx new file mode 100644 index 000000000..5c8497a5d --- /dev/null +++ b/chart2/source/view/charttypes/CandleStickChart.cxx @@ -0,0 +1,314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "CandleStickChart.hxx" +#include +#include +#include +#include +#include +#include "BarPositionHelper.hxx" +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +CandleStickChart::CandleStickChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount ) + , m_pMainPosHelper( new BarPositionHelper() ) +{ + PlotterBase::m_pPosHelper = m_pMainPosHelper.get(); + VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get(); +} + +CandleStickChart::~CandleStickChart() +{ +} + +// MinimumAndMaximumSupplier + +bool CandleStickChart::isSeparateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +LegendSymbolStyle CandleStickChart::getLegendSymbolStyle() +{ + return LegendSymbolStyle::Line; +} + +drawing::Direction3D CandleStickChart::getPreferredDiagramAspectRatio() const +{ + return drawing::Direction3D(-1,-1,-1); +} + +void CandleStickChart::addSeries( std::unique_ptr pSeries, sal_Int32 /* zSlot */, sal_Int32 xSlot, sal_Int32 ySlot ) +{ + //ignore y stacking for candle stick chart + VSeriesPlotter::addSeries( std::move(pSeries), 0, xSlot, ySlot ); +} + +void CandleStickChart::createShapes() +{ + if( m_aZSlots.empty() ) //no series + return; + + if( m_nDimension!=2 ) + return; + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"CandleStickChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //the text labels should be always on top of the other series shapes + //therefore create an own group for the texts to move them to front + //(because the text group is created after the series group the texts are displayed on top) + + rtl::Reference xSeriesTarget = + createGroupShape( m_xLogicTarget ); + rtl::Reference xLossTarget = + createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_STOCK_LOSS, u"" )); + rtl::Reference xGainTarget = + createGroupShape( m_xLogicTarget, ObjectIdentifier::createClassifiedIdentifier( + OBJECTTYPE_DATA_STOCK_GAIN, u"" )); + rtl::Reference< SvxShapeGroup > xTextTarget = + ShapeFactory::createGroup2D( m_xFinalTarget ); + + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + bool bJapaneseStyle=true;//@todo is this the correct default? + bool bShowFirst = true;//is only important if bJapaneseStyle == false + tNameSequence aWhiteBox_Names, aBlackBox_Names; + tAnySequence aWhiteBox_Values, aBlackBox_Values; + try + { + if( m_xChartTypeModel.is() ) + { + m_xChartTypeModel->getPropertyValue( "ShowFirst" ) >>= bShowFirst; + + uno::Reference< beans::XPropertySet > xWhiteDayProps; + uno::Reference< beans::XPropertySet > xBlackDayProps; + m_xChartTypeModel->getPropertyValue( "Japanese" ) >>= bJapaneseStyle; + m_xChartTypeModel->getPropertyValue( "WhiteDay" ) >>= xWhiteDayProps; + m_xChartTypeModel->getPropertyValue( "BlackDay" ) >>= xBlackDayProps; + + tPropertyNameValueMap aWhiteBox_Map; + PropertyMapper::getValueMap( aWhiteBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xWhiteDayProps ); + PropertyMapper::getMultiPropertyListsFromValueMap( aWhiteBox_Names, aWhiteBox_Values, aWhiteBox_Map ); + + tPropertyNameValueMap aBlackBox_Map; + PropertyMapper::getValueMap( aBlackBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xBlackDayProps ); + PropertyMapper::getMultiPropertyListsFromValueMap( aBlackBox_Names, aBlackBox_Values, aBlackBox_Map ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //(@todo maybe different iteration for breaks in axis ?) + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + double fLogicZ = 1.5;//as defined + //iterate through all x values per indices + for( sal_Int32 nIndex = 0; nIndex < nEndIndex; nIndex++ ) + { + for( auto const& rZSlot : m_aZSlots ) + { + BarPositionHelper* pPosHelper = m_pMainPosHelper.get(); + if( !rZSlot.empty() ) + { + sal_Int32 nAttachedAxisIndex = rZSlot.front().getAttachedAxisIndexForFirstSeries(); + //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot + pPosHelper = dynamic_cast(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) ); + if(!pPosHelper) + pPosHelper = m_pMainPosHelper.get(); + } + PlotterBase::m_pPosHelper = pPosHelper; + + //update/create information for current group + pPosHelper->updateSeriesCount( rZSlot.size() ); + double fSlotX=0; + //iterate through all x slots in this category + for( auto const& rXSlot : rZSlot ) + { + //iterate through all series in this x slot + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + //collect data point information (logic coordinates, style ): + double fUnscaledX = pSeries->getXValue( nIndex ); + if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) + fUnscaledX = DateHelper::RasterizeDateValue( fUnscaledX, m_aNullDate, m_nTimeResolution ); + if(fUnscaledXgetLogicMinX() || fUnscaledX>pPosHelper->getLogicMaxX()) + continue;//point not visible + double fScaledX = pPosHelper->getScaledSlotPos( fUnscaledX, fSlotX ); + + double fUnscaledY_First = pSeries->getY_First( nIndex ); + double fUnscaledY_Last = pSeries->getY_Last( nIndex ); + double fUnscaledY_Min = pSeries->getY_Min( nIndex ); + double fUnscaledY_Max = pSeries->getY_Max( nIndex ); + + bool bBlack=false; + if(fUnscaledY_Last<=fUnscaledY_First) + { + std::swap(fUnscaledY_First,fUnscaledY_Last); + bBlack=true; + } + if(fUnscaledY_Max 4) + double fHalfScaledWidth = pPosHelper->getScaledSlotWidth()/2.0; + + double fScaledY_First(fUnscaledY_First); + double fScaledY_Last(fUnscaledY_Last); + double fScaledY_Min(fUnscaledY_Min); + double fScaledY_Max(fUnscaledY_Max); + pPosHelper->clipLogicValues( nullptr,&fScaledY_First,nullptr ); + pPosHelper->clipLogicValues( nullptr,&fScaledY_Last,nullptr ); + pPosHelper->clipLogicValues( nullptr,&fScaledY_Min,nullptr ); + pPosHelper->clipLogicValues( nullptr,&fScaledY_Max,nullptr ); + pPosHelper->doLogicScaling( nullptr,&fScaledY_First,nullptr ); + pPosHelper->doLogicScaling( nullptr,&fScaledY_Last,nullptr ); + pPosHelper->doLogicScaling( nullptr,&fScaledY_Min,nullptr ); + pPosHelper->doLogicScaling( nullptr,&fScaledY_Max,nullptr ); + + drawing::Position3D aPosLeftFirst( pPosHelper->transformScaledLogicToScene( fScaledX-fHalfScaledWidth, fScaledY_First ,0 ,true ) ); + drawing::Position3D aPosRightLast( pPosHelper->transformScaledLogicToScene( fScaledX+fHalfScaledWidth, fScaledY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleFirst( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_First ,0 ,true ) ); + drawing::Position3D aPosMiddleLast( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Last ,0 ,true ) ); + drawing::Position3D aPosMiddleMinimum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Min ,0 ,true ) ); + drawing::Position3D aPosMiddleMaximum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Max ,0 ,true ) ); + + rtl::Reference xLossGainTarget( xGainTarget ); + if(bBlack) + xLossGainTarget = xLossTarget; + + uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint( nIndex )); + rtl::Reference xPointGroupShape_Shapes; + { + OUString aPointCID = ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nIndex ); + rtl::Reference xSeriesGroupShape_Shapes( getSeriesGroupShape(pSeries.get(), xSeriesTarget) ); + xPointGroupShape_Shapes = createGroupShape(xSeriesGroupShape_Shapes,aPointCID); + } + + //create min-max line + if( isValidPosition(aPosMiddleMinimum) && isValidPosition(aPosMiddleMaximum) ) + { + std::vector> aPoly + { + { aPosMiddleMinimum, aPosMiddleMaximum } + }; + + rtl::Reference xShape = + ShapeFactory::createLine2D( xPointGroupShape_Shapes, aPoly); + PropertyMapper::setMappedProperties( *xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + } + + //create first-last shape + if(bJapaneseStyle && isValidPosition(aPosLeftFirst) && isValidPosition(aPosRightLast) ) + { + drawing::Direction3D aDiff = aPosRightLast-aPosLeftFirst; + awt::Size aAWTSize( Direction3DToAWTSize( aDiff )); + // workaround for bug in drawing: if height is 0 the box gets infinitely large + if( aAWTSize.Height == 0 ) + aAWTSize.Height = 1; + + tNameSequence aNames; + tAnySequence aValues; + + rtl::Reference xShape = + ShapeFactory::createRectangle( xLossGainTarget, + aAWTSize, Position3DToAWTPoint( aPosLeftFirst ), + aNames, aValues); + + if(bBlack) + PropertyMapper::setMultiProperties( aBlackBox_Names, aBlackBox_Values, *xShape ); + else + PropertyMapper::setMultiProperties( aWhiteBox_Names, aWhiteBox_Values, *xShape ); + } + else + { + std::vector> aPoly; + + sal_Int32 nLineIndex = 0; + if( bShowFirst && pPosHelper->isLogicVisible( fUnscaledX, fUnscaledY_First ,fLogicZ ) + && isValidPosition(aPosLeftFirst) && isValidPosition(aPosMiddleFirst) ) + { + AddPointToPoly( aPoly, aPosLeftFirst, nLineIndex ); + AddPointToPoly( aPoly, aPosMiddleFirst, nLineIndex++ ); + } + if( pPosHelper->isLogicVisible( fUnscaledX, fUnscaledY_Last ,fLogicZ ) + && isValidPosition(aPosMiddleLast) && isValidPosition(aPosRightLast) ) + { + AddPointToPoly( aPoly, aPosMiddleLast, nLineIndex ); + AddPointToPoly( aPoly, aPosRightLast, nLineIndex ); + } + + if( !aPoly.empty() ) + { + rtl::Reference xShape = + ShapeFactory::createLine2D( xPointGroupShape_Shapes, aPoly ); + PropertyMapper::setMappedProperties( *xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + } + } + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nIndex) ) + { + if(isValidPosition(aPosMiddleFirst)) + createDataLabel( xTextTarget, *pSeries, nIndex + , fUnscaledY_First, 1.0, Position3DToAWTPoint(aPosMiddleFirst), LABEL_ALIGN_LEFT_BOTTOM ); + if(isValidPosition(aPosMiddleLast)) + createDataLabel( xTextTarget, *pSeries, nIndex + , fUnscaledY_Last, 1.0, Position3DToAWTPoint(aPosMiddleLast), LABEL_ALIGN_RIGHT_TOP ); + if(isValidPosition(aPosMiddleMinimum)) + createDataLabel( xTextTarget, *pSeries, nIndex + , fUnscaledY_Min, 1.0, Position3DToAWTPoint(aPosMiddleMinimum), LABEL_ALIGN_BOTTOM ); + if(isValidPosition(aPosMiddleMaximum)) + createDataLabel( xTextTarget, *pSeries, nIndex + , fUnscaledY_Max, 1.0, Position3DToAWTPoint(aPosMiddleMaximum), LABEL_ALIGN_TOP ); + } + }//next series in x slot (next y slot) + fSlotX+=1.0; + }//next x slot + }//next z slot + }//next category + /* @todo remove series shapes if empty + //remove and delete point-group-shape if empty + if(!xSeriesGroupShape_Shapes->getCount()) + { + pSeries->m_xShape.set(NULL); + m_xLogicTarget->remove(xSeriesGroupShape_Shape); + } + */ + + //remove and delete series-group-shape if empty + + //... todo +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/CandleStickChart.hxx b/chart2/source/view/charttypes/CandleStickChart.hxx new file mode 100644 index 000000000..93571889e --- /dev/null +++ b/chart2/source/view/charttypes/CandleStickChart.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace chart +{ +class BarPositionHelper; + +class CandleStickChart : public VSeriesPlotter +{ + // public methods +public: + CandleStickChart() = delete; + + CandleStickChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount ); + virtual ~CandleStickChart() override; + + virtual void createShapes() override; + virtual void addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + + // MinimumAndMaximumSupplier + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual LegendSymbolStyle getLegendSymbolStyle() override; + +private: //member + std::unique_ptr m_pMainPosHelper; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.cxx b/chart2/source/view/charttypes/CategoryPositionHelper.cxx new file mode 100644 index 000000000..d7412d3cb --- /dev/null +++ b/chart2/source/view/charttypes/CategoryPositionHelper.cxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "CategoryPositionHelper.hxx" + +namespace chart +{ + +CategoryPositionHelper::CategoryPositionHelper( double fSeriesCount, double fCategoryWidth ) + : m_fSeriesCount(fSeriesCount) + , m_fCategoryWidth(fCategoryWidth) + , m_fInnerDistance(0.0) + , m_fOuterDistance(1.0) +{ +} + +CategoryPositionHelper::~CategoryPositionHelper() +{ +} + +double CategoryPositionHelper::getScaledSlotWidth() const +{ + double fWidth = m_fCategoryWidth / + ( m_fSeriesCount + + m_fOuterDistance + + m_fInnerDistance*( m_fSeriesCount - 1.0) ); + return fWidth; +} + +double CategoryPositionHelper::getScaledSlotPos( double fScaledXPos, double fSeriesNumber ) const +{ + //the returned position is in the middle of the rect + //fSeriesNumber 0...n-1 + double fPos = fScaledXPos + - (m_fCategoryWidth/2.0) + + (m_fOuterDistance/2.0 + fSeriesNumber*(1.0+m_fInnerDistance)) * getScaledSlotWidth() + + getScaledSlotWidth()/2.0; + return fPos; +} + +void CategoryPositionHelper::setInnerDistance( double fInnerDistance ) +{ + if( fInnerDistance < -1.0 ) + fInnerDistance = -1.0; + if( fInnerDistance > 1.0 ) + fInnerDistance = 1.0; + m_fInnerDistance = fInnerDistance; +} + +void CategoryPositionHelper::setOuterDistance( double fOuterDistance ) +{ + if( fOuterDistance < 0.0 ) + fOuterDistance = 0.0; + if( fOuterDistance > 6.0 ) + fOuterDistance = 6.0; + m_fOuterDistance = fOuterDistance; +} + +void CategoryPositionHelper::setCategoryWidth( double fCategoryWidth ) +{ + m_fCategoryWidth = fCategoryWidth; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/CategoryPositionHelper.hxx b/chart2/source/view/charttypes/CategoryPositionHelper.hxx new file mode 100644 index 000000000..ebc784ef6 --- /dev/null +++ b/chart2/source/view/charttypes/CategoryPositionHelper.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +namespace chart +{ +class CategoryPositionHelper +{ +public: + CategoryPositionHelper(double fSeriesCount, double CategoryWidth = 1.0); + virtual ~CategoryPositionHelper(); + + CategoryPositionHelper(CategoryPositionHelper const&) = default; + CategoryPositionHelper(CategoryPositionHelper&&) = default; + CategoryPositionHelper& operator=(CategoryPositionHelper const&) = default; + CategoryPositionHelper& operator=(CategoryPositionHelper&&) = default; + + double getScaledSlotWidth() const; + virtual double getScaledSlotPos(double fCategoryX, double fSeriesNumber) const; + void setCategoryWidth(double fCategoryWidth); + + //Distance between two neighboring bars in same category, seen relative to width of the bar + void setInnerDistance(double fInnerDistance); + + //Distance between two neighboring bars in different category, seen relative to width of the bar: + void setOuterDistance(double fOuterDistance); + +protected: + double m_fSeriesCount; + double m_fCategoryWidth; + //Distance between two neighboring bars in same category, seen relative to width of the bar: + double + m_fInnerDistance; //[-1,1] m_fInnerDistance=1 --> distance == width; m_fInnerDistance=-1-->all rects are painted on the same position + //Distance between two neighboring bars in different category, seen relative to width of the bar: + double m_fOuterDistance; //>=0 m_fOuterDistance=1 --> distance == width +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/ConfigAccess.cxx b/chart2/source/view/charttypes/ConfigAccess.cxx new file mode 100644 index 000000000..ce02c4817 --- /dev/null +++ b/chart2/source/view/charttypes/ConfigAccess.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ +class ChartConfigItem : public ::utl::ConfigItem +{ +private: + virtual void ImplCommit() override; + +public: + ChartConfigItem(); + + bool getUseErrorRectangle(); + virtual void Notify(const uno::Sequence& aPropertyNames) override; +}; +} + +ChartConfigItem::ChartConfigItem() + : ConfigItem("Office.Chart/ErrorProperties") +{ +} + +void ChartConfigItem::ImplCommit() {} +void ChartConfigItem::Notify(const uno::Sequence&) {} + +bool ChartConfigItem::getUseErrorRectangle() +{ + uno::Sequence aNames{ "ErrorRectangle" }; + + auto b = o3tl::tryAccess(GetProperties(aNames)[0]); + return b && *b; +} + +namespace ConfigAccess +{ +bool getUseErrorRectangle() +{ + //a ChartConfigItem Singleton + static ChartConfigItem SINGLETON; + bool bResult(SINGLETON.getUseErrorRectangle()); + return bResult; +} +} //namespace ConfigAccess + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/NetChart.cxx b/chart2/source/view/charttypes/NetChart.cxx new file mode 100644 index 000000000..5b8f1db34 --- /dev/null +++ b/chart2/source/view/charttypes/NetChart.cxx @@ -0,0 +1,642 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "NetChart.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +NetChart::NetChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bNoArea + , std::unique_ptr pPlottingPositionHelper + ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount, true ) + , m_pMainPosHelper(std::move(pPlottingPositionHelper)) + , m_bArea(!bNoArea) + , m_bLine(bNoArea) +{ + // we only support 2D Net charts + assert(nDimensionCount == 2); + + m_pMainPosHelper->AllowShiftXAxisPos(true); + m_pMainPosHelper->AllowShiftZAxisPos(true); + + PlotterBase::m_pPosHelper = m_pMainPosHelper.get(); + VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get(); +} + +NetChart::~NetChart() +{ +} + +double NetChart::getMaximumX() +{ + double fMax = VSeriesPlotter::getMaximumX() + 1.0; + return fMax; +} + +bool NetChart::isExpandIfValuesCloseToBorder( sal_Int32 ) +{ + return false; +} + +bool NetChart::isSeparateStackingForDifferentSigns( sal_Int32 /*nDimensionIndex*/ ) +{ + // no separate stacking in all types of line/area charts + return false; +} + +LegendSymbolStyle NetChart::getLegendSymbolStyle() +{ + if( m_bArea ) + return LegendSymbolStyle::Box; + return LegendSymbolStyle::Line; +} + +uno::Any NetChart::getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex ) +{ + uno::Any aRet; + + Symbol* pSymbolProperties = rSeries.getSymbolProperties( nPointIndex ); + if( pSymbolProperties ) + { + aRet <<= *pSymbolProperties; + } + + return aRet; +} + +drawing::Direction3D NetChart::getPreferredDiagramAspectRatio() const +{ + return drawing::Direction3D(1,1,1); +} + +bool NetChart::impl_createLine( VDataSeries* pSeries + , const std::vector>* pSeriesPoly + , PlottingPositionHelper const * pPosHelper ) +{ + //return true if a line was created successfully + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); + + std::vector> aPoly; + { + bool bIsClipped = false; + if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) + { + // do NOT connect last and first point, if one is NAN, and NAN handling is NAN_AS_GAP + double fFirstY = pSeries->getYValue( 0 ); + double fLastY = pSeries->getYValue( VSeriesPlotter::getPointCount() - 1 ); + if( (pSeries->getMissingValueTreatment() != css::chart::MissingValueTreatment::LEAVE_GAP) + || (std::isfinite( fFirstY ) && std::isfinite( fLastY )) ) + { + // connect last point in last polygon with first point in first polygon + ::basegfx::B2DRectangle aScaledLogicClipDoubleRect( pPosHelper->getScaledLogicClipDoubleRect() ); + std::vector> aTmpPoly(*pSeriesPoly); + drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly[0][0].PositionY,aTmpPoly[0][0].PositionZ); + // add connector line to last polygon + AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->size() - 1 ); + Clipping::clipPolygonAtRectangle( aTmpPoly, aScaledLogicClipDoubleRect, aPoly ); + bIsClipped = true; + } + } + + if( !bIsClipped ) + Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + } + + if(!ShapeFactory::hasPolygonAnyLines(aPoly)) + return false; + + //transformation 3) -> 4) + pPosHelper->transformScaledLogicToScene( aPoly ); + + //create line: + rtl::Reference xShape; + { + xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes, aPoly ); + PropertyMapper::setMappedProperties( *xShape + , pSeries->getPropertiesOfSeries() + , PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); + //because of this name this line will be used for marking + ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles"); + } + return true; +} + +bool NetChart::impl_createArea( VDataSeries* pSeries + , const std::vector>* pSeriesPoly + , std::vector> const * pPreviousSeriesPoly + , PlottingPositionHelper const * pPosHelper ) +{ + //return true if an area was created successfully + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); + double zValue = pSeries->m_fLogicZPos; + + std::vector> aPoly( *pSeriesPoly ); + //add second part to the polygon (grounding points or previous series points) + if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) + { + if( pPreviousSeriesPoly ) + addPolygon( aPoly, *pPreviousSeriesPoly ); + } + else if(!pPreviousSeriesPoly) + { + double fMinX = pSeries->m_fLogicMinX; + double fMaxX = pSeries->m_fLogicMaxX; + double fY = pPosHelper->getBaseValueY();//logic grounding + + //clip to scale + if(fMaxXgetLogicMinX() || fMinX>pPosHelper->getLogicMaxX()) + return false;//no visible shape needed + pPosHelper->clipLogicValues( &fMinX, &fY, nullptr ); + pPosHelper->clipLogicValues( &fMaxX, nullptr, nullptr ); + + //apply scaling + { + pPosHelper->doLogicScaling( &fMinX, &fY, &zValue ); + pPosHelper->doLogicScaling( &fMaxX, nullptr, nullptr ); + } + + AddPointToPoly( aPoly, drawing::Position3D( fMaxX,fY,zValue) ); + AddPointToPoly( aPoly, drawing::Position3D( fMinX,fY,zValue) ); + } + else + { + appendPoly( aPoly, *pPreviousSeriesPoly ); + } + ShapeFactory::closePolygon(aPoly); + + //apply clipping + { + std::vector> aClippedPoly; + Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false ); + ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping + aPoly = aClippedPoly; + } + + if(!ShapeFactory::hasPolygonAnyLines(aPoly)) + return false; + + //transformation 3) -> 4) + pPosHelper->transformScaledLogicToScene( aPoly ); + + //create area: + rtl::Reference + xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes + , aPoly ); + PropertyMapper::setMappedProperties( *xShape + , pSeries->getPropertiesOfSeries() + , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + //because of this name this line will be used for marking + ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles"); + return true; +} + +void NetChart::impl_createSeriesShapes() +{ + //the polygon shapes for each series need to be created before + + //iterate through all series again to create the series shapes + for( auto const& rZSlot : m_aZSlots ) + { + for( auto const& rXSlot : rZSlot ) + { + std::map< sal_Int32, std::vector>* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex + std::vector>* pSeriesPoly = nullptr; + + //iterate through all series + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex); + + pSeriesPoly = &pSeries->m_aPolyPolygonShape3D; + if( m_bArea ) + { + if (!impl_createArea(pSeries.get(), pSeriesPoly, + aPreviousSeriesPolyMap[nAttachedAxisIndex], m_pPosHelper)) + continue; + } + if( m_bLine ) + { + if (!impl_createLine(pSeries.get(), pSeriesPoly, m_pPosHelper)) + continue; + } + aPreviousSeriesPolyMap[nAttachedAxisIndex] = pSeriesPoly; + }//next series in x slot (next y slot) + }//next x slot + }//next z slot +} + +namespace +{ + +void lcl_reorderSeries( std::vector< std::vector< VDataSeriesGroup > >& rZSlots ) +{ + std::vector< std::vector< VDataSeriesGroup > > aRet; + aRet.reserve( rZSlots.size() ); + + std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZIt( rZSlots.rbegin() ); + std::vector< std::vector< VDataSeriesGroup > >::reverse_iterator aZEnd( rZSlots.rend() ); + for( ; aZIt != aZEnd; ++aZIt ) + { + std::vector< VDataSeriesGroup > aXSlot; + + std::vector< VDataSeriesGroup >::reverse_iterator aXIt( aZIt->rbegin() ); + std::vector< VDataSeriesGroup >::reverse_iterator aXEnd( aZIt->rend() ); + for( ; aXIt != aXEnd; ++aXIt ) + aXSlot.push_back(std::move(*aXIt)); + + aRet.push_back(std::move(aXSlot)); + } + + rZSlots = std::move(aRet); +} + +//better performance for big data +struct FormerPoint +{ + FormerPoint( double fX, double fY, double fZ ) + : m_fX(fX), m_fY(fY), m_fZ(fZ) + {} + FormerPoint() + : m_fX(std::numeric_limits::quiet_NaN()) + , m_fY(std::numeric_limits::quiet_NaN()) + , m_fZ(std::numeric_limits::quiet_NaN()) + + { + } + + double m_fX; + double m_fY; + double m_fZ; +}; + +}//anonymous namespace + +void NetChart::createShapes() +{ + if( m_aZSlots.empty() ) //no series + return; + + //tdf#127813 Don't reverse the series in OOXML-heavy environments + if (officecfg::Office::Compatibility::View::ReverseSeriesOrderAreaAndNetChart::get() && m_bArea) + lcl_reorderSeries( m_aZSlots ); + + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"NetChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) + return; + + //the text labels should be always on top of the other series shapes + //for area chart the error bars should be always on top of the other series shapes + + //therefore create an own group for the texts and the error bars to move them to front + //(because the text group is created after the series group the texts are displayed on top) + m_xSeriesTarget = createGroupShape( m_xLogicTarget ); + m_xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + //update/create information for current group + double fLogicZ = 1.0;//as defined + + sal_Int32 const nStartIndex = 0; // inclusive ;..todo get somehow from x scale + sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); + if(nEndIndex<=0) + nEndIndex=1; + + //better performance for big data + std::map< VDataSeries*, FormerPoint > aSeriesFormerPointMap; + m_bPointsWereSkipped = false; + + bool bDateCategory = (m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis()); + + //iterate through all x values per indices + for( sal_Int32 nIndex = nStartIndex; nIndex < nEndIndex; nIndex++ ) + { + std::map< sal_Int32, double > aLogicYSumMap;//one for each different nAttachedAxisIndex + for( auto const& rZSlot : m_aZSlots ) + { + //iterate through all x slots in this category to get 100percent sum + for( auto const& rXSlot : rZSlot ) + { + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + if (bDateCategory) + pSeries->doSortByXValues(); + + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + aLogicYSumMap.insert({nAttachedAxisIndex, 0.0}); + + m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex); + + double fAdd = pSeries->getYValue( nIndex ); + if( !std::isnan(fAdd) && !std::isinf(fAdd) ) + aLogicYSumMap[nAttachedAxisIndex] += fabs( fAdd ); + } + } + } + + for( auto const& rZSlot : m_aZSlots ) + { + //for the area chart there should be at most one x slot (no side by side stacking available) + //attention different: xSlots are always interpreted as independent areas one behind the other: @todo this doesn't work why not??? + for( auto const& rXSlot : rZSlot ) + { + std::map< sal_Int32, double > aLogicYForNextSeriesMap;//one for each different nAttachedAxisIndex + //iterate through all series + for( std::unique_ptr const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + /* #i70133# ignore points outside of series length in standard area + charts. Stacked area charts will use missing points as zeros. In + standard charts, pSeriesList contains only one series. */ + if( m_bArea && (rXSlot.m_aSeriesVector.size() == 1) && (nIndex >= pSeries->getTotalPointCount()) ) + continue; + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShapeFrontChild(pSeries.get(), m_xSeriesTarget); + + sal_Int32 nAttachedAxisIndex = pSeries->getAttachedAxisIndex(); + m_pPosHelper = &getPlottingPositionHelper(nAttachedAxisIndex); + + pSeries->m_fLogicZPos = fLogicZ; + + //collect data point information (logic coordinates, style ): + double fLogicX = pSeries->getXValue(nIndex); + if (bDateCategory) + fLogicX = DateHelper::RasterizeDateValue( fLogicX, m_aNullDate, m_nTimeResolution ); + double fLogicY = pSeries->getYValue(nIndex); + + if( m_bArea && ( std::isnan(fLogicY) || std::isinf(fLogicY) ) ) + { + if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP ) + { + if( rXSlot.m_aSeriesVector.size() == 1 || pSeries == rXSlot.m_aSeriesVector.front() ) + { + fLogicY = m_pPosHelper->getLogicMinY(); + if (!m_pPosHelper->isMathematicalOrientationY()) + fLogicY = m_pPosHelper->getLogicMaxY(); + } + else + fLogicY = 0.0; + } + } + + if (m_pPosHelper->isPercentY() && aLogicYSumMap[nAttachedAxisIndex] != 0.0) + { + fLogicY = fabs( fLogicY )/aLogicYSumMap[nAttachedAxisIndex]; + } + + if( std::isnan(fLogicX) || std::isinf(fLogicX) + || std::isnan(fLogicY) || std::isinf(fLogicY) + || std::isnan(fLogicZ) || std::isinf(fLogicZ) ) + { + if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP ) + { + std::vector>& rPolygon = pSeries->m_aPolyPolygonShape3D; + sal_Int32& rIndex = pSeries->m_nPolygonIndex; + if( 0<= rIndex && o3tl::make_unsigned(rIndex) < rPolygon.size() ) + { + if( !rPolygon[ rIndex ].empty() ) + rIndex++; //start a new polygon for the next point if the current poly is not empty + } + } + continue; + } + + aLogicYForNextSeriesMap.try_emplace(nAttachedAxisIndex, 0.0); + + double fLogicValueForLabeDisplay = fLogicY; + + fLogicY += aLogicYForNextSeriesMap[nAttachedAxisIndex]; + aLogicYForNextSeriesMap[nAttachedAxisIndex] = fLogicY; + + bool bIsVisible = m_pPosHelper->isLogicVisible(fLogicX, fLogicY, fLogicZ); + + //remind minimal and maximal x values for area 'grounding' points + //only for filled area + { + double& rfMinX = pSeries->m_fLogicMinX; + if(!nIndex||fLogicXm_fLogicMaxX; + if(!nIndex||fLogicX>rfMaxX) + rfMaxX=fLogicX; + } + + drawing::Position3D aUnscaledLogicPosition( fLogicX, fLogicY, fLogicZ ); + drawing::Position3D aScaledLogicPosition(aUnscaledLogicPosition); + m_pPosHelper->doLogicScaling(aScaledLogicPosition); + + //transformation 3) -> 4) + drawing::Position3D aScenePosition( + m_pPosHelper->transformLogicToScene(fLogicX, fLogicY, fLogicZ, false)); + + //better performance for big data + FormerPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); + m_pPosHelper->setCoordinateSystemResolution(m_aCoordinateSystemResolution); + if( !pSeries->isAttributedDataPoint(nIndex) + && m_pPosHelper->isSameForGivenResolution( + aFormerPoint.m_fX, aFormerPoint.m_fY, aFormerPoint.m_fZ + , aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ ) ) + { + m_bPointsWereSkipped = true; + continue; + } + aSeriesFormerPointMap[pSeries.get()] = FormerPoint(aScaledLogicPosition.PositionX, aScaledLogicPosition.PositionY, aScaledLogicPosition.PositionZ); + + //store point information for series polygon + //for area and/or line (symbols only do not need this) + if( isValidPosition(aScaledLogicPosition) ) + { + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aScaledLogicPosition, pSeries->m_nPolygonIndex ); + + //prepare clipping for filled net charts + if( !bIsVisible && m_bArea ) + { + drawing::Position3D aClippedPos(aScaledLogicPosition); + m_pPosHelper->clipScaledLogicValues(nullptr, &aClippedPos.PositionY, + nullptr); + if (m_pPosHelper->isLogicVisible(aClippedPos.PositionX, + aClippedPos.PositionY, + aClippedPos.PositionZ)) + { + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aClippedPos, pSeries->m_nPolygonIndex ); + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aScaledLogicPosition, pSeries->m_nPolygonIndex ); + } + } + } + + //create a single datapoint if point is visible + //apply clipping: + if( !bIsVisible ) + continue; + + Symbol* pSymbolProperties = pSeries->getSymbolProperties( nIndex ); + bool bCreateSymbol = pSymbolProperties && (pSymbolProperties->Style != SymbolStyle_NONE); + + if( !bCreateSymbol && !pSeries->getDataPointLabelIfLabel(nIndex) ) + continue; + + //create a group shape for this point and add to the series shape: + OUString aPointCID = ObjectIdentifier::createPointCID( + pSeries->getPointCID_Stub(), nIndex ); + rtl::Reference xPointGroupShape_Shapes( + createGroupShape(xSeriesGroupShape_Shapes,aPointCID) ); + + { + //create data point + drawing::Direction3D aSymbolSize(0,0,0); + if (bCreateSymbol) // implies pSymbolProperties + { + if (pSymbolProperties->Style != SymbolStyle_NONE) + { + aSymbolSize.DirectionX = pSymbolProperties->Size.Width; + aSymbolSize.DirectionY = pSymbolProperties->Size.Height; + } + + if (pSymbolProperties->Style == SymbolStyle_STANDARD) + { + sal_Int32 nSymbol = pSymbolProperties->StandardSymbol; + ShapeFactory::createSymbol2D( + xPointGroupShape_Shapes, aScenePosition, aSymbolSize, nSymbol, + pSymbolProperties->BorderColor, pSymbolProperties->FillColor); + } + else if (pSymbolProperties->Style == SymbolStyle_GRAPHIC) + { + ShapeFactory::createGraphic2D(xPointGroupShape_Shapes, + aScenePosition, aSymbolSize, + pSymbolProperties->Graphic); + } + //@todo other symbol styles + } + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nIndex) ) + { + LabelAlignment eAlignment = LABEL_ALIGN_TOP; + drawing::Position3D aScenePosition3D( aScenePosition.PositionX + , aScenePosition.PositionY + , aScenePosition.PositionZ+getTransformedDepth() ); + + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( + nIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY()); + + switch(nLabelPlacement) + { + case css::chart::DataLabelPlacement::TOP: + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + case css::chart::DataLabelPlacement::BOTTOM: + aScenePosition3D.PositionY += (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_BOTTOM; + break; + case css::chart::DataLabelPlacement::LEFT: + aScenePosition3D.PositionX -= (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_LEFT; + break; + case css::chart::DataLabelPlacement::RIGHT: + aScenePosition3D.PositionX += (aSymbolSize.DirectionX/2+1); + eAlignment = LABEL_ALIGN_RIGHT; + break; + case css::chart::DataLabelPlacement::CENTER: + eAlignment = LABEL_ALIGN_CENTER; + //todo implement this different for area charts + break; + default: + OSL_FAIL("this label alignment is not implemented yet"); + aScenePosition3D.PositionY -= (aSymbolSize.DirectionY/2+1); + eAlignment = LABEL_ALIGN_TOP; + break; + } + + awt::Point aScreenPosition2D;//get the screen position for the labels + sal_Int32 nOffset = 100; //todo maybe calculate this font height dependent + if( nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE ) + { + PolarPlottingPositionHelper* pPolarPosHelper + = dynamic_cast(m_pPosHelper); + if( pPolarPosHelper ) + { + PolarLabelPositionHelper aPolarLabelPositionHelper(pPolarPosHelper,m_nDimension,m_xLogicTarget); + aScreenPosition2D = aPolarLabelPositionHelper.getLabelScreenPositionAndAlignmentForLogicValues( + eAlignment, fLogicX, fLogicY, fLogicZ, nOffset ); + } + } + else + { + if(eAlignment==LABEL_ALIGN_CENTER ) + nOffset = 0; + aScreenPosition2D = LabelPositionHelper(m_nDimension,m_xLogicTarget) + .transformSceneToScreenPosition( aScenePosition3D ); + } + + createDataLabel( m_xTextTarget, *pSeries, nIndex + , fLogicValueForLabeDisplay + , aLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset ); + } + } + + //remove PointGroupShape if empty + if(!xPointGroupShape_Shapes->getCount()) + xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shapes); + + }//next series in x slot (next y slot) + }//next x slot + }//next z slot + }//next category + + impl_createSeriesShapes(); + +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/NetChart.hxx b/chart2/source/view/charttypes/NetChart.hxx new file mode 100644 index 000000000..a536daf15 --- /dev/null +++ b/chart2/source/view/charttypes/NetChart.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace chart +{ + +class NetChart : public VSeriesPlotter +{ + // public methods +public: + NetChart() = delete; + + NetChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bNoArea + , std::unique_ptr pPlottingPositionHelper //takes ownership + ); + virtual ~NetChart() override; + + virtual void createShapes() override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + + // MinimumAndMaximumSupplier + virtual double getMaximumX() override; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual LegendSymbolStyle getLegendSymbolStyle() override; + virtual css::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex/*-1 for series symbol*/ ) override; + +private: //methods + void impl_createSeriesShapes(); + bool impl_createArea( VDataSeries* pSeries + , const std::vector>* pSeriesPoly + , std::vector> const * pPreviousSeriesPoly + , PlottingPositionHelper const * pPosHelper ); + bool impl_createLine( VDataSeries* pSeries + , const std::vector>* pSeriesPoly + , PlottingPositionHelper const * pPosHelper ); + +private: //member + std::unique_ptr m_pMainPosHelper; + + bool m_bArea;//false -> line or symbol only + bool m_bLine; + + rtl::Reference m_xSeriesTarget; + rtl::Reference m_xTextTarget; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx new file mode 100644 index 000000000..a81428c24 --- /dev/null +++ b/chart2/source/view/charttypes/PieChart.cxx @@ -0,0 +1,1719 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "PieChart.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +namespace chart { + +struct PieChart::ShapeParam +{ + /** the start angle of the slice + */ + double mfUnitCircleStartAngleDegree; + + /** the angle width of the slice + */ + double mfUnitCircleWidthAngleDegree; + + /** the normalized outer radius of the ring the slice belongs to. + */ + double mfUnitCircleOuterRadius; + + /** the normalized inner radius of the ring the slice belongs to + */ + double mfUnitCircleInnerRadius; + + /** relative distance offset of a slice from the pie center; + * this parameter is used for instance when the user performs manual + * dragging of a slice (the drag operation is possible only for slices that + * belong to the outer ring and only along the ray bisecting the slice); + * the value for the given entry in the data series is obtained by the + * `Offset` property attached to each entry; note that the value + * provided by the `Offset` property is used both as a logical value in + * `PiePositionHelper::getInnerAndOuterRadius` and as a percentage value in + * the `PieChart::createDataPoint` and `PieChart::createTextLabelShape` + * methods; since the logical height of a ring is always 1, this duality + * does not cause any incorrect behavior; + */ + double mfExplodePercentage; + + /** sum of all Y values in a single series + */ + double mfLogicYSum; + + /** for 3D pie chart: label z coordinate + */ + double mfLogicZ; + + /** for 3D pie chart: height + */ + double mfDepth; + + ShapeParam() : + mfUnitCircleStartAngleDegree(0.0), + mfUnitCircleWidthAngleDegree(0.0), + mfUnitCircleOuterRadius(0.0), + mfUnitCircleInnerRadius(0.0), + mfExplodePercentage(0.0), + mfLogicYSum(0.0), + mfLogicZ(0.0), + mfDepth(0.0) {} +}; + +namespace +{ +::basegfx::B2IRectangle lcl_getRect(const rtl::Reference& xShape) +{ + ::basegfx::B2IRectangle aRect; + if (xShape.is()) + aRect = BaseGFXHelper::makeRectangle(xShape->getPosition(), xShape->getSize()); + return aRect; +} + +bool lcl_isInsidePage(const awt::Point& rPos, const awt::Size& rSize, const awt::Size& rPageSize) +{ + if (rPos.X < 0 || rPos.Y < 0) + return false; + if ((rPos.X + rSize.Width) > rPageSize.Width) + return false; + if ((rPos.Y + rSize.Height) > rPageSize.Height) + return false; + return true; +} + +} //end anonymous namespace + +class PiePositionHelper : public PolarPlottingPositionHelper +{ +public: + PiePositionHelper( double fAngleDegreeOffset ); + + bool getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const; + +public: + //Distance between different category rings, seen relative to width of a ring: + double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width +}; + +PiePositionHelper::PiePositionHelper( double fAngleDegreeOffset ) + : m_fRingDistance(0.0) +{ + m_fRadiusOffset = 0.0; + m_fAngleDegreeOffset = fAngleDegreeOffset; +} + +/** Compute the outer and the inner radius for the current ring (not for the + * whole donut!), in general it is: + * inner_radius = (ring_index + 1) - 0.5 + max_offset, + * outer_radius = (ring_index + 1) + 0.5 + max_offset. + * When orientation for the radius axis is reversed these values are swapped. + * (Indeed the orientation for the radius axis is always reversed! + * See `PieChartTypeTemplate::adaptScales`.) + * The maximum relative offset (see notes for `PieChart::getMaxOffset`) is + * added to both the inner and the outer radius. + * It returns true if the ring is visible (that is not out of the radius + * axis scale range). + */ +bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX + , double& fLogicInnerRadius, double& fLogicOuterRadius + , bool bUseRings, double fMaxOffset ) const +{ + if( !bUseRings ) + fCategoryX = 1.0; + + double fLogicInner = fCategoryX -0.5+m_fRingDistance/2.0; + double fLogicOuter = fCategoryX +0.5-m_fRingDistance/2.0; + + if( !isMathematicalOrientationRadius() ) + { + //in this case the given getMaximumX() was not correct instead the minimum should have been smaller by fMaxOffset + //but during getMaximumX and getMimumX we do not know the axis orientation + fLogicInner += fMaxOffset; + fLogicOuter += fMaxOffset; + } + + if( fLogicInner >= getLogicMaxX() ) + return false; + if( fLogicOuter <= getLogicMinX() ) + return false; + + if( fLogicInner < getLogicMinX() ) + fLogicInner = getLogicMinX(); + if( fLogicOuter > getLogicMaxX() ) + fLogicOuter = getLogicMaxX(); + + fLogicInnerRadius = fLogicInner; + fLogicOuterRadius = fLogicOuter; + if( !isMathematicalOrientationRadius() ) + std::swap(fLogicInnerRadius,fLogicOuterRadius); + return true; +} + +PieChart::PieChart( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bExcludingPositioning ) + : VSeriesPlotter( xChartTypeModel, nDimensionCount ) + , m_pPosHelper( new PiePositionHelper( (m_nDimension==3) ? 0.0 : 90.0 ) ) + , m_bUseRings(false) + , m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning) + , m_fMaxOffset(std::numeric_limits::quiet_NaN()) +{ + PlotterBase::m_pPosHelper = m_pPosHelper.get(); + VSeriesPlotter::m_pMainPosHelper = m_pPosHelper.get(); + m_pPosHelper->m_fRadiusOffset = 0.0; + m_pPosHelper->m_fRingDistance = 0.0; + + if( !xChartTypeModel.is() ) + return; + + try + { + xChartTypeModel->getPropertyValue( "UseRings") >>= m_bUseRings; + if( m_bUseRings ) + { + m_pPosHelper->m_fRadiusOffset = 1.0; + if( nDimensionCount==3 ) + m_pPosHelper->m_fRingDistance = 0.1; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +PieChart::~PieChart() +{ +} + +void PieChart::setScales( std::vector< ExplicitScaleData >&& rScales, bool /* bSwapXAndYAxis */ ) +{ + OSL_ENSURE(m_nDimension<=static_cast(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence"); + m_pPosHelper->setScales( std::move(rScales), true ); +} + +drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const +{ + if( m_nDimension == 3 ) + return drawing::Direction3D(1,1,0.10); + return drawing::Direction3D(1,1,1); +} + +bool PieChart::shouldSnapRectToUsedArea() +{ + return true; +} + +rtl::Reference PieChart::createDataPoint( + const rtl::Reference& xTarget, + const uno::Reference& xObjectProperties, + const ShapeParam& rParam, + const sal_Int32 nPointCount, + const bool bConcentricExplosion) +{ + //transform position: + drawing::Direction3D aOffset; + double fExplodedInnerRadius = rParam.mfUnitCircleInnerRadius; + double fExplodedOuterRadius = rParam.mfUnitCircleOuterRadius; + double fStartAngle = rParam.mfUnitCircleStartAngleDegree; + double fWidthAngle = rParam.mfUnitCircleWidthAngleDegree; + + if (rParam.mfExplodePercentage != 0.0) { + double fRadius = (fExplodedOuterRadius-fExplodedInnerRadius)*rParam.mfExplodePercentage; + + if (bConcentricExplosion) { + + // For concentric explosion, increase the radius but retain the original + // arc length of all ring segments together. This results in a gap + // that's evenly divided among all segments, assuming they all have + // the same explosion percentage + assert(fExplodedInnerRadius >= 0 && fExplodedOuterRadius > 0); + double fAngleRatio = (fExplodedInnerRadius + fExplodedOuterRadius) / + (fExplodedInnerRadius + fExplodedOuterRadius + 2 * fRadius); + + assert(nPointCount > 0); + double fAngleGap = 360 * (1.0 - fAngleRatio) / nPointCount; + fStartAngle += fAngleGap / 2; + fWidthAngle -= fAngleGap; + + fExplodedInnerRadius += fRadius; + fExplodedOuterRadius += fRadius; + + } else { + // For the non-concentric explosion case, keep the original radius + // but shift the circle origin + double fAngle = fStartAngle + fWidthAngle/2.0; + + drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene(0, 0, rParam.mfLogicZ); + drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene(fAngle, fRadius, rParam.mfLogicZ); + aOffset = aNewOrigin - aOrigin; + } + } + + //create point + rtl::Reference xShape; + if(m_nDimension==3) + { + xShape = ShapeFactory::createPieSegment( xTarget + , fStartAngle, fWidthAngle + , fExplodedInnerRadius, fExplodedOuterRadius + , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) + , rParam.mfDepth ); + } + else + { + xShape = ShapeFactory::createPieSegment2D( xTarget + , fStartAngle, fWidthAngle + , fExplodedInnerRadius, fExplodedOuterRadius + , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) ); + } + PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + return xShape; +} + +void PieChart::createTextLabelShape( + const rtl::Reference& xTextTarget, + VDataSeries& rSeries, sal_Int32 nPointIndex, ShapeParam& rParam ) +{ + if (!rSeries.getDataPointLabelIfLabel(nPointIndex)) + // There is no text label for this data point. Nothing to do. + return; + + ///by using the `mfExplodePercentage` parameter a normalized offset is added + ///to both normalized radii. (See notes for + ///`PolarPlottingPositionHelper::transformToRadius`, especially example 3, + ///and related comments). + if (rParam.mfExplodePercentage != 0.0) + { + double fExplodeOffset = (rParam.mfUnitCircleOuterRadius-rParam.mfUnitCircleInnerRadius)*rParam.mfExplodePercentage; + rParam.mfUnitCircleInnerRadius += fExplodeOffset; + rParam.mfUnitCircleOuterRadius += fExplodeOffset; + } + + ///get the required label placement type. Available placements are + ///`AVOID_OVERLAP`, `CENTER`, `OUTSIDE` and `INSIDE`; + sal_Int32 nLabelPlacement = rSeries.getLabelPlacement( + nPointIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY()); + + ///when the placement is of `AVOID_OVERLAP` type a later rearrangement of + ///the label position is allowed; the `createTextLabelShape` treats the + ///`AVOID_OVERLAP` as if it was of `CENTER` type; + + double nVal = rSeries.getYValue(nPointIndex); + //AVOID_OVERLAP is in fact "Best fit" in the UI. + bool bMovementAllowed = nLabelPlacement == css::chart::DataLabelPlacement::AVOID_OVERLAP + || nLabelPlacement == css::chart::DataLabelPlacement::CUSTOM; + if( bMovementAllowed ) + nLabelPlacement = css::chart::DataLabelPlacement::CENTER; + + ///for `OUTSIDE` (`INSIDE`) label placements an offset of 150 (-150), in the + ///radius direction, is added to the final screen position of the label + ///anchor point. This is required in order to ensure that the label is + ///completely outside (inside) the related slice. Indeed this value should + ///depend on the font height; + ///pay attention: 150 is not a big offset, in fact the screen position + ///coordinates for label anchor points are in the 10000-20000 range, hence + ///these are coordinates of a virtual screen and 150 is a small value; + LabelAlignment eAlignment(LABEL_ALIGN_CENTER); + sal_Int32 nScreenValueOffsetInRadiusDirection = 0 ; + if( nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE ) + nScreenValueOffsetInRadiusDirection = (m_nDimension!=3) ? 150 : 0;//todo maybe calculate this font height dependent + else if( nLabelPlacement == css::chart::DataLabelPlacement::INSIDE ) + nScreenValueOffsetInRadiusDirection = (m_nDimension!=3) ? -150 : 0;//todo maybe calculate this font height dependent + + ///the scene position of the label anchor point is calculated (see notes for + ///`PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues`), + ///and immediately transformed into the screen position. + PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper.get(),m_nDimension,m_xLogicTarget); + awt::Point aScreenPosition2D( + aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement + , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree + , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius, rParam.mfLogicZ+0.5, 0 )); + + ///the screen position of the pie/donut center is calculated. + PieLabelInfo aPieLabelInfo; + aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y ); + awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, rParam.mfLogicZ+1.0 ) ) ); + aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y ); + + ///add a scaling independent Offset if requested + if( nScreenValueOffsetInRadiusDirection != 0) + { + basegfx::B2IVector aDirection( aScreenPosition2D.X- aOrigin.X, aScreenPosition2D.Y- aOrigin.Y ); + aDirection.setLength(nScreenValueOffsetInRadiusDirection); + aScreenPosition2D.X += aDirection.getX(); + aScreenPosition2D.Y += aDirection.getY(); + } + + // compute outer pie radius + awt::Point aOuterCirclePoint = PlottingPositionHelper::transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( + 0, + rParam.mfUnitCircleOuterRadius, + 0 ), + m_xLogicTarget, m_nDimension ); + basegfx::B2IVector aRadiusVector( + aOuterCirclePoint.X - aPieLabelInfo.aOrigin.getX(), + aOuterCirclePoint.Y - aPieLabelInfo.aOrigin.getY() ); + double fSquaredPieRadius = aRadiusVector.scalar(aRadiusVector); + double fPieRadius = sqrt( fSquaredPieRadius ); + double fAngleDegree + = rParam.mfUnitCircleStartAngleDegree + rParam.mfUnitCircleWidthAngleDegree / 2.0; + while (fAngleDegree > 360.0) + fAngleDegree -= 360.0; + while (fAngleDegree < 0.0) + fAngleDegree += 360.0; + + awt::Point aOuterPosition = PlottingPositionHelper::transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene(fAngleDegree, rParam.mfUnitCircleOuterRadius, 0), + m_xLogicTarget, m_nDimension); + aPieLabelInfo.aOuterPosition = basegfx::B2IVector(aOuterPosition.X, aOuterPosition.Y); + + // set the maximum text width to be used when text wrapping is enabled + double fTextMaximumFrameWidth = 0.8 * fPieRadius; + if (nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE + && m_aAvailableOuterRect.getWidth()) + { + if ((fAngleDegree >= 67.5 && fAngleDegree <= 112.5) + || (fAngleDegree >= 247.5 && fAngleDegree <= 292.5)) + fTextMaximumFrameWidth = m_aAvailableOuterRect.getWidth() / 3.0; + else + fTextMaximumFrameWidth = 0.85 * (m_aAvailableOuterRect.getWidth() / 2.0 - fPieRadius); + } + sal_Int32 nTextMaximumFrameWidth = ceil(fTextMaximumFrameWidth); + + ///the text shape for the label is created + aPieLabelInfo.xTextShape = createDataLabel( + xTextTarget, rSeries, nPointIndex, nVal, rParam.mfLogicYSum, + aScreenPosition2D, eAlignment, 0, nTextMaximumFrameWidth); + + ///a new `PieLabelInfo` instance is initialized with all the info related to + ///the current label in order to simplify later label position rearrangement; + rtl::Reference< SvxShape > xChild = aPieLabelInfo.xTextShape; + + ///text shape could be empty; in that case there is no need to add label info + if( !xChild.is() ) + return; + + aPieLabelInfo.xLabelGroupShape = dynamic_cast(xChild->getParent().get()); + + if (bMovementAllowed && !m_bUseRings) + { + /** Handle the placement of the label in the best fit case. + * First off the routine try to place the label inside the related pie slice, + * if this is not possible the label is placed outside. + */ + if (rSeries.getLabelPlacement(nPointIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY()) + == css::chart::DataLabelPlacement::CUSTOM + || !performLabelBestFitInnerPlacement(rParam, aPieLabelInfo)) + { + if (m_aAvailableOuterRect.getWidth()) + { + if ((fAngleDegree >= 67.5 && fAngleDegree <= 112.5) + || (fAngleDegree >= 247.5 && fAngleDegree <= 292.5)) + fTextMaximumFrameWidth = m_aAvailableOuterRect.getWidth() / 3.0; + else + fTextMaximumFrameWidth + = 0.85 * (m_aAvailableOuterRect.getWidth() / 2.0 - fPieRadius); + nTextMaximumFrameWidth = ceil(fTextMaximumFrameWidth); + } + + nScreenValueOffsetInRadiusDirection = (m_nDimension != 3) ? 150 : 0; + aScreenPosition2D + = aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues( + eAlignment, css::chart::DataLabelPlacement::OUTSIDE, + rParam.mfUnitCircleStartAngleDegree, + rParam.mfUnitCircleWidthAngleDegree, rParam.mfUnitCircleInnerRadius, + rParam.mfUnitCircleOuterRadius, rParam.mfLogicZ + 0.5, 0); + aPieLabelInfo.aFirstPosition + = basegfx::B2IVector(aScreenPosition2D.X, aScreenPosition2D.Y); + + //add a scaling independent Offset if requested + if (nScreenValueOffsetInRadiusDirection != 0) + { + basegfx::B2IVector aDirection(aScreenPosition2D.X - aOrigin.X, + aScreenPosition2D.Y - aOrigin.Y); + aDirection.setLength(nScreenValueOffsetInRadiusDirection); + aScreenPosition2D.X += aDirection.getX(); + aScreenPosition2D.Y += aDirection.getY(); + } + + uno::Reference xShapes(xChild->getParent(), uno::UNO_QUERY); + xShapes->remove(aPieLabelInfo.xTextShape); + aPieLabelInfo.xTextShape + = createDataLabel(xTextTarget, rSeries, nPointIndex, nVal, rParam.mfLogicYSum, + aScreenPosition2D, eAlignment, 0, nTextMaximumFrameWidth); + xChild = aPieLabelInfo.xTextShape; + if (!xChild.is()) + return; + + aPieLabelInfo.xLabelGroupShape = dynamic_cast(xChild->getParent().get()); + } + } + + bool bShowLeaderLine = rSeries.getPropertiesOfSeries() + ->getPropertyValue("ShowCustomLeaderLines") + .get(); + if (m_bPieLabelsAllowToMove) + { + ::basegfx::B2IRectangle aRect(lcl_getRect(aPieLabelInfo.xLabelGroupShape)); + sal_Int32 nPageWidth = m_aPageReferenceSize.Width; + sal_Int32 nPageHeight = m_aPageReferenceSize.Height; + + // the data label should be inside the chart area + awt::Point aShapePos = aPieLabelInfo.xLabelGroupShape->getPosition(); + if (aRect.getMinX() < 0) + aPieLabelInfo.xLabelGroupShape->setPosition( + awt::Point(aShapePos.X - aRect.getMinX(), aShapePos.Y)); + if (aRect.getMinY() < 0) + aPieLabelInfo.xLabelGroupShape->setPosition( + awt::Point(aShapePos.X, aShapePos.Y - aRect.getMinY())); + if (aRect.getMaxX() > nPageWidth) + aPieLabelInfo.xLabelGroupShape->setPosition( + awt::Point(aShapePos.X - (aRect.getMaxX() - nPageWidth), aShapePos.Y)); + if (aRect.getMaxY() > nPageHeight) + aPieLabelInfo.xLabelGroupShape->setPosition( + awt::Point(aShapePos.X, aShapePos.Y - (aRect.getMaxY() - nPageHeight))); + + if (rSeries.isLabelCustomPos(nPointIndex) && bShowLeaderLine) + { + sal_Int32 nX1 = aPieLabelInfo.aOuterPosition.getX(); + sal_Int32 nY1 = aPieLabelInfo.aOuterPosition.getY(); + sal_Int32 nX2 = nX1; + sal_Int32 nY2 = nY1; + if (nX1 < aRect.getMinX()) + nX2 = aRect.getMinX(); + else if (nX1 > aRect.getMaxX()) + nX2 = aRect.getMaxX(); + + if (nY1 < aRect.getMinY()) + nY2 = aRect.getMinY(); + else if (nY1 > aRect.getMaxY()) + nY2 = aRect.getMaxY(); + + sal_Int32 nSquaredDistanceFromOrigin + = (nX2 - aOrigin.X) * (nX2 - aOrigin.X) + (nY2 - aOrigin.Y) * (nY2 - aOrigin.Y); + + // tdf#138018 Don't show leader line when custom positioned data label is inside pie chart + if (nSquaredDistanceFromOrigin > fSquaredPieRadius) + { + //when the line is very short compared to the page size don't create one + ::basegfx::B2DVector aLength(nX1 - nX2, nY1 - nY2); + double fPageDiagonaleLength = std::hypot(nPageWidth, nPageHeight); + if ((aLength.getLength() / fPageDiagonaleLength) >= 0.01) + { + drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } }; + + VLineProperties aVLineProperties; + if (aPieLabelInfo.xTextShape.is()) + { + sal_Int32 nColor = 0; + aPieLabelInfo.xTextShape->SvxShape::getPropertyValue("CharColor") >>= nColor; + //automatic font color does not work for lines -> fallback to black + if (nColor != -1) + aVLineProperties.Color <<= nColor; + } + ShapeFactory::createLine2D(xTextTarget, aPoints, &aVLineProperties); + } + } + } + } + + aPieLabelInfo.fValue = nVal; + aPieLabelInfo.bMovementAllowed = bMovementAllowed; + aPieLabelInfo.bMoved = false; + aPieLabelInfo.xTextTarget = xTextTarget; + aPieLabelInfo.bShowLeaderLine = bShowLeaderLine && !rSeries.isLabelCustomPos(nPointIndex); + + m_aLabelInfoList.push_back(aPieLabelInfo); +} + +void PieChart::addSeries( std::unique_ptr pSeries, sal_Int32 /* zSlot */, sal_Int32 /* xSlot */, sal_Int32 /* ySlot */ ) +{ + VSeriesPlotter::addSeries( std::move(pSeries), 0, -1, 0 ); +} + +double PieChart::getMinimumX() +{ + return 0.5; +} +double PieChart::getMaxOffset() +{ + if (!std::isnan(m_fMaxOffset)) + // Value already cached. Use it. + return m_fMaxOffset; + + m_fMaxOffset = 0.0; + if( m_aZSlots.empty() ) + return m_fMaxOffset; + if( m_aZSlots.front().empty() ) + return m_fMaxOffset; + + const std::vector< std::unique_ptr >& rSeriesList( m_aZSlots.front().front().m_aSeriesVector ); + if(rSeriesList.empty()) + return m_fMaxOffset; + + VDataSeries* pSeries = rSeriesList.front().get(); + uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() ); + if( !xSeriesProp.is() ) + return m_fMaxOffset; + + double fExplodePercentage=0.0; + xSeriesProp->getPropertyValue( "Offset") >>= fExplodePercentage; + if(fExplodePercentage>m_fMaxOffset) + m_fMaxOffset=fExplodePercentage; + + if(!m_bSizeExcludesLabelsAndExplodedSegments) + { + uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; + if( xSeriesProp->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList ) + { + for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;) + { + uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint(aAttributedDataPointIndexList[nN]) ); + if(xPointProp.is()) + { + fExplodePercentage=0.0; + xPointProp->getPropertyValue( "Offset") >>= fExplodePercentage; + if(fExplodePercentage>m_fMaxOffset) + m_fMaxOffset=fExplodePercentage; + } + } + } + } + return m_fMaxOffset; +} +double PieChart::getMaximumX() +{ + double fMaxOffset = getMaxOffset(); + if( !m_aZSlots.empty() && m_bUseRings) + return m_aZSlots.front().size()+0.5+fMaxOffset; + return 1.5+fMaxOffset; +} +double PieChart::getMinimumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ ) +{ + return 0.0; +} + +double PieChart::getMaximumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ ) +{ + return 1.0; +} + +bool PieChart::isExpandBorderToIncrementRhythm( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +bool PieChart::isExpandIfValuesCloseToBorder( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +bool PieChart::isExpandWideValuesToZero( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +bool PieChart::isExpandNarrowValuesTowardZero( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +bool PieChart::isSeparateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ ) +{ + return false; +} + +void PieChart::createShapes() +{ + ///a ZSlot is a vector< vector< VDataSeriesGroup > >. There is only one + ///ZSlot: m_aZSlots[0] which has a number of elements equal to the total + ///number of data series (in fact, even if m_aZSlots[0][i] is an object of + ///type `VDataSeriesGroup`, in the current implementation, there is only one + ///data series in each data series group). + if (m_aZSlots.empty()) + // No series to plot. + return; + + ///m_xLogicTarget is where the group of all data series shapes (e.g. a pie + ///slice) is added (xSeriesTarget); + + ///m_xFinalTarget is where the group of all text shapes (labels) is added + ///(xTextTarget). + + ///both have been already created and added to the same root shape + ///( a member of a VDiagram object); this initialization occurs in + ///`ChartView::impl_createDiagramAndContent`. + + OSL_ENSURE(m_xLogicTarget.is() && m_xFinalTarget.is(), "PieChart is not properly initialized."); + if (!m_xLogicTarget.is() || !m_xFinalTarget.is()) + return; + + ///the text labels should be always on top of the other series shapes + ///therefore create an own group for the texts to move them to front + ///(because the text group is created after the series group the texts are + ///displayed on top) + rtl::Reference xSeriesTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); + //check necessary here that different Y axis can not be stacked in the same group? ... hm? + + ///pay attention that the `m_bSwapXAndY` parameter used by the polar + ///plotting position helper is always set to true for pie/donut charts + ///(see PieChart::setScales). This fact causes that `createShapes` expects + ///that the radius axis scale is the one with index 0 and the angle axis + ///scale is the one with index 1. + + std::vector< VDataSeriesGroup >::iterator aXSlotIter = m_aZSlots.front().begin(); + const std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = m_aZSlots.front().end(); + + ///m_bUseRings == true if chart type is `donut`, == false if chart type is + ///`pie`; if the chart is of `donut` type we have as many rings as many data + ///series, else we have a single ring (a pie) representing the first data + ///series; + ///for what I can see the radius axis orientation is always reversed and + ///the angle axis orientation is always non-reversed; + ///the radius axis scale range is [0.5, number of rings + 0.5 + max_offset], + ///the angle axis scale range is [0, 1]. The max_offset parameter is used + ///for exploded pie chart and its value is 0.5. + + ///the `explodeable` ring is the first one except when the radius axis + ///orientation is reversed (always!?) and we are dealing with a donut: in + ///such a case the `explodeable` ring is the last one. + std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0; + if( m_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings ) + nExplodeableSlot = m_aZSlots.front().size()-1; + + m_aLabelInfoList.clear(); + m_fMaxOffset = std::numeric_limits::quiet_NaN(); + sal_Int32 n3DRelativeHeight = 100; + if ( (m_nDimension==3) && m_xChartTypeModel.is()) + { + try + { + uno::Any aAny = m_xChartTypeModel->getPropertyValue( "3DRelativeHeight" ); + aAny >>= n3DRelativeHeight; + } + catch (const uno::Exception&) { } + } + ///iterate over each xslot, that is on each data series (there is + ///only one data series in each data series group!); note that if the chart + ///type is a pie the loop iterates only over the first data series + ///(m_bUseRings||fSlotX<0.5) + for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); ++aXSlotIter, fSlotX+=1.0 ) + { + ShapeParam aParam; + + std::vector< std::unique_ptr >* pSeriesList = &(aXSlotIter->m_aSeriesVector); + if(pSeriesList->empty())//there should be only one series in each x slot + continue; + VDataSeries* pSeries = pSeriesList->front().get(); + if(!pSeries) + continue; + + bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor"); + + /// The angle degree offset is set by the same property of the + /// data series. + /// Counter-clockwise offset from the 3 o'clock position. + m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle(); + + ///iterate through all points to get the sum of all entries of + ///the current data series + sal_Int32 nPointIndex=0; + sal_Int32 nPointCount=pSeries->getTotalPointCount(); + for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ ) + { + double fY = pSeries->getYValue( nPointIndex ); + if(fY<0.0) + { + //@todo warn somehow that negative values are treated as positive + } + if( std::isnan(fY) ) + continue; + aParam.mfLogicYSum += fabs(fY); + } + + if (aParam.mfLogicYSum == 0.0) + // Total sum of all Y values in this series is zero. Skip the whole series. + continue; + + double fLogicYForNextPoint = 0.0; + ///iterate through all points to create shapes + for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ ) + { + double fLogicInnerRadius, fLogicOuterRadius; + + ///compute the maximum relative distance offset of the current slice + ///from the pie center + ///it is worth noting that after the first invocation the maximum + ///offset value is cached, so it is evaluated only once per each + ///call to `createShapes` + double fOffset = getMaxOffset(); + + ///compute the outer and the inner radius for the current ring slice + bool bIsVisible = m_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset ); + if( !bIsVisible ) + continue; + + aParam.mfDepth = getTransformedDepth() * (n3DRelativeHeight / 100.0); + + rtl::Reference xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget); + ///collect data point information (logic coordinates, style ): + double fLogicYValue = fabs(pSeries->getYValue( nPointIndex )); + if( std::isnan(fLogicYValue) ) + continue; + if(fLogicYValue==0.0)//@todo: continue also if the resolution is too small + continue; + double fLogicYPos = fLogicYForNextPoint; + fLogicYForNextPoint += fLogicYValue; + + uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex ); + + //iterate through all subsystems to create partial points + { + //logic values on angle axis: + double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum; + double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / aParam.mfLogicYSum; + + ///note that the explode percentage is set to the `Offset` + ///property of the current data series entry only for slices + ///belonging to the outer ring + aParam.mfExplodePercentage = 0.0; + bool bDoExplode = ( nExplodeableSlot == static_cast< std::vector< VDataSeriesGroup >::size_type >(fSlotX) ); + if(bDoExplode) try + { + xPointProperties->getPropertyValue( "Offset") >>= aParam.mfExplodePercentage; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + ///see notes for `PolarPlottingPositionHelper` methods + ///transform to unit circle: + aParam.mfUnitCircleWidthAngleDegree = m_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue ); + aParam.mfUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue ); + aParam.mfUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius ); + aParam.mfUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius ); + + ///create data point + aParam.mfLogicZ = -1.0; // For 3D pie chart label position + + // Do concentric explosion if it's a donut chart with more than one series + const bool bConcentricExplosion = m_bUseRings && (m_aZSlots.front().size() > 1); + rtl::Reference xPointShape = + createDataPoint( + xSeriesGroupShape_Shapes, xPointProperties, aParam, nPointCount, + bConcentricExplosion); + + ///point color: + if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is()) + { + xPointShape->setPropertyValue("FillColor", + uno::Any(m_xColorScheme->getColorByIndex( nPointIndex ))); + } + + + if(bHasFillColorMapping) + { + double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor"); + if(!std::isnan(nPropVal)) + { + xPointShape->setPropertyValue("FillColor", uno::Any(static_cast( nPropVal))); + } + } + + ///create label + createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam); + + if(!bDoExplode) + { + ShapeFactory::setShapeName( xPointShape + , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) ); + } + else try + { + ///enable dragging of outer segments + + double fAngle = aParam.mfUnitCircleStartAngleDegree + aParam.mfUnitCircleWidthAngleDegree/2.0; + double fMaxDeltaRadius = aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius; + drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ ); + drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius + fMaxDeltaRadius, aParam.mfLogicZ ); + + sal_Int32 nOffsetPercent( static_cast(aParam.mfExplodePercentage * 100.0) ); + + awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition( + aOrigin, m_xLogicTarget, m_nDimension ) ); + awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition( + aNewOrigin, m_xLogicTarget, m_nDimension ) ); + + //enable dragging of piesegments + OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT + , pSeries->getSeriesParticle() + , ObjectIdentifier::getPieSegmentDragMethodServiceName() + , ObjectIdentifier::createPieSegmentDragParameterString( + nOffsetPercent, aMinimumPosition, aMaximumPosition ) + ) ); + + ShapeFactory::setShapeName( xPointShape + , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + }//next series in x slot (next y slot) + }//next category + }//next x slot +} + +PieChart::PieLabelInfo::PieLabelInfo() + : fValue(0.0) + , bMovementAllowed(false), bMoved(false) + , bShowLeaderLine(false), pPrevious(nullptr) + , pNext(nullptr) +{ +} + +/** In case this label and the passed label overlap the routine moves this + * label in order to fix the issue. After the label position has been + * rearranged it is checked that the moved label is still inside the page + * document, if the test is positive the routine returns true else returns + * false. + */ +bool PieChart::PieLabelInfo::moveAwayFrom( const PieChart::PieLabelInfo* pFix, const awt::Size& rPageSize, bool bMoveHalfWay, bool bMoveClockwise ) +{ + //return true if the move was successful + if(!bMovementAllowed) + return false; + + const sal_Int32 nLabelDistanceX = rPageSize.Width/50; + const sal_Int32 nLabelDistanceY = rPageSize.Height/50; + + ///compute the rectangle representing the intersection of the label bounding + ///boxes (`aOverlap`). + ::basegfx::B2IRectangle aOverlap( lcl_getRect( xLabelGroupShape ) ); + aOverlap.intersect( lcl_getRect( pFix->xLabelGroupShape ) ); + if( aOverlap.isEmpty() ) + return true; + + //TODO: alternative move direction + + ///the label is shifted along the direction orthogonal to the vector + ///starting at the pie/donut center and ending at this label anchor + ///point; + + ///named `aTangentialDirection` the unit vector related to such a + ///direction, the magnitude of the shift along such a direction is + ///calculated in this way: if the horizontal component of + ///`aTangentialDirection` is greater than the vertical component, + ///the magnitude of the shift is equal to `aOverlap.Width` else to + ///`aOverlap.Height`; + basegfx::B2IVector aRadiusDirection = aFirstPosition - aOrigin; + aRadiusDirection.setLength(1.0); + basegfx::B2IVector aTangentialDirection( -aRadiusDirection.getY(), aRadiusDirection.getX() ); + bool bShiftHorizontal = abs(aTangentialDirection.getX()) > abs(aTangentialDirection.getY()); + sal_Int32 nShift = bShiftHorizontal ? static_cast(aOverlap.getWidth()) : static_cast(aOverlap.getHeight()); + ///the magnitude of the shift is also increased by 1/50-th of the width + ///or the height of the document page; + nShift += (bShiftHorizontal ? nLabelDistanceX : nLabelDistanceY); + ///in case the `bMoveHalfWay` parameter is true the magnitude of + ///the shift is halved. + if( bMoveHalfWay ) + nShift/=2; + ///in case the `bMoveClockwise` parameter is false the direction of + ///`aTangentialDirection` is reversed; + if(!bMoveClockwise) + nShift*=-1; + awt::Point aOldPos( xLabelGroupShape->getPosition() ); + basegfx::B2IVector aNewPos = basegfx::B2IVector( aOldPos.X, aOldPos.Y ) + nShift*aTangentialDirection; + + ///a final check is performed in order to be sure that the moved label + ///is still inside the page document; + awt::Point aNewAWTPos( aNewPos.getX(), aNewPos.getY() ); + if( !lcl_isInsidePage( aNewAWTPos, xLabelGroupShape->getSize(), rPageSize ) ) + return false; + + xLabelGroupShape->setPosition( aNewAWTPos ); + bMoved = true; + + return true; + + ///note that no further test is performed in order to check that the + ///overlap is really fixed: this result is surely achieved if the shift + ///would occur in the horizontal or vertical direction (since, in such a + ///direction, the magnitude of the shift would be greater than the length + ///of the overlap), but in general this is not true; + ///adding a constant term equal to 1/50-th of the width or the height of + ///the document page increases the probability of success, anyway it is + ///worth noting that the method can return true even if the overlap issue + ///is not (completely) fixed; +} + +void PieChart::resetLabelPositionsToPreviousState() +{ + for (auto const& labelInfo : m_aLabelInfoList) + labelInfo.xLabelGroupShape->setPosition(labelInfo.aPreviousPosition); +} + +bool PieChart::detectLabelOverlapsAndMove( const awt::Size& rPageSize ) +{ + ///the routine tries to individuate a chain of overlapping labels and + ///assigns the first and the last of them to `pFirstBorder` and + ///`pSecondBorder`; + ///this result is achieved by performing two consecutive while loop. + + ///find borders of a group of overlapping labels + + ///a first while loop is started on the collection of `PieLabelInfo` objects; + ///the bounding box of each label is checked for overlap against the bounding + ///box of the previous and of the next label; + ///when an overlap is found `bOverlapFound` is set to true, however the + ///iteration is break only if the overlap occurs against only the next label + ///and not against the previous label: so we exit from the loop whenever an + ///overlap occurs except when the loop initial label overlaps with the + ///previous one; + bool bOverlapFound = false; + PieLabelInfo* pStart = &(*(m_aLabelInfoList.rbegin())); + PieLabelInfo* pFirstBorder = nullptr; + PieLabelInfo* pSecondBorder = nullptr; + PieLabelInfo* pCurrent = pStart; + do + { + ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) ); + ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap ); + aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) ); + aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) ); + + bool bPreviousOverlap = !aPreviousOverlap.isEmpty(); + bool bNextOverlap = !aNextOverlap.isEmpty(); + if( bPreviousOverlap || bNextOverlap ) + bOverlapFound = true; + if( !bPreviousOverlap && bNextOverlap ) + { + pFirstBorder = pCurrent; + break; + } + pCurrent = pCurrent->pNext; + } + while( pCurrent != pStart ); + + if( !bOverlapFound ) + return false; + + ///in case we found a label (`pFirstBorder`) which overlaps with the next + ///label and not with the previous label a second while loop is started with + ///`pFirstBorder` as initial label; one more time the bounding box of each + ///label is checked for overlap against the bounding box of the previous and + ///of the next label, however this time we exit from the loop only if the + ///current label overlaps with the previous one but does not with the next + ///one (the opposite of what is required in the former loop); + ///in case such a label is found it is assigned to `pSecondBorder` and the + ///iteration is stopped; so in case there is a chain of overlapping labels + ///we end up having the first label of the chain pointed by `pFirstBorder` + ///and the last label of the chain pointed by `pSecondBorder`; + if( pFirstBorder ) + { + pCurrent = pFirstBorder; + do + { + ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) ); + ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap ); + aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) ); + aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) ); + + if( !aPreviousOverlap.isEmpty() && aNextOverlap.isEmpty() ) + { + pSecondBorder = pCurrent; + break; + } + pCurrent = pCurrent->pNext; + } + while( pCurrent != pFirstBorder ); + } + + ///when two labels satisfying the required conditions are not found + ///(`pFirstBorder == 0 || pSecondBorder == 0`) but still an overlap occurs + ///(`bOverlapFound == true`) we are in the situation where each label + ///overlaps with both the previous and the next one; so `pFirstBorder` is + ///set to point to the last `PieLabelInfo` object in the collection and + ///`pSecondBorder` is set to point to the first one; + if( !pFirstBorder || !pSecondBorder ) + { + pFirstBorder = &(*(m_aLabelInfoList.rbegin())); + pSecondBorder = &(*(m_aLabelInfoList.begin())); + } + + ///the total number of labels that made up the chain is calculated and used + ///for getting a pointer to the central label (`pCenter`); + PieLabelInfo* pCenter = pFirstBorder; + sal_Int32 nOverlapGroupCount = 1; + for( pCurrent = pFirstBorder ;pCurrent != pSecondBorder; pCurrent = pCurrent->pNext ) + nOverlapGroupCount++; + sal_Int32 nCenterPos = nOverlapGroupCount/2; + bool bSingleCenter = nOverlapGroupCount%2 != 0; + if( bSingleCenter ) + nCenterPos++; + if(nCenterPos>1) + { + pCurrent = pFirstBorder; + while( --nCenterPos ) + pCurrent = pCurrent->pNext; + pCenter = pCurrent; + } + + ///the current position of each label in the collection is saved in + ///`PieLabelInfo.aPreviousPosition`, so that it is possible to undo the label + ///move action if it is needed; the undo action is provided by the + ///`PieChart::resetLabelPositionsToPreviousState` method. + pCurrent = pStart; + do + { + pCurrent->aPreviousPosition = pCurrent->xLabelGroupShape->getPosition(); + pCurrent = pCurrent->pNext; + } + while( pCurrent != pStart ); + + ///the `PieChart::tryMoveLabels` method is invoked with + ///`rbAlternativeMoveDirection` boolean parameter set to false, such a method + ///tries to remove all overlaps that occur in the list of labels going from + ///`pFirstBorder` to `pSecondBorder`; + ///if the `PieChart::tryMoveLabels` returns true no further action is + ///performed, however it is worth noting that it does not mean that all + ///overlap issues have been surely fixed, but only that all moved labels are + ///at least completely inside the page document; + ///when `PieChart::tryMoveLabels` returns false, it means that the attempt + ///to fix one of the overlap issues caused that a label has been moved + ///(partially) outside the page document (anyway the `PieChart::tryMoveLabels` + ///method takes care to restore the position of all labels to their initial + ///position, and to set the `rbAlternativeMoveDirection` in/out parameter to + ///true); in such a case a second invocation of `PieChart::tryMoveLabels` is + ///performed (and this time the `rbAlternativeMoveDirection` boolean + ///parameter is true) and independently by what the `PieChart::tryMoveLabels` + ///method returns no further action is performed; + ///(see notes for `PieChart::tryMoveLabels`); + bool bAlternativeMoveDirection = false; + if( !tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ) ) + tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ); + + ///in both cases (one or two invocations of `PieChart::tryMoveLabels`) the + ///`detectLabelOverlapsAndMove` method ends returning true. + return true; +} + + +/** Try to remove all overlaps that occur in the list of labels going from + * `pFirstBorder` to `pSecondBorder` + */ +bool PieChart::tryMoveLabels( PieLabelInfo const * pFirstBorder, PieLabelInfo const * pSecondBorder + , PieLabelInfo* pCenter + , bool bSingleCenter, bool& rbAlternativeMoveDirection, const awt::Size& rPageSize ) +{ + + PieLabelInfo* p1 = bSingleCenter ? pCenter->pPrevious : pCenter; + PieLabelInfo* p2 = pCenter->pNext; + //return true when successful + + bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle(); + + ///two loops are performed simultaneously: the outer loop iterates on + ///`PieLabelInfo` objects in the list starting from the central element + ///(`pCenter`) and moving forward until the last element (`pSecondBorder`); + ///the inner loop starts from the previous element of `pCenter` and moves + ///forward until the current `PieLabelInfo` object of the outer loop is + ///reached + PieLabelInfo* pCurrent = nullptr; + for( pCurrent = p2 ;pCurrent->pPrevious != pSecondBorder; pCurrent = pCurrent->pNext ) + { + PieLabelInfo* pFix = nullptr; + for( pFix = p2->pPrevious ;pFix != pCurrent; pFix = pFix->pNext ) + { + ///on the current `PieLabelInfo` object of the outer loop the + ///`moveAwayFrom` method is invoked by passing the current + ///`PieLabelInfo` object of the inner loop as argument. + + ///so each label going from the central one to the last one is + ///checked for overlapping against all previous labels (that comes + ///after the central label) and in case the overlap occurs the + ///`moveAwayFrom` method tries to fix the issue; + ///if `moveAwayFrom` returns true (pay attention: that does not + ///mean that the overlap issue has been surely fixed but only that + ///the moved label is at least completely inside the page document: + ///see notes on `PieChart::PieLabelInfo::moveAwayFrom`), the inner + ///loop starts a new iteration else the `rbAlternativeMoveDirection` + ///boolean parameter is tested: if it is false the parameter is set + ///to true, the position of all labels is restored to the initial + ///one (through the `PieChart::resetLabelPositionsToPreviousState` + ///method) and the method ends by returning false, else the inner + ///loop starts a new iteration step; + ///so when `rbAlternativeMoveDirection` is true the method goes on + ///trying to fix left overlap issues even if the last `moveAwayFrom` + ///invocation has moved a label in a position that it is not + ///completely inside the page document + + if( !pCurrent->moveAwayFrom( pFix, rPageSize, !bSingleCenter && pCurrent == p2, !bLabelOrderIsAntiClockWise ) ) + { + if( !rbAlternativeMoveDirection ) + { + rbAlternativeMoveDirection = true; + resetLabelPositionsToPreviousState(); + return false; + } + } + } + } + + ///if the method does not return before ending the first pair of loops, + ///a second pair of simultaneous loops is performed in the opposite + ///direction (respect with the previous case): the outer loop iterates on + ///`PieLabelInfo` objects in the list starting from the central element + ///(`pCenter`) and moving backward until the first element (`pFirstBorder`); + ///the inner loop starts from the next element of `pCenter` and moves + ///backward until the current `PieLabelInfo` object of the outer loop is + ///reached + + ///like in the previous case on the current `PieLabelInfo` object of + ///the outer loop the `moveAwayFrom` method is invoked by passing + ///the current `PieLabelInfo` object of the inner loop as argument + + ///so each label going from the central one to the first one is checked for + ///overlapping on all subsequent labels (that come before the central label) + ///and in case the overlap occurs the `moveAwayFrom` method tries to fix + ///the issue. The subsequent actions performed after the invocation + ///`moveAwayFrom` are the same detailed above for the first pair of loops + + for( pCurrent = p1 ;pCurrent->pNext != pFirstBorder; pCurrent = pCurrent->pPrevious ) + { + PieLabelInfo* pFix = nullptr; + for( pFix = p2->pNext ;pFix != pCurrent; pFix = pFix->pPrevious ) + { + if( !pCurrent->moveAwayFrom( pFix, rPageSize, false, bLabelOrderIsAntiClockWise ) ) + { + if( !rbAlternativeMoveDirection ) + { + rbAlternativeMoveDirection = true; + resetLabelPositionsToPreviousState(); + return false; + } + } + } + } + return true; +} + +void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSize ) +{ + ///this method is invoked by `ChartView::impl_createDiagramAndContent` for + ///pie and donut charts after text label creation; + ///it tries to rearrange labels only when the label placement type is + ///`AVOID_OVERLAP`. + // no need to do anything when we only have one label + if (m_aLabelInfoList.size() < 2) + return; + + ///check whether there are any labels that should be moved + bool bMoveableFound = false; + for (auto const& labelInfo : m_aLabelInfoList) + { + if(labelInfo.bMovementAllowed) + { + bMoveableFound = true; + break; + } + } + if(!bMoveableFound) + return; + + double fPageDiagonaleLength = std::hypot(rPageSize.Width, rPageSize.Height); + if( fPageDiagonaleLength == 0.0 ) + return; + + ///initialize next and previous member of `PieLabelInfo` objects + auto aIt1 = m_aLabelInfoList.begin(); + auto aEnd = m_aLabelInfoList.end(); + std::vector< PieLabelInfo >::iterator aIt2 = aIt1; + aIt1->pPrevious = &(*(m_aLabelInfoList.rbegin())); + ++aIt2; + for( ;aIt2!=aEnd; ++aIt1, ++aIt2 ) + { + PieLabelInfo& rInfo1( *aIt1 ); + PieLabelInfo& rInfo2( *aIt2 ); + rInfo1.pNext = &rInfo2; + rInfo2.pPrevious = &rInfo1; + } + aIt1->pNext = &(*(m_aLabelInfoList.begin())); + + ///detect overlaps and move + sal_Int32 nMaxIterations = 50; + while( detectLabelOverlapsAndMove( rPageSize ) && nMaxIterations > 0 ) + nMaxIterations--; + + ///create connection lines for the moved labels + VLineProperties aVLineProperties; + for (auto const& labelInfo : m_aLabelInfoList) + { + if( labelInfo.bMoved && labelInfo.bShowLeaderLine ) + { + sal_Int32 nX1 = labelInfo.aOuterPosition.getX(); + sal_Int32 nY1 = labelInfo.aOuterPosition.getY(); + sal_Int32 nX2 = nX1; + sal_Int32 nY2 = nY1; + ::basegfx::B2IRectangle aRect( lcl_getRect( labelInfo.xLabelGroupShape ) ); + if( nX1 < aRect.getMinX() ) + nX2 = aRect.getMinX(); + else if( nX1 > aRect.getMaxX() ) + nX2 = aRect.getMaxX(); + + if( nY1 < aRect.getMinY() ) + nY2 = aRect.getMinY(); + else if( nY1 > aRect.getMaxY() ) + nY2 = aRect.getMaxY(); + + //when the line is very short compared to the page size don't create one + ::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2); + if( (aLength.getLength()/fPageDiagonaleLength) < 0.01 ) + continue; + + drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } }; + + if( labelInfo.xTextShape.is() ) + { + sal_Int32 nColor = 0; + labelInfo.xTextShape->SvxShape::getPropertyValue("CharColor") >>= nColor; + if( nColor != -1 )//automatic font color does not work for lines -> fallback to black + aVLineProperties.Color <<= nColor; + } + ShapeFactory::createLine2D( labelInfo.xTextTarget, aPoints, &aVLineProperties ); + } + } +} + + +/** Handle the placement of the label in the best fit case: + * the routine try to place the label inside the related pie slice, + * in case of success it returns true else returns false. + * + * Notation: + * C: the pie center + * s: the bisector ray of the current pie slice + * alpha: the angle between the horizontal axis and the bisector ray s + * N: the vertex of the label b.b. which is nearest to C + * F: the vertex of the label b.b. not adjacent to N; F lies on the pie border + * P, Q: the intersection points between the label b.b. and the bisector ray s; + * P is the one at minimum distance respect with C + * e: the edge of the label b.b. where P lies (the nearest edge to C) + * M: the vertex of e that is not N + * G: the vertex of the label b.b. which is adjacent to N and that is not M + * beta: the angle MPF + * theta: the angle CPF + * + * + * | + * | /s + * | / + * | / + * | G _________________________/____________________________ F + * | | /Q ..| + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / d. . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . . | + * | | / . \ beta . | + * | |__________/._\___|_______.____________________________| + * | N /P / . M + * | /___/theta . + * | / . + * | / . r + * | / . + * | / . + * | / . + * | / . + * | / . + * | / . + * | / . + * | / . + * | /\. alpha + * __|/__|_____________________________________________________________ + * |C + * | + * + * + * When alpha = 45k (k integer) s crosses the label b.b. at N exactly. + * In such a case the nearest edge e is defined as the edge having N as the + * start vertex and that is covered in the counterclockwise direction when + * we move from N to the adjacent vertex. + * + * The nearest vertex N is: + * 1. the bottom left vertex when 0 < alpha < 90 + * 2. the bottom right vertex when 90 < alpha < 180 + * 3. the top right vertex when 180 < alpha < 270 + * 4. the top left vertex when 270 < alpha < 360. + * + * The nearest edge e is: + * 1. the left edge when −45 < alpha < 45 + * 2. the bottom edge when 45 < alpha <135 + * 3. the right edge when 135 < alpha < 225 + * 4. the top edge when 225 < alpha < 315. + * + **/ +bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLabelInfo const & rPieLabelInfo) +{ + SAL_INFO( "chart2.pie.label.bestfit.inside", + "** PieChart::performLabelBestFitInnerPlacement invoked **" ); + + // get pie slice properties + double fStartAngleDeg = NormAngle360(rShapeParam.mfUnitCircleStartAngleDegree); + double fWidthAngleDeg = rShapeParam.mfUnitCircleWidthAngleDegree; + double fHalfWidthAngleDeg = fWidthAngleDeg / 2.0; + double fBisectingRayAngleDeg = NormAngle360(fStartAngleDeg + fHalfWidthAngleDeg); + + // get the middle point of the arc representing the pie slice border + double fLogicZ = rShapeParam.mfLogicZ + 1.0; + awt::Point aMiddleArcPoint = PlottingPositionHelper::transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( + fBisectingRayAngleDeg, + rShapeParam.mfUnitCircleOuterRadius, + fLogicZ ), + m_xLogicTarget, m_nDimension ); + + // compute the pie radius + basegfx::B2IVector aPieCenter = rPieLabelInfo.aOrigin; + basegfx::B2IVector aRadiusVector( + aMiddleArcPoint.X - aPieCenter.getX(), + aMiddleArcPoint.Y - aPieCenter.getY() ); + double fSquaredPieRadius = aRadiusVector.scalar(aRadiusVector); + double fPieRadius = sqrt( fSquaredPieRadius ); + + // the bb is moved as much as possible near to the border of the pie, + // anyway a small offset from the border is present (0.025 * pie radius) + const double fPieBorderOffset = 0.025; + fPieRadius = fPieRadius - fPieRadius * fPieBorderOffset; + + SAL_INFO( "chart2.pie.label.bestfit.inside", + " pie sector:" ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " start angle = " << fStartAngleDeg ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " angle width = " << fWidthAngleDeg ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " bisecting ray angle = " << fBisectingRayAngleDeg ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " pie radius = " << fPieRadius ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " pie center = " << rPieLabelInfo.aOrigin ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " middle arc point = (" << aMiddleArcPoint.X << "," + << aMiddleArcPoint.Y << ")" ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " label bounding box:" ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " old anchor point = " << rPieLabelInfo.aFirstPosition ); + + + if( fPieRadius == 0.0 ) + return false; + + // get label b.b. width and height + ::basegfx::B2IRectangle aBb( lcl_getRect( rPieLabelInfo.xLabelGroupShape ) ); + double fLabelWidth = aBb.getWidth(); + double fLabelHeight = aBb.getHeight(); + + // -45 <= fAlphaDeg < 315 + double fAlphaDeg = NormAngle360(fBisectingRayAngleDeg + 45) - 45; + double fAlphaRad = basegfx::deg2rad(fAlphaDeg); + + // compute nearest edge index + // 0 left + // 1 bottom + // 2 right + // 3 top + int nSectorIndex = floor( (fAlphaDeg + 45) / 45.0 ); + int nNearestEdgeIndex = nSectorIndex / 2; + + // compute lengths of the nearest edge and of the orthogonal edges + double fNearestEdgeLength = fLabelWidth; + double fOrthogonalEdgeLength = fLabelHeight; + basegfx::Axis2D eAxis = basegfx::Axis2D::X; + basegfx::Axis2D eOrthogonalAxis = basegfx::Axis2D::Y; + if( nNearestEdgeIndex % 2 == 0 ) // nearest edge is vertical + { + fNearestEdgeLength = fLabelHeight; + fOrthogonalEdgeLength = fLabelWidth; + eAxis = basegfx::Axis2D::Y; + eOrthogonalAxis = basegfx::Axis2D::X; + } + + // compute the distance between N and P + // such a distance is piece wise linear respect with alpha: + // given 45k <= alpha < 45(k+1) we have + // when k is even: d(N,P) = (length(e) / 2) * (1 - (alpha - 45k)/45) + // when k is odd: d(N,P) = (length(e) / 2) * (1 - (45(k+1) - alpha)/45) + int nIndex = nSectorIndex -1; // nIndex = -1...6 + double fIndexMod2 = (nIndex + 8) % 2; // fIndexMod2 must be non negative + double fSgn = 2.0 * (fIndexMod2 - 0.5); // 0 -> -1, 1 -> 1 + double fDistanceNP = (fNearestEdgeLength / 2.0) * (1 + fSgn * ((fAlphaDeg - 45 * (nIndex + fIndexMod2)) / 45.0)); + double fDistancePM = fNearestEdgeLength - fDistanceNP; + + // compute the length of the diagonal vector d, + // that is the distance between P and F + double fDistancePF = std::hypot(fDistancePM, fOrthogonalEdgeLength); + + SAL_INFO( "chart2.pie.label.bestfit.inside", + " width = " << fLabelWidth ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " height = " << fLabelHeight ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " nearest edge index = " << nNearestEdgeIndex ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " alpha = " << fAlphaDeg ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " distance(N,P) = " << fDistanceNP ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " nIndex = " << nIndex ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " fIndexMod2 = " << fIndexMod2 ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " fSgn = " << fSgn ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " distance(P,F) = " << fDistancePF ); + + + // we check that the condition length(d) <= pie radius holds + if (fDistancePF > fPieRadius) + { + return false; + } + + // compute beta: the angle of the diagonal vector d, + // that is, the angle in P respect with the triangle PMF; + // since both arguments are non negative the returned value is in [0, PI/2] + double fBetaRad = atan2( fOrthogonalEdgeLength, fDistancePM ); + + // compute the theta angle, that is the angle in P + // respect with the triangle CFP; + // when the second intersection edge is opposite to the nearest edge, + // theta depends on alpha and beta according to the following relation: + // theta = f(alpha, beta) = s * alpha + 90 * (1 - s * i) + beta + // where i is the nearest edge index and s is the sign of (alpha' - 45), + // with alpha' = (alpha + 45) mod 90; + // when the second intersection edge is adjacent to the nearest edge, + // we have theta = 360 - f(alpha, beta); + // note that in the former case 0 <= f(alpha, beta) <= 180, + // whilst in the latter case 180 <= f(alpha, beta) <= 360; + double fAlphaMod90 = fmod( fAlphaDeg + 45, 90.0 ) - 45; + double fSign = fAlphaMod90 == 0.0 + ? 0.0 + : ( fAlphaMod90 < 0 ) ? -1.0 : 1.0; + double fThetaRad = fSign * fAlphaRad + M_PI_2 * (1 - fSign * nNearestEdgeIndex) + fBetaRad; + if( fThetaRad > M_PI ) + { + fThetaRad = 2 * M_PI - fThetaRad; + } + + // compute the length of the positional vector, + // that is the distance between C and P + double fDistanceCP; + // when the bisector ray intersects the b.b. in F we have theta mod 180 == 0 + if( fmod(fThetaRad, M_PI) == 0.0 ) + { + fDistanceCP = fPieRadius - fDistancePF; + } + else // general case + { + // we can compute d(C,P) by applying some trigonometric formula to + // the triangle CFP : we know length(d) and length(r) = r and we have + // computed the angle in P (theta); so named delta the angle in C and + // gamma the angle in F, by the relation: + // + // r d(P,F) d(C,P) + // --------- = --------- = --------- + // sin theta sin delta sin gamma + // + // we get the wanted distance + double fSinTheta = sin( fThetaRad ); + double fSinDelta = fDistancePF * fSinTheta / fPieRadius; + double fDeltaRad = asin( fSinDelta ); + double fGammaRad = M_PI - (fThetaRad + fDeltaRad); + double fSinGamma = sin( fGammaRad ); + fDistanceCP = fPieRadius * fSinGamma / fSinTheta; + } + + // define the positional vector + basegfx::B2DVector aPositionalVector( cos(fAlphaRad), sin(fAlphaRad) ); + aPositionalVector.setLength(fDistanceCP); + + // we define a direction vector in order to know + // in which quadrant we are working + basegfx::B2DVector aDirection(1.0, 1.0); + if( 90 <= fBisectingRayAngleDeg && fBisectingRayAngleDeg < 270 ) + { + aDirection.setX(-1.0); + } + if( fBisectingRayAngleDeg >= 180 ) + { + aDirection.setY(-1.0); + } + + // compute vertices N, M and G respect with pie center C + basegfx::B2DVector aNearestVertex(aPositionalVector); + aNearestVertex.set(eAxis, aNearestVertex.get(eAxis) - aDirection.get(eAxis) * fDistanceNP); + basegfx::B2DVector aVertexM(aNearestVertex); + aVertexM.set(eAxis, aVertexM.get(eAxis) + aDirection.get(eAxis) * fNearestEdgeLength); + basegfx::B2DVector aVertexG(aNearestVertex); + aVertexG.set(eOrthogonalAxis, aVertexG.get(eOrthogonalAxis) + aDirection.get(eOrthogonalAxis) * fOrthogonalEdgeLength); + + SAL_INFO( "chart2.pie.label.bestfit.inside", + " beta = " << basegfx::rad2deg(fBetaRad) ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " theta = " << basegfx::rad2deg(fThetaRad) ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " fAlphaMod90 = " << fAlphaMod90 ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " fSign = " << fSign ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " distance(C,P) = " << fDistanceCP ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " direction vector = " << aDirection ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " N = " << aNearestVertex ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " M = " << aVertexM ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " G = " << aVertexG ); + + // in order to be able to place the label inside the pie slice we need + // to check that each angle between s and the ray starting from C and + // passing through a b.b. vertex is less than half width of the pie slice; + // when the nearest edge e crosses a Cartesian axis it is sufficient + // to test only the vertices belonging to e, else we need to test + // the 2 vertices that aren't either N or F. Note that if a b.b. edge + // crosses a Cartesian axis then it is the nearest edge to C + + // check the angle between CP and CM + double fAngleRad = aPositionalVector.angle(aVertexM); + double fAngleDeg = NormAngle360(basegfx::rad2deg(fAngleRad)); + if( fAngleDeg > 180 ) // in case the wrong angle has been computed + fAngleDeg = 360 - fAngleDeg; + SAL_INFO( "chart2.pie.label.bestfit.inside", + " angle between CP and CM: " << fAngleDeg ); + if( fAngleDeg > fHalfWidthAngleDeg ) + { + return false; + } + + if( ( aNearestVertex.get(eAxis) >= 0 && aVertexM.get(eAxis) <= 0 ) + || ( aNearestVertex.get(eAxis) <= 0 && aVertexM.get(eAxis) >= 0 ) ) + { + // check the angle between CP and CN + fAngleRad = aPositionalVector.angle(aNearestVertex); + fAngleDeg = NormAngle360(basegfx::rad2deg(fAngleRad)); + if( fAngleDeg > 180 ) // in case the wrong angle has been computed + fAngleDeg = 360 - fAngleDeg; + SAL_INFO( "chart2.pie.label.bestfit.inside", + " angle between CP and CN: " << fAngleDeg ); + if( fAngleDeg > fHalfWidthAngleDeg ) + { + return false; + } + } + else + { + // check the angle between CP and CG + fAngleRad = aPositionalVector.angle(aVertexG); + fAngleDeg = NormAngle360(basegfx::rad2deg(fAngleRad)); + if( fAngleDeg > 180 ) // in case the wrong angle has been computed + fAngleDeg = 360 - fAngleDeg; + SAL_INFO( "chart2.pie.label.bestfit.inside", + " angle between CP and CG: " << fAngleDeg ); + if( fAngleDeg > fHalfWidthAngleDeg ) + { + return false; + } + } + + // compute the b.b. center respect with the pie center + basegfx::B2DVector aBBCenter(aNearestVertex); + aBBCenter.set(eAxis, aBBCenter.get(eAxis) + aDirection.get(eAxis) * fNearestEdgeLength / 2); + aBBCenter.set(eOrthogonalAxis, aBBCenter.get(eOrthogonalAxis) + aDirection.get(eOrthogonalAxis) * fOrthogonalEdgeLength / 2); + + // compute the b.b. anchor point + basegfx::B2IVector aNewAnchorPoint = aPieCenter; + aNewAnchorPoint.setX(aNewAnchorPoint.getX() + floor(aBBCenter.getX())); + aNewAnchorPoint.setY(aNewAnchorPoint.getY() - floor(aBBCenter.getY())); // the Y axis on the screen points downward + + // compute the translation vector for moving the label from the current + // screen position to the new one + basegfx::B2IVector aTranslationVector = aNewAnchorPoint - rPieLabelInfo.aFirstPosition; + + // compute the new screen position and move the label + // XShape::getPosition returns the top left vertex of the b.b. of the shape + awt::Point aOldPos( rPieLabelInfo.xLabelGroupShape->getPosition() ); + awt::Point aNewPos( aOldPos.X + aTranslationVector.getX(), + aOldPos.Y + aTranslationVector.getY() ); + rPieLabelInfo.xLabelGroupShape->setPosition(aNewPos); + + SAL_INFO( "chart2.pie.label.bestfit.inside", + " center = " << aBBCenter ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " new anchor point = " << aNewAnchorPoint ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " translation vector = " << aTranslationVector ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " old position = (" << aOldPos.X << "," << aOldPos.Y << ")" ); + SAL_INFO( "chart2.pie.label.bestfit.inside", + " new position = (" << aNewPos.X << "," << aNewPos.Y << ")" ); + + return true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx new file mode 100644 index 000000000..9a5b7fb4c --- /dev/null +++ b/chart2/source/view/charttypes/PieChart.hxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace chart +{ +class PiePositionHelper; + +class PieChart : public VSeriesPlotter +{ + struct ShapeParam; + +public: + PieChart() = delete; + + PieChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount, bool bExcludingPositioning ); + virtual ~PieChart() override; + + /** This method creates all shapes needed for representing the pie chart. + */ + virtual void createShapes() override; + virtual void rearrangeLabelToAvoidOverlapIfRequested( const css::awt::Size& rPageSize ) override; + + virtual void setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) override; + virtual void addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) override; + + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const override; + virtual bool shouldSnapRectToUsedArea() override; + + //MinimumAndMaximumSupplier + virtual double getMinimumX() override; + virtual double getMaximumX() override; + virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + + virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) override; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + +private: //methods + rtl::Reference + createDataPoint( + const rtl::Reference& xTarget, + const css::uno::Reference& xObjectProperties, + const ShapeParam& rParam, + const sal_Int32 nPointCount, + const bool bConcentricExplosion); + + /** This method creates a text shape for a label of a data point. + * + * @param xTextTarget + * where to append the new created text shape. + * @param rSeries + * the data series, the data point belongs to. + * @param nPointIndex + * the index of the data point the label is related to. + * @param rParam + * ShapeParam object. + */ + void createTextLabelShape( + const rtl::Reference& xTextTarget, + VDataSeries& rSeries, sal_Int32 nPointIndex, ShapeParam& rParam ); + + /** This method sets `m_fMaxOffset` to the maximum `Offset` property and + * returns it. There is a `Offset` property for each entry in a data + * series, moreover there exists a shared `Offset` property attached to + * the whole data series. The `Offset` property represents the + * relative distance offset of a slice from the pie center. + * The shared property is used for exploded pie chart, while the property + * attached to single data series entries is used for manual dragging of + * a slice. + * `m_fMaxOffset` is used by `PiePositionHelper::getInnerAndOuterRadius`. + * Note that only the `Offset` properties of the first (x slot) data series + * and its entries are utilized for computing the maximum offset. + */ + double getMaxOffset(); + bool detectLabelOverlapsAndMove(const css::awt::Size& rPageSize);//returns true when there might be more to do + void resetLabelPositionsToPreviousState(); +struct PieLabelInfo; + bool tryMoveLabels( PieLabelInfo const * pFirstBorder, PieLabelInfo const * pSecondBorder + , PieLabelInfo* pCenter, bool bSingleCenter, bool& rbAlternativeMoveDirection + , const css::awt::Size& rPageSize ); + + bool performLabelBestFitInnerPlacement( ShapeParam& rShapeParam + , PieLabelInfo const & rPieLabelInfo ); + +private: //member + std::unique_ptr + m_pPosHelper; + bool m_bUseRings; + bool m_bSizeExcludesLabelsAndExplodedSegments; + + struct PieLabelInfo + { + PieLabelInfo(); + bool moveAwayFrom( const PieLabelInfo* pFix, const css::awt::Size& rPageSize + , bool bMoveHalfWay, bool bMoveClockwise ); + + rtl::Reference< SvxShapeText > xTextShape; + rtl::Reference< SvxShapeGroupAnyD > xLabelGroupShape; + ::basegfx::B2IVector aFirstPosition; + ::basegfx::B2IVector aOuterPosition; + ::basegfx::B2IVector aOrigin; + double fValue; + bool bMovementAllowed; + bool bMoved; + bool bShowLeaderLine; + rtl::Reference xTextTarget; + PieLabelInfo* pPrevious; + PieLabelInfo* pNext; + css::awt::Point aPreviousPosition; + }; + + std::vector< PieLabelInfo > m_aLabelInfoList; + + double m_fMaxOffset; /// cached max offset value (init'ed to NaN) +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx new file mode 100644 index 000000000..2aac96929 --- /dev/null +++ b/chart2/source/view/charttypes/Splines.cxx @@ -0,0 +1,872 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "Splines.hxx" +#include +#include + +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +namespace +{ + +typedef std::pair< double, double > tPointType; +typedef std::vector< tPointType > tPointVecType; +typedef tPointVecType::size_type lcl_tSizeType; + +class lcl_SplineCalculation +{ +public: + /** @descr creates an object that calculates cubic splines on construction + + @param rSortedPoints the points for which splines shall be calculated, they need to be sorted in x values + @param fY1FirstDerivation the resulting spline should have the first + derivation equal to this value at the x-value of the first point + of rSortedPoints. If fY1FirstDerivation is set to infinity, a natural + spline is calculated. + @param fYnFirstDerivation the resulting spline should have the first + derivation equal to this value at the x-value of the last point + of rSortedPoints + */ + lcl_SplineCalculation( tPointVecType && rSortedPoints, + double fY1FirstDerivation, + double fYnFirstDerivation ); + + /** @descr creates an object that calculates cubic splines on construction + for the special case of periodic cubic spline + + @param rSortedPoints the points for which splines shall be calculated, + they need to be sorted in x values. First and last y value must be equal + */ + explicit lcl_SplineCalculation( tPointVecType && rSortedPoints); + + /** @descr this function corresponds to the function splint in [1]. + + [1] Numerical Recipes in C, 2nd edition + William H. Press, et al., + Section 3.3, page 116 + */ + double GetInterpolatedValue( double x ); + +private: + /// a copy of the points given in the CTOR + tPointVecType m_aPoints; + + /// the result of the Calculate() method + std::vector< double > m_aSecDerivY; + + double m_fYp1; + double m_fYpN; + + // these values are cached for performance reasons + lcl_tSizeType m_nKLow; + lcl_tSizeType m_nKHigh; + double m_fLastInterpolatedValue; + + /** @descr this function corresponds to the function spline in [1]. + + [1] Numerical Recipes in C, 2nd edition + William H. Press, et al., + Section 3.3, page 115 + */ + void Calculate(); + + /** @descr this function corresponds to the algorithm 4.76 in [2] and + theorem 5.3.7 in [3] + + [2] Engeln-Müllges, Gisela: Numerik-Algorithmen: Verfahren, Beispiele, Anwendungen + Springer, Berlin; Auflage: 9., überarb. und erw. A. (8. Dezember 2004) + Section 4.10.2, page 175 + + [3] Hanrath, Wilhelm: Mathematik III / Numerik, Vorlesungsskript zur + Veranstaltung im WS 2007/2008 + Fachhochschule Aachen, 2009-09-19 + Numerik_01.pdf, downloaded 2011-04-19 via + http://www.fh-aachen.de/index.php?id=11424&no_cache=1&file=5016&uid=44191 + Section 5.3, page 129 + */ + void CalculatePeriodic(); +}; + +lcl_SplineCalculation::lcl_SplineCalculation( + tPointVecType && rSortedPoints, + double fY1FirstDerivation, + double fYnFirstDerivation ) + : m_aPoints( std::move(rSortedPoints) ), + m_fYp1( fY1FirstDerivation ), + m_fYpN( fYnFirstDerivation ), + m_nKLow( 0 ), + m_nKHigh( m_aPoints.size() - 1 ), + m_fLastInterpolatedValue(std::numeric_limits::infinity()) +{ + Calculate(); +} + +lcl_SplineCalculation::lcl_SplineCalculation( + tPointVecType && rSortedPoints) + : m_aPoints( std::move(rSortedPoints) ), + m_fYp1( 0.0 ), /*dummy*/ + m_fYpN( 0.0 ), /*dummy*/ + m_nKLow( 0 ), + m_nKHigh( m_aPoints.size() - 1 ), + m_fLastInterpolatedValue(std::numeric_limits::infinity()) +{ + CalculatePeriodic(); +} + +void lcl_SplineCalculation::Calculate() +{ + if( m_aPoints.size() <= 1 ) + return; + + // n is the last valid index to m_aPoints + const lcl_tSizeType n = m_aPoints.size() - 1; + std::vector< double > u( n ); + m_aSecDerivY.resize( n + 1, 0.0 ); + + if( std::isinf( m_fYp1 ) ) + { + // natural spline + m_aSecDerivY[ 0 ] = 0.0; + u[ 0 ] = 0.0; + } + else + { + m_aSecDerivY[ 0 ] = -0.5; + double xDiff = m_aPoints[ 1 ].first - m_aPoints[ 0 ].first; + u[ 0 ] = ( 3.0 / xDiff ) * + ((( m_aPoints[ 1 ].second - m_aPoints[ 0 ].second ) / xDiff ) - m_fYp1 ); + } + + for( lcl_tSizeType i = 1; i < n; ++i ) + { + tPointType + p_i = m_aPoints[ i ], + p_im1 = m_aPoints[ i - 1 ], + p_ip1 = m_aPoints[ i + 1 ]; + + double sig = ( p_i.first - p_im1.first ) / + ( p_ip1.first - p_im1.first ); + double p = sig * m_aSecDerivY[ i - 1 ] + 2.0; + + m_aSecDerivY[ i ] = ( sig - 1.0 ) / p; + u[ i ] = + ( ( p_ip1.second - p_i.second ) / + ( p_ip1.first - p_i.first ) ) - + ( ( p_i.second - p_im1.second ) / + ( p_i.first - p_im1.first ) ); + u[ i ] = + ( 6.0 * u[ i ] / ( p_ip1.first - p_im1.first ) + - sig * u[ i - 1 ] ) / p; + } + + // initialize to values for natural splines (used for m_fYpN equal to + // infinity) + double qn = 0.0; + double un = 0.0; + + if( ! std::isinf( m_fYpN ) ) + { + qn = 0.5; + double xDiff = m_aPoints[ n ].first - m_aPoints[ n - 1 ].first; + un = ( 3.0 / xDiff ) * + ( m_fYpN - ( m_aPoints[ n ].second - m_aPoints[ n - 1 ].second ) / xDiff ); + } + + m_aSecDerivY[ n ] = ( un - qn * u[ n - 1 ] ) / ( qn * m_aSecDerivY[ n - 1 ] + 1.0 ); + + // note: the algorithm in [1] iterates from n-1 to 0, but as size_type + // may be (usually is) an unsigned type, we can not write k >= 0, as this + // is always true. + for( lcl_tSizeType k = n; k > 0; --k ) + { + m_aSecDerivY[ k - 1 ] = (m_aSecDerivY[ k - 1 ] * m_aSecDerivY[ k ] ) + u[ k - 1 ]; + } +} + +void lcl_SplineCalculation::CalculatePeriodic() +{ + if( m_aPoints.size() <= 1 ) + return; + + // n is the last valid index to m_aPoints + const lcl_tSizeType n = m_aPoints.size() - 1; + + // u is used for vector f in A*c=f in [3], vector a in Ax=a in [2], + // vector z in Rtranspose z = a and Dr=z in [2] + std::vector< double > u( n + 1, 0.0 ); + + // used for vector c in A*c=f and vector x in Ax=a in [2] + m_aSecDerivY.resize( n + 1, 0.0 ); + + // diagonal of matrix A, used index 1 to n + std::vector< double > Adiag( n + 1, 0.0 ); + + // secondary diagonal of matrix A with index 1 to n-1 and upper right element in A[n] + std::vector< double > Aupper( n + 1, 0.0 ); + + // diagonal of matrix D in A=(R transpose)*D*R in [2], used index 1 to n + std::vector< double > Ddiag( n+1, 0.0 ); + + // right column of matrix R, used index 1 to n-2 + std::vector< double > Rright( n-1, 0.0 ); + + // secondary diagonal of matrix R, used index 1 to n-1 + std::vector< double > Rupper( n, 0.0 ); + + if (n<4) + { + if (n==3) + { // special handling of three polynomials, that are four points + double xDiff0 = m_aPoints[ 1 ].first - m_aPoints[ 0 ].first ; + double xDiff1 = m_aPoints[ 2 ].first - m_aPoints[ 1 ].first ; + double xDiff2 = m_aPoints[ 3 ].first - m_aPoints[ 2 ].first ; + double xDiff2p1 = xDiff2 + xDiff1; + double xDiff0p2 = xDiff0 + xDiff2; + double xDiff1p0 = xDiff1 + xDiff0; + double fFactor = 1.5 / (xDiff0*xDiff1 + xDiff1*xDiff2 + xDiff2*xDiff0); + double yDiff0 = (m_aPoints[ 1 ].second - m_aPoints[ 0 ].second) / xDiff0; + double yDiff1 = (m_aPoints[ 2 ].second - m_aPoints[ 1 ].second) / xDiff1; + double yDiff2 = (m_aPoints[ 0 ].second - m_aPoints[ 2 ].second) / xDiff2; + m_aSecDerivY[ 1 ] = fFactor * (yDiff1*xDiff2p1 - yDiff0*xDiff0p2); + m_aSecDerivY[ 2 ] = fFactor * (yDiff2*xDiff0p2 - yDiff1*xDiff1p0); + m_aSecDerivY[ 3 ] = fFactor * (yDiff0*xDiff1p0 - yDiff2*xDiff2p1); + m_aSecDerivY[ 0 ] = m_aSecDerivY[ 3 ]; + } + else if (n==2) + { + // special handling of two polynomials, that are three points + double xDiff0 = m_aPoints[ 1 ].first - m_aPoints[ 0 ].first; + double xDiff1 = m_aPoints[ 2 ].first - m_aPoints[ 1 ].first; + double fHelp = 3.0 * (m_aPoints[ 0 ].second - m_aPoints[ 1 ].second) / (xDiff0*xDiff1); + m_aSecDerivY[ 1 ] = fHelp ; + m_aSecDerivY[ 2 ] = -fHelp ; + m_aSecDerivY[ 0 ] = m_aSecDerivY[ 2 ] ; + } + else + { + // should be handled with natural spline, periodic not possible. + } + } + else + { + double xDiff_i =1.0; // values are dummy; + double xDiff_im1 =1.0; + double yDiff_i = 1.0; + double yDiff_im1 = 1.0; + // fill matrix A and fill right side vector u + for( lcl_tSizeType i=1; i=1; --i) + { + m_aSecDerivY[ i ] = u[ i ] - Rupper[ i ] * m_aSecDerivY[ i+1 ] - Rright[ i ] * m_aSecDerivY[ n ]; + } + // periodic + m_aSecDerivY[ 0 ] = m_aSecDerivY[ n ]; + } + + // adapt m_aSecDerivY for usage in GetInterpolatedValue() + for( lcl_tSizeType i = 0; i <= n ; ++i ) + { + m_aSecDerivY[ i ] *= 2.0; + } + +} + +double lcl_SplineCalculation::GetInterpolatedValue( double x ) +{ + OSL_PRECOND( ( m_aPoints[ 0 ].first <= x ) && + ( x <= m_aPoints[ m_aPoints.size() - 1 ].first ), + "Trying to extrapolate" ); + + const lcl_tSizeType n = m_aPoints.size() - 1; + if( x < m_fLastInterpolatedValue ) + { + m_nKLow = 0; + m_nKHigh = n; + + // calculate m_nKLow and m_nKHigh + // first initialization is done in CTOR + while( m_nKHigh - m_nKLow > 1 ) + { + lcl_tSizeType k = ( m_nKHigh + m_nKLow ) / 2; + if( m_aPoints[ k ].first > x ) + m_nKHigh = k; + else + m_nKLow = k; + } + } + else + { + while( ( m_nKHigh <= n ) && + ( m_aPoints[ m_nKHigh ].first < x ) ) + { + ++m_nKHigh; + ++m_nKLow; + } + OSL_ENSURE( m_nKHigh <= n, "Out of Bounds" ); + } + m_fLastInterpolatedValue = x; + + double h = m_aPoints[ m_nKHigh ].first - m_aPoints[ m_nKLow ].first; + OSL_ENSURE( h != 0, "Bad input to GetInterpolatedValue()" ); + + double a = ( m_aPoints[ m_nKHigh ].first - x ) / h; + double b = ( x - m_aPoints[ m_nKLow ].first ) / h; + + return ( a * m_aPoints[ m_nKLow ].second + + b * m_aPoints[ m_nKHigh ].second + + (( a*a*a - a ) * m_aSecDerivY[ m_nKLow ] + + ( b*b*b - b ) * m_aSecDerivY[ m_nKHigh ] ) * + ( h*h ) / 6.0 ); +} + +// helper methods for B-spline + +// Create parameter t_0 to t_n using the centripetal method with a power of 0.5 +bool createParameterT(const tPointVecType& rUniquePoints, double* t) +{ // precondition: no adjacent identical points + // postcondition: 0 = t_0 < t_1 < ... < t_n = 1 + bool bIsSuccessful = true; + const lcl_tSizeType n = rUniquePoints.size() - 1; + t[0]=0.0; + double fDenominator = 0.0; // initialized for summing up + for (lcl_tSizeType i=1; i<=n ; ++i) + { // 4th root(dx^2+dy^2) + double dx = rUniquePoints[i].first - rUniquePoints[i-1].first; + double dy = rUniquePoints[i].second - rUniquePoints[i-1].second; + if (dx == 0 && dy == 0) + { + bIsSuccessful = false; + break; + } + else + { + fDenominator += sqrt(std::hypot(dx, dy)); + } + } + if (fDenominator == 0.0) + { + bIsSuccessful = false; + } + if (bIsSuccessful) + { + for (lcl_tSizeType j=1; j<=n ; ++j) + { + double fNumerator = 0.0; + for (lcl_tSizeType i=1; i<=j ; ++i) + { + double dx = rUniquePoints[i].first - rUniquePoints[i-1].first; + double dy = rUniquePoints[i].second - rUniquePoints[i-1].second; + fNumerator += sqrt(std::hypot(dx, dy)); + } + t[j] = fNumerator / fDenominator; + + } + // postcondition check + t[n] = 1.0; + double fPrevious = 0.0; + for (lcl_tSizeType i=1; i <= n && bIsSuccessful ; ++i) + { + if (fPrevious >= t[i]) + { + bIsSuccessful = false; + } + else + { + fPrevious = t[i]; + } + } + } + return bIsSuccessful; +} + +void createKnotVector(const lcl_tSizeType n, const sal_uInt32 p, const double* t, double* u) +{ // precondition: 0 = t_0 < t_1 < ... < t_n = 1 + for (lcl_tSizeType j = 0; j <= p; ++j) + { + u[j] = 0.0; + } + for (lcl_tSizeType j = 1; j <= n-p; ++j ) + { + double fSum = 0.0; + for (lcl_tSizeType i = j; i <= j+p-1; ++i) + { + fSum += t[i]; + } + assert(p != 0); + u[j+p] = fSum / p ; + } + for (lcl_tSizeType j = n+1; j <= n+1+p; ++j) + { + u[j] = 1.0; + } +} + +void applyNtoParameterT(const lcl_tSizeType i,const double tk,const sal_uInt32 p,const double* u, double* rowN) +{ + // get N_p(t_k) recursively, only N_(i-p) till N_(i) are relevant, all other N_# are zero + + // initialize with indicator function degree 0 + rowN[p] = 1.0; // all others are zero + + // calculate up to degree p + for (sal_uInt32 s = 1; s <= p; ++s) + { + // first element + double fLeftFactor = 0.0; + double fRightFactor = ( u[i+1] - tk ) / ( u[i+1]- u[i-s+1] ); + // i-s "true index" - (i-p)"shift" = p-s + rowN[p-s] = fRightFactor * rowN[p-s+1]; + + // middle elements + for (sal_uInt32 j = s-1; j>=1 ; --j) + { + fLeftFactor = ( tk - u[i-j] ) / ( u[i-j+s] - u[i-j] ) ; + fRightFactor = ( u[i-j+s+1] - tk ) / ( u[i-j+s+1] - u[i-j+1] ); + // i-j "true index" - (i-p)"shift" = p-j + rowN[p-j] = fLeftFactor * rowN[p-j] + fRightFactor * rowN[p-j+1]; + } + + // last element + fLeftFactor = ( tk - u[i] ) / ( u[i+s] - u[i] ); + // i "true index" - (i-p)"shift" = p + rowN[p] = fLeftFactor * rowN[p]; + } +} + +} // anonymous namespace + +// Calculates uniform parametric splines with subinterval length 1, +// according ODF1.2 part 1, chapter 'chart interpolation'. +void SplineCalculater::CalculateCubicSplines( + const std::vector>& rInput + , std::vector>& rResult + , sal_uInt32 nGranularity ) +{ + OSL_PRECOND( nGranularity > 0, "Granularity is invalid" ); + + sal_uInt32 nOuterCount = rInput.size(); + + rResult.resize(nOuterCount); + + auto pSequence = rResult.data(); + + if( !nOuterCount ) + return; + + for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( rInput[nOuter].size() <= 1 ) + continue; //we need at least two points + + sal_uInt32 nMaxIndexPoints = rInput[nOuter].size()-1; // is >=1 + const css::drawing::Position3D* pOld = rInput[nOuter].data(); + + std::vector < double > aParameter(nMaxIndexPoints+1); + aParameter[0]=0.0; + for( sal_uInt32 nIndex=1; nIndex<=nMaxIndexPoints; nIndex++ ) + { + aParameter[nIndex]=aParameter[nIndex-1]+1; + } + + // Split the calculation to X, Y and Z coordinate + tPointVecType aInputX; + aInputX.resize(nMaxIndexPoints+1); + tPointVecType aInputY; + aInputY.resize(nMaxIndexPoints+1); + tPointVecType aInputZ; + aInputZ.resize(nMaxIndexPoints+1); + for (sal_uInt32 nN=0;nN<=nMaxIndexPoints; nN++ ) + { + aInputX[ nN ].first=aParameter[nN]; + aInputX[ nN ].second=pOld[ nN ].PositionX; + aInputY[ nN ].first=aParameter[nN]; + aInputY[ nN ].second=pOld[ nN ].PositionY; + aInputZ[ nN ].first=aParameter[nN]; + aInputZ[ nN ].second=pOld[ nN ].PositionZ; + } + + // generate a spline for each coordinate. It holds the complete + // information to calculate each point of the curve + std::unique_ptr aSplineX; + std::unique_ptr aSplineY; + // lcl_SplineCalculation* aSplineZ; the z-coordinates of all points in + // a data series are equal. No spline calculation needed, but copy + // coordinate to output + + if( pOld[ 0 ].PositionX == pOld[nMaxIndexPoints].PositionX && + pOld[ 0 ].PositionY == pOld[nMaxIndexPoints].PositionY && + pOld[ 0 ].PositionZ == pOld[nMaxIndexPoints].PositionZ && + nMaxIndexPoints >=2 ) + { // periodic spline + aSplineX = std::make_unique(std::move(aInputX)); + aSplineY = std::make_unique(std::move(aInputY)); + } + else // generate the kind "natural spline" + { + double fXDerivation = std::numeric_limits::infinity(); + double fYDerivation = std::numeric_limits::infinity(); + aSplineX = std::make_unique(std::move(aInputX), fXDerivation, fXDerivation); + aSplineY = std::make_unique(std::move(aInputY), fYDerivation, fYDerivation); + } + + // fill result polygon with calculated values + pSequence[nOuter].resize( nMaxIndexPoints*nGranularity + 1); + + css::drawing::Position3D* pNew = pSequence[nOuter].data(); + + sal_uInt32 nNewPointIndex = 0; // Index in result points + + for( sal_uInt32 ni = 0; ni < nMaxIndexPoints; ni++ ) + { + // given point is surely a curve point + pNew[nNewPointIndex].PositionX = pOld[ni].PositionX; + pNew[nNewPointIndex].PositionY = pOld[ni].PositionY; + pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ; + nNewPointIndex++; + + // calculate intermediate points + double fInc = ( aParameter[ ni+1 ] - aParameter[ni] ) / static_cast< double >( nGranularity ); + for(sal_uInt32 nj = 1; nj < nGranularity; nj++) + { + double fParam = aParameter[ni] + ( fInc * static_cast< double >( nj ) ); + + pNew[nNewPointIndex].PositionX = aSplineX->GetInterpolatedValue( fParam ); + pNew[nNewPointIndex].PositionY = aSplineY->GetInterpolatedValue( fParam ); + // pNewZ[nNewPointIndex]=aSplineZ->GetInterpolatedValue( fParam ); + pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ; + nNewPointIndex++; + } + } + // add last point + pNew[nNewPointIndex] = pOld[nMaxIndexPoints]; + } +} + +void SplineCalculater::CalculateBSplines( + const std::vector>& rInput + , std::vector>& rResult + , sal_uInt32 nResolution + , sal_uInt32 nDegree ) +{ + // nResolution is ODF1.2 file format attribute chart:spline-resolution and + // ODF1.2 spec variable k. Causion, k is used as index in the spec in addition. + // nDegree is ODF1.2 file format attribute chart:spline-order and + // ODF1.2 spec variable p + OSL_ASSERT( nResolution > 1 ); + OSL_ASSERT( nDegree >= 1 ); + + // limit the b-spline degree at 15 to prevent insanely large sets of points + sal_uInt32 p = std::min(nDegree, 15); + + sal_Int32 nOuterCount = rInput.size(); + + rResult.resize(nOuterCount); + + auto pSequence = rResult.data(); + + if( !nOuterCount ) + return; // no input + + for( sal_Int32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( rInput[nOuter].size() <= 1 ) + continue; // need at least 2 points, next piece of the series + + // Copy input to vector of points and remove adjacent double points. The + // Z-coordinate is equal for all points in a series and holds the depth + // in 3D mode, simple copying is enough. + lcl_tSizeType nMaxIndexPoints = rInput[nOuter].size()-1; // is >=1 + const css::drawing::Position3D* pOld = rInput[nOuter].data(); + double fZCoordinate = pOld[0].PositionZ; + tPointVecType aPointsIn; + aPointsIn.resize(nMaxIndexPoints+1); + for (lcl_tSizeType i = 0; i <= nMaxIndexPoints; ++i ) + { + aPointsIn[ i ].first = pOld[i].PositionX; + aPointsIn[ i ].second = pOld[i].PositionY; + } + aPointsIn.erase( std::unique( aPointsIn.begin(), aPointsIn.end()), + aPointsIn.end() ); + + // n is the last valid index to the reduced aPointsIn + // There are n+1 valid data points. + const lcl_tSizeType n = aPointsIn.size() - 1; + if (n < 1 || p > n) + continue; // need at least 2 points, degree p needs at least n+1 points + // next piece of series + + std::vector t(n + 1); + if (!createParameterT(aPointsIn, t.data())) + { + continue; // next piece of series + } + + lcl_tSizeType m = n + p + 1; + std::vector u(m + 1); + createKnotVector(n, p, t.data(), u.data()); + + // The matrix N contains the B-spline basis functions applied to parameters. + // In each row only p+1 adjacent elements are non-zero. The starting + // column in a higher row is equal or greater than in the lower row. + // To store this matrix the non-zero elements are shifted to column 0 + // and the amount of shifting is remembered in an array. + std::vector> aMatN(n + 1, std::vector(p + 1)); + std::vector aShift(n + 1); + aMatN[0][0] = 1.0; //all others are zero + aShift[0] = 0; + aMatN[n][0] = 1.0; + aShift[n] = n; + for (lcl_tSizeType k = 1; k<=n-1; ++k) + { // all basis functions are applied to t_k, + // results are elements in row k in matrix N + + // find the one interval with u_i <= t_k < u_(i+1) + // remember u_0 = ... = u_p = 0.0 and u_(m-p) = ... u_m = 1.0 and 0 t[k] || t[k] >= u[i+1]) + { + ++i; + } + + // index in reduced matrix aMatN = (index in full matrix N) - (i-p) + aShift[k] = i - p; + + applyNtoParameterT(i, t[k], p, u.data(), aMatN[k].data()); + } // next row k + + // Get matrix C of control points from the matrix equation aMatN * C = aPointsIn + // aPointsIn is overwritten with C. + // Gaussian elimination is possible without pivoting, see reference + lcl_tSizeType r = 0; // true row index + lcl_tSizeType c = 0; // true column index + double fDivisor = 1.0; // used for diagonal element + double fEliminate = 1.0; // used for the element, that will become zero + bool bIsSuccessful = true; + for (c = 0 ; c <= n && bIsSuccessful; ++c) + { + // search for first non-zero downwards + r = c; + while ( r < n && aMatN[r][c-aShift[r]] == 0 ) + { + ++r; + } + if (aMatN[r][c-aShift[r]] == 0.0) + { + // Matrix N is singular, although this is mathematically impossible + bIsSuccessful = false; + } + else + { + // exchange total row r with total row c if necessary + if (r != c) + { + std::swap( aMatN[r], aMatN[c] ); + std::swap( aPointsIn[r], aPointsIn[c] ); + std::swap( aShift[r], aShift[c] ); + } + + // divide row c, so that element(c,c) becomes 1 + fDivisor = aMatN[c][c-aShift[c]]; // not zero, see above + for (sal_uInt32 i = 0; i <= p; ++i) + { + aMatN[c][i] /= fDivisor; + } + aPointsIn[c].first /= fDivisor; + aPointsIn[c].second /= fDivisor; + + // eliminate forward, examine row c+1 to n-1 (worst case) + // stop if first non-zero element in row has an higher column as c + // look at nShift for that, elements in nShift are equal or increasing + for ( r = c+1; r < n && aShift[r]<=c ; ++r) + { + fEliminate = aMatN[r][0]; + if (fEliminate != 0.0) // else accidentally zero, nothing to do + { + for (sal_uInt32 i = 1; i <= p; ++i) + { + aMatN[r][i-1] = aMatN[r][i] - fEliminate * aMatN[c][i]; + } + aMatN[r][p]=0; + aPointsIn[r].first -= fEliminate * aPointsIn[c].first; + aPointsIn[r].second -= fEliminate * aPointsIn[c].second; + ++aShift[r]; + } + } + } + }// upper triangle form is reached + if( bIsSuccessful) + { + // eliminate backwards, begin with last column + for (lcl_tSizeType cc = n; cc >= 1; --cc ) + { + // In row cc the diagonal element(cc,cc) == 1 and all elements left from + // diagonal are zero and do not influence other rows. + // Full matrix N has semibandwidth < p, therefore element(r,c) is + // zero, if abs(r-cc)>=p. abs(r-cc)=cc-r, because r aP(m + 1); + lcl_tSizeType nLow = 0; + for ( lcl_tSizeType nTIndex = 0; nTIndex <= n-1; ++nTIndex) + { + for (sal_uInt32 nResolutionStep = 1; + nResolutionStep <= nResolution && ( nTIndex != n-1 || nResolutionStep != nResolution); + ++nResolutionStep) + { + lcl_tSizeType nNewIndex = nTIndex * nResolution + nResolutionStep; + double ux = t[nTIndex] + nResolutionStep * ( t[nTIndex+1] - t[nTIndex]) /nResolution; + + // get index nLow, so that u[nLow]<= ux < u[nLow +1] + // continue from previous nLow + while ( u[nLow] <= ux) + { + ++nLow; + } + --nLow; + + // x-coordinate + for (lcl_tSizeType i = nLow-p; i <= nLow; ++i) + { + aP[i] = aPointsIn[i].first; + } + for (sal_uInt32 lcl_Degree = 1; lcl_Degree <= p; ++lcl_Degree) + { + for (lcl_tSizeType i = nLow; i >= nLow + lcl_Degree - p; --i) + { + double fFactor = ( ux - u[i] ) / ( u[i+p+1-lcl_Degree] - u[i]); + aP[i] = (1 - fFactor)* aP[i-1] + fFactor * aP[i]; + } + } + pNew[nNewIndex].PositionX = aP[nLow]; + + // y-coordinate + for (lcl_tSizeType i = nLow - p; i <= nLow; ++i) + { + aP[i] = aPointsIn[i].second; + } + for (sal_uInt32 lcl_Degree = 1; lcl_Degree <= p; ++lcl_Degree) + { + for (lcl_tSizeType i = nLow; i >= nLow +lcl_Degree - p; --i) + { + double fFactor = ( ux - u[i] ) / ( u[i+p+1-lcl_Degree] - u[i]); + aP[i] = (1 - fFactor)* aP[i-1] + fFactor * aP[i]; + } + } + pNew[nNewIndex].PositionY = aP[nLow]; + pNew[nNewIndex].PositionZ = fZCoordinate; + } + } + } + } // next piece of the series +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/Splines.hxx b/chart2/source/view/charttypes/Splines.hxx new file mode 100644 index 000000000..b83c13931 --- /dev/null +++ b/chart2/source/view/charttypes/Splines.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } +namespace com::sun::star::drawing { struct Position3D; } + +namespace chart +{ + +class SplineCalculater +{ +public: + static void CalculateCubicSplines( + const std::vector>& rPoints + , std::vector>& rResult + , sal_uInt32 nGranularity ); + + static void CalculateBSplines( + const std::vector>& rPoints + , std::vector>& rResult + , sal_uInt32 nGranularity + , sal_uInt32 nSplineDepth ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx new file mode 100644 index 000000000..fd3a1fe1f --- /dev/null +++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx @@ -0,0 +1,2847 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//only for creation: @todo remove if all plotter are uno components and instantiated via servicefactory +#include "BarChart.hxx" +#include "PieChart.hxx" +#include "AreaChart.hxx" +#include "CandleStickChart.hxx" +#include "BubbleChart.hxx" +#include "NetChart.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace chart { + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart; +using namespace ::com::sun::star::chart2; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +VDataSeriesGroup::CachedYValues::CachedYValues() + : m_bValuesDirty(true) + , m_fMinimumY(0.0) + , m_fMaximumY(0.0) +{ +} + +VDataSeriesGroup::VDataSeriesGroup( std::unique_ptr pSeries ) + : m_aSeriesVector(1) + , m_bMaxPointCountDirty(true) + , m_nMaxPointCount(0) +{ + m_aSeriesVector[0] = std::move(pSeries); +} + +VDataSeriesGroup::VDataSeriesGroup(VDataSeriesGroup&& other) noexcept + : m_aSeriesVector( std::move(other.m_aSeriesVector) ) + , m_bMaxPointCountDirty( other.m_bMaxPointCountDirty ) + , m_nMaxPointCount( other.m_nMaxPointCount ) + , m_aListOfCachedYValues( std::move(other.m_aListOfCachedYValues) ) +{ +} + +VDataSeriesGroup::~VDataSeriesGroup() +{ +} + +void VDataSeriesGroup::deleteSeries() +{ + //delete all data series help objects: + m_aSeriesVector.clear(); +} + +void VDataSeriesGroup::addSeries( std::unique_ptr pSeries ) +{ + m_aSeriesVector.push_back(std::move(pSeries)); + m_bMaxPointCountDirty=true; +} + +sal_Int32 VDataSeriesGroup::getSeriesCount() const +{ + return m_aSeriesVector.size(); +} + +VSeriesPlotter::VSeriesPlotter( const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount, bool bCategoryXAxis ) + : PlotterBase( nDimensionCount ) + , m_pMainPosHelper( nullptr ) + , m_xChartTypeModel(xChartTypeModel) + , m_bCategoryXAxis(bCategoryXAxis) + , m_nTimeResolution(css::chart::TimeUnit::DAY) + , m_aNullDate(30,12,1899) + , m_pExplicitCategoriesProvider(nullptr) + , m_bPointsWereSkipped(false) + , m_bPieLabelsAllowToMove(false) + , m_aAvailableOuterRect(0, 0, 0, 0) +{ + SAL_WARN_IF(!m_xChartTypeModel.is(),"chart2","no XChartType available in view, fallback to default values may be wrong"); +} + +VSeriesPlotter::~VSeriesPlotter() +{ + //delete all data series help objects: + for (std::vector & rGroupVector : m_aZSlots) + { + for (VDataSeriesGroup & rGroup : rGroupVector) + { + rGroup.deleteSeries(); + } + rGroupVector.clear(); + } + m_aZSlots.clear(); + + m_aSecondaryPosHelperMap.clear(); + + m_aSecondaryValueScales.clear(); +} + +void VSeriesPlotter::addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ) +{ + //take ownership of pSeries + + OSL_PRECOND( pSeries, "series to add is NULL" ); + if(!pSeries) + return; + + if(m_bCategoryXAxis) + { + if( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) + pSeries->setXValues( m_pExplicitCategoriesProvider->getOriginalCategories() ); + else + pSeries->setCategoryXAxis(); + } + else + { + if( m_pExplicitCategoriesProvider ) + pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() ); + } + + if(zSlot<0 || o3tl::make_unsigned(zSlot)>=m_aZSlots.size()) + { + //new z slot + std::vector< VDataSeriesGroup > aZSlot; + aZSlot.emplace_back( std::move(pSeries) ); + m_aZSlots.push_back( std::move(aZSlot) ); + } + else + { + //existing zslot + std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot]; + + if(xSlot<0 || o3tl::make_unsigned(xSlot)>=rXSlots.size()) + { + //append the series to already existing x series + rXSlots.emplace_back( std::move(pSeries) ); + } + else + { + //x slot is already occupied + //y slot decides what to do: + + VDataSeriesGroup& rYSlots = rXSlots[xSlot]; + sal_Int32 nYSlotCount = rYSlots.getSeriesCount(); + + if( ySlot < -1 ) + { + //move all existing series in the xSlot to next slot + //@todo + OSL_FAIL( "Not implemented yet"); + } + else if( ySlot == -1 || ySlot >= nYSlotCount) + { + //append the series to already existing y series + rYSlots.addSeries( std::move(pSeries) ); + } + else + { + //y slot is already occupied + //insert at given y and x position + + //@todo + OSL_FAIL( "Not implemented yet"); + } + } + } +} + +drawing::Direction3D VSeriesPlotter::getPreferredDiagramAspectRatio() const +{ + drawing::Direction3D aRet(1.0,1.0,1.0); + if (!m_pPosHelper) + return aRet; + + drawing::Direction3D aScale( m_pPosHelper->getScaledLogicWidth() ); + aRet.DirectionZ = aScale.DirectionZ*0.2; + if(aRet.DirectionZ>1.0) + aRet.DirectionZ=1.0; + if(aRet.DirectionZ>10) + aRet.DirectionZ=10; + return aRet; +} + +void VSeriesPlotter::releaseShapes() +{ + for (std::vector const & rGroupVector : m_aZSlots) + { + for (VDataSeriesGroup const & rGroup : rGroupVector) + { + //iterate through all series in this x slot + for (std::unique_ptr const & pSeries : rGroup.m_aSeriesVector) + { + pSeries->releaseShapes(); + } + } + } +} + +rtl::Reference VSeriesPlotter::getSeriesGroupShape( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ) +{ + if( !pDataSeries->m_xGroupShape ) + //create a group shape for this series and add to logic target: + pDataSeries->m_xGroupShape = createGroupShape( xTarget,pDataSeries->getCID() ); + return pDataSeries->m_xGroupShape; +} + +rtl::Reference VSeriesPlotter::getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ) +{ + if(!pDataSeries->m_xFrontSubGroupShape) + { + //ensure that the series group shape is already created + rtl::Reference xSeriesShapes( getSeriesGroupShape( pDataSeries, xTarget ) ); + //ensure that the back child is created first + getSeriesGroupShapeBackChild( pDataSeries, xTarget ); + //use series group shape as parent for the new created front group shape + pDataSeries->m_xFrontSubGroupShape = createGroupShape( xSeriesShapes ); + } + return pDataSeries->m_xFrontSubGroupShape; +} + +rtl::Reference VSeriesPlotter::getSeriesGroupShapeBackChild( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ) +{ + if(!pDataSeries->m_xBackSubGroupShape) + { + //ensure that the series group shape is already created + rtl::Reference xSeriesShapes( getSeriesGroupShape( pDataSeries, xTarget ) ); + //use series group shape as parent for the new created back group shape + pDataSeries->m_xBackSubGroupShape = createGroupShape( xSeriesShapes ); + } + return pDataSeries->m_xBackSubGroupShape; +} + +rtl::Reference VSeriesPlotter::getLabelsGroupShape( VDataSeries& rDataSeries + , const rtl::Reference& xTextTarget ) +{ + //xTextTarget needs to be a 2D shape container always! + if(!rDataSeries.m_xLabelsGroupShape) + { + //create a 2D group shape for texts of this series and add to text target: + rDataSeries.m_xLabelsGroupShape = ShapeFactory::createGroup2D( xTextTarget, rDataSeries.getLabelsCID() ); + } + return rDataSeries.m_xLabelsGroupShape; +} + +rtl::Reference VSeriesPlotter::getErrorBarsGroupShape( VDataSeries& rDataSeries + , const rtl::Reference& xTarget + , bool bYError ) +{ + rtl::Reference &rShapeGroup = + bYError ? rDataSeries.m_xErrorYBarsGroupShape : rDataSeries.m_xErrorXBarsGroupShape; + + if(!rShapeGroup) + { + //create a group shape for this series and add to logic target: + rShapeGroup = createGroupShape( xTarget,rDataSeries.getErrorBarsCID(bYError) ); + } + return rShapeGroup; + +} + +OUString VSeriesPlotter::getLabelTextForValue( VDataSeries const & rDataSeries + , sal_Int32 nPointIndex + , double fValue + , bool bAsPercentage ) +{ + OUString aNumber; + + if (m_apNumberFormatterWrapper) + { + sal_Int32 nNumberFormatKey = 0; + if( rDataSeries.hasExplicitNumberFormat(nPointIndex,bAsPercentage) ) + nNumberFormatKey = rDataSeries.getExplicitNumberFormat(nPointIndex,bAsPercentage); + else if( bAsPercentage ) + { + sal_Int32 nPercentFormat = DiagramHelper::getPercentNumberFormat( m_apNumberFormatterWrapper->getNumberFormatsSupplier() ); + if( nPercentFormat != -1 ) + nNumberFormatKey = nPercentFormat; + } + else + { + nNumberFormatKey = rDataSeries.detectNumberFormatKey( nPointIndex ); + } + if(nNumberFormatKey<0) + nNumberFormatKey=0; + + Color nLabelCol; + bool bColChanged; + aNumber = m_apNumberFormatterWrapper->getFormattedString( + nNumberFormatKey, fValue, nLabelCol, bColChanged ); + //@todo: change color of label if bColChanged is true + } + else + { + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + assert(aNumDecimalSep.getLength() > 0); + sal_Unicode cDecSeparator = aNumDecimalSep[0]; + aNumber = ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G /*rtl_math_StringFormat*/ + , 3/*DecPlaces*/ , cDecSeparator ); + } + return aNumber; +} + +rtl::Reference VSeriesPlotter::createDataLabel( const rtl::Reference& xTarget + , VDataSeries& rDataSeries + , sal_Int32 nPointIndex + , double fValue + , double fSumValue + , const awt::Point& rScreenPosition2D + , LabelAlignment eAlignment + , sal_Int32 nOffset + , sal_Int32 nTextWidth ) +{ + rtl::Reference xTextShape; + Sequence> aCustomLabels; + + try + { + const uno::Reference< css::beans::XPropertySet >& xPropertySet( + rDataSeries.getPropertiesOfPoint( nPointIndex ) ); + if( xPropertySet.is() ) + { + uno::Any aAny = xPropertySet->getPropertyValue( CHART_UNONAME_CUSTOM_LABEL_FIELDS ); + if( aAny.hasValue() ) + { + aAny >>= aCustomLabels; + } + } + + awt::Point aScreenPosition2D(rScreenPosition2D); + if(eAlignment==LABEL_ALIGN_LEFT) + aScreenPosition2D.X -= nOffset; + else if(eAlignment==LABEL_ALIGN_RIGHT) + aScreenPosition2D.X += nOffset; + else if(eAlignment==LABEL_ALIGN_TOP) + aScreenPosition2D.Y -= nOffset; + else if(eAlignment==LABEL_ALIGN_BOTTOM) + aScreenPosition2D.Y += nOffset; + + rtl::Reference xTarget_ = + ShapeFactory::createGroup2D( + getLabelsGroupShape(rDataSeries, xTarget), + ObjectIdentifier::createPointCID( rDataSeries.getLabelCID_Stub(), nPointIndex)); + + //check whether the label needs to be created and how: + DataPointLabel* pLabel = rDataSeries.getDataPointLabelIfLabel( nPointIndex ); + + if( !pLabel ) + return xTextShape; + + //prepare legend symbol + + // get the font size for the label through the "CharHeight" property + // attached to the passed data series entry. + // (By tracing font height values it results that for pie chart the + // font size is not the same for all labels, but here no font size + // modification occurs). + float fViewFontSize( 10.0 ); + { + uno::Reference< beans::XPropertySet > xProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) ); + if( xProps.is() ) + xProps->getPropertyValue( "CharHeight") >>= fViewFontSize; + fViewFontSize = convertPointToMm100(fViewFontSize); + } + + // the font height is used for computing the size of an optional legend + // symbol to be prepended to the text label. + rtl::Reference< SvxShapeGroup > xSymbol; + if(pLabel->ShowLegendSymbol) + { + sal_Int32 nSymbolHeight = static_cast< sal_Int32 >( fViewFontSize * 0.6 ); + awt::Size aCurrentRatio = getPreferredLegendKeyAspectRatio(); + sal_Int32 nSymbolWidth = aCurrentRatio.Width; + if( aCurrentRatio.Height > 0 ) + { + nSymbolWidth = nSymbolHeight* aCurrentRatio.Width/aCurrentRatio.Height; + } + awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeight ); + + if( rDataSeries.isVaryColorsByPoint() ) + xSymbol = VSeriesPlotter::createLegendSymbolForPoint( aMaxSymbolExtent, rDataSeries, nPointIndex, xTarget_ ); + else + xSymbol = VSeriesPlotter::createLegendSymbolForSeries( aMaxSymbolExtent, rDataSeries, xTarget_ ); + } + + //prepare text + bool bTextWrap = false; + OUString aSeparator(" "); + double fRotationDegrees = 0.0; + try + { + uno::Reference< beans::XPropertySet > xPointProps( rDataSeries.getPropertiesOfPoint( nPointIndex ) ); + if(xPointProps.is()) + { + xPointProps->getPropertyValue( "TextWordWrap" ) >>= bTextWrap; + xPointProps->getPropertyValue( "LabelSeparator" ) >>= aSeparator; + // Extract the optional text rotation through the + // "TextRotation" property attached to the passed data point. + xPointProps->getPropertyValue( "TextRotation" ) >>= fRotationDegrees; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + sal_Int32 nLineCountForSymbolsize = 0; + sal_uInt32 nTextListLength = 4; + sal_uInt32 nCustomLabelsCount = aCustomLabels.getLength(); + Sequence< OUString > aTextList( nTextListLength ); + + bool bUseCustomLabel = nCustomLabelsCount > 0; + if( bUseCustomLabel ) + { + nTextListLength = ( nCustomLabelsCount > 3 ) ? nCustomLabelsCount : 3; + aSeparator = ""; + aTextList = Sequence< OUString >( nTextListLength ); + auto pTextList = aTextList.getArray(); + for( sal_uInt32 i = 0; i < nCustomLabelsCount; ++i ) + { + switch( aCustomLabels[i]->getFieldType() ) + { + case DataPointCustomLabelFieldType_VALUE: + { + pTextList[i] = getLabelTextForValue( rDataSeries, nPointIndex, fValue, false ); + break; + } + case DataPointCustomLabelFieldType_CATEGORYNAME: + { + pTextList[i] = getCategoryName( nPointIndex ); + break; + } + case DataPointCustomLabelFieldType_SERIESNAME: + { + OUString aRole; + if ( m_xChartTypeModel ) + aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel(); + const rtl::Reference< DataSeries >& xSeries( rDataSeries.getModel() ); + pTextList[i] = DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ); + break; + } + case DataPointCustomLabelFieldType_PERCENTAGE: + { + if(fSumValue == 0.0) + fSumValue = 1.0; + fValue /= fSumValue; + if(fValue < 0) + fValue *= -1.0; + + pTextList[i] = getLabelTextForValue(rDataSeries, nPointIndex, fValue, true); + break; + } + case DataPointCustomLabelFieldType_CELLRANGE: + { + if (aCustomLabels[i]->getDataLabelsRange()) + pTextList[i] = aCustomLabels[i]->getString(); + else + pTextList[i] = OUString(); + break; + } + case DataPointCustomLabelFieldType_CELLREF: + { + // TODO: for now doesn't show placeholder + pTextList[i] = OUString(); + break; + } + case DataPointCustomLabelFieldType_TEXT: + { + pTextList[i] = aCustomLabels[i]->getString(); + break; + } + case DataPointCustomLabelFieldType_NEWLINE: + { + pTextList[i] = "\n"; + break; + } + default: + break; + } + aCustomLabels[i]->setString( aTextList[i] ); + } + } + else + { + auto pTextList = aTextList.getArray(); + if( pLabel->ShowCategoryName ) + { + pTextList[0] = getCategoryName( nPointIndex ); + } + + if( pLabel->ShowSeriesName ) + { + OUString aRole; + if ( m_xChartTypeModel ) + aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel(); + const rtl::Reference< DataSeries >& xSeries( rDataSeries.getModel() ); + pTextList[1] = DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ); + } + + if( pLabel->ShowNumber ) + { + pTextList[2] = getLabelTextForValue(rDataSeries, nPointIndex, fValue, false); + } + + if( pLabel->ShowNumberInPercent ) + { + if(fSumValue==0.0) + fSumValue=1.0; + fValue /= fSumValue; + if( fValue < 0 ) + fValue*=-1.0; + + pTextList[3] = getLabelTextForValue(rDataSeries, nPointIndex, fValue, true); + } + } + + for( auto const & line : std::as_const(aTextList) ) + { + if( !line.isEmpty() ) + { + ++nLineCountForSymbolsize; + } + } + + //prepare properties for multipropertyset-interface of shape + tNameSequence* pPropNames; + tAnySequence* pPropValues; + if( !rDataSeries.getTextLabelMultiPropertyLists( nPointIndex, pPropNames, pPropValues ) ) + return xTextShape; + + // set text alignment for the text shape to be created. + LabelPositionHelper::changeTextAdjustment( *pPropValues, *pPropNames, eAlignment ); + + // check if data series entry percent value and absolute value have to + // be appended to the text label, and what should be the separator + // character (comma, space, new line). In case it is a new line we get + // a multi-line label. + bool bMultiLineLabel = ( aSeparator == "\n" ); + + if( bUseCustomLabel ) + { + Sequence< uno::Reference< XFormattedString > > aFormattedLabels( + comphelper::containerToSequence>(aCustomLabels)); + + // create text shape + xTextShape = ShapeFactory:: + createText( xTarget_, aFormattedLabels, *pPropNames, *pPropValues, + ShapeFactory::makeTransformation( aScreenPosition2D ) ); + } + else + { + // join text list elements + OUStringBuffer aText; + for( sal_uInt32 nN = 0; nN < nTextListLength; ++nN) + { + if( !aTextList[nN].isEmpty() ) + { + if( !aText.isEmpty() ) + { + aText.append(aSeparator); + } + aText.append( aTextList[nN] ); + } + } + + //create text shape + xTextShape = ShapeFactory:: + createText( xTarget_, aText.makeStringAndClear(), *pPropNames, *pPropValues, + ShapeFactory::makeTransformation( aScreenPosition2D ) ); + } + + if( !xTextShape.is() ) + return xTextShape; + + // we need to use a default value for the maximum width property ? + if( nTextWidth == 0 && bTextWrap ) + { + sal_Int32 nMinSize = + (m_aPageReferenceSize.Height < m_aPageReferenceSize.Width) + ? m_aPageReferenceSize.Height + : m_aPageReferenceSize.Width; + nTextWidth = nMinSize / 3; + } + + // in case text must be wrapped set the maximum width property + // for the text shape + if( nTextWidth != 0 && bTextWrap ) + { + // compute the height of a line of text + if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 ) + { + nLineCountForSymbolsize = 1; + } + awt::Size aTextSize = xTextShape->getSize(); + sal_Int32 aTextLineHeight = aTextSize.Height / nLineCountForSymbolsize; + + // set maximum text width + uno::Any aTextMaximumFrameWidth( nTextWidth ); + xTextShape->SvxShape::setPropertyValue( "TextMaximumFrameWidth", aTextMaximumFrameWidth ); + + // compute the total lines of text + aTextSize = xTextShape->getSize(); + nLineCountForSymbolsize = aTextSize.Height / aTextLineHeight; + } + + // in case text is rotated, the transformation property of the text + // shape is modified. + if( fRotationDegrees != 0.0 ) + { + const double fDegreesPi( -basegfx::deg2rad(fRotationDegrees) ); + xTextShape->SvxShape::setPropertyValue( "Transformation", ShapeFactory::makeTransformation( aScreenPosition2D, fDegreesPi ) ); + LabelPositionHelper::correctPositionForRotation( xTextShape, eAlignment, fRotationDegrees, true /*bRotateAroundCenter*/ ); + } + + awt::Point aTextShapePos(xTextShape->getPosition()); + if( m_bPieLabelsAllowToMove && rDataSeries.isLabelCustomPos(nPointIndex) ) + { + awt::Point aRelPos = rDataSeries.getLabelPosition(aTextShapePos, nPointIndex); + if( aRelPos.X != -1 ) + { + xTextShape->setPosition(aRelPos); + if( !m_xChartTypeModel->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) && + rDataSeries.getPropertiesOfSeries()->getPropertyValue( "ShowCustomLeaderLines" ).get()) + { + sal_Int32 nX1 = rScreenPosition2D.X; + sal_Int32 nY1 = rScreenPosition2D.Y; + sal_Int32 nX2 = nX1; + sal_Int32 nY2 = nY1; + ::basegfx::B2IRectangle aRect(BaseGFXHelper::makeRectangle(aRelPos, xTextShape->getSize())); + if (nX1 < aRelPos.X) + nX2 = aRelPos.X; + else if (nX1 > aRect.getMaxX()) + nX2 = aRect.getMaxX(); + + if (nY1 < aRect.getMinY()) + nY2 = aRect.getMinY(); + else if (nY1 > aRect.getMaxY()) + nY2 = aRect.getMaxY(); + + //when the line is very short compared to the page size don't create one + ::basegfx::B2DVector aLength(nX1 - nX2, nY1 - nY2); + double fPageDiagonaleLength + = std::hypot(m_aPageReferenceSize.Width, m_aPageReferenceSize.Height); + if ((aLength.getLength() / fPageDiagonaleLength) >= 0.01) + { + drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } }; + + VLineProperties aVLineProperties; + ShapeFactory::createLine2D(xTarget, aPoints, &aVLineProperties); + } + } + } + } + + // in case legend symbol has to be displayed, text shape position is + // slightly changed. + const awt::Point aUnrotatedTextPos(xTextShape->getPosition()); + if( xSymbol.is() ) + { + const awt::Point aOldTextPos( xTextShape->getPosition() ); + awt::Point aNewTextPos( aOldTextPos ); + + awt::Point aSymbolPosition( aUnrotatedTextPos ); + awt::Size aSymbolSize( xSymbol->getSize() ); + awt::Size aTextSize = xTextShape->getSize(); + + sal_Int32 nXDiff = aSymbolSize.Width + static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm + if( !bMultiLineLabel || nLineCountForSymbolsize <= 0 ) + nLineCountForSymbolsize = 1; + aSymbolPosition.Y += ((aTextSize.Height/nLineCountForSymbolsize)/4); + + if(eAlignment==LABEL_ALIGN_LEFT + || eAlignment==LABEL_ALIGN_LEFT_TOP + || eAlignment==LABEL_ALIGN_LEFT_BOTTOM) + { + aSymbolPosition.X -= nXDiff; + } + else if(eAlignment==LABEL_ALIGN_RIGHT + || eAlignment==LABEL_ALIGN_RIGHT_TOP + || eAlignment==LABEL_ALIGN_RIGHT_BOTTOM ) + { + aNewTextPos.X += nXDiff; + } + else if(eAlignment==LABEL_ALIGN_TOP + || eAlignment==LABEL_ALIGN_BOTTOM + || eAlignment==LABEL_ALIGN_CENTER ) + { + aSymbolPosition.X -= nXDiff/2; + aNewTextPos.X += nXDiff/2; + } + + xSymbol->setPosition( aSymbolPosition ); + xTextShape->setPosition( aNewTextPos ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + return xTextShape; +} + +namespace +{ +double lcl_getErrorBarLogicLength( + const uno::Sequence< double > & rData, + const uno::Reference< beans::XPropertySet >& xProp, + sal_Int32 nErrorBarStyle, + sal_Int32 nIndex, + bool bPositive, + bool bYError ) +{ + double fResult = std::numeric_limits::quiet_NaN(); + try + { + switch( nErrorBarStyle ) + { + case css::chart::ErrorBarStyle::NONE: + break; + case css::chart::ErrorBarStyle::VARIANCE: + fResult = StatisticsHelper::getVariance( rData ); + break; + case css::chart::ErrorBarStyle::STANDARD_DEVIATION: + fResult = StatisticsHelper::getStandardDeviation( rData ); + break; + case css::chart::ErrorBarStyle::RELATIVE: + { + double fPercent = 0; + if( xProp->getPropertyValue( bPositive + ? OUString("PositiveError") + : OUString("NegativeError") ) >>= fPercent ) + { + if( nIndex >=0 && nIndex < rData.getLength() && + ! std::isnan( rData[nIndex] ) && + ! std::isnan( fPercent )) + { + fResult = rData[nIndex] * fPercent / 100.0; + } + } + } + break; + case css::chart::ErrorBarStyle::ABSOLUTE: + xProp->getPropertyValue( bPositive + ? OUString("PositiveError") + : OUString("NegativeError") ) >>= fResult; + break; + case css::chart::ErrorBarStyle::ERROR_MARGIN: + { + // todo: check if this is really what's called error-margin + double fPercent = 0; + if( xProp->getPropertyValue( bPositive + ? OUString("PositiveError") + : OUString("NegativeError") ) >>= fPercent ) + { + double fMaxValue = -std::numeric_limits::infinity(); + for(double d : rData) + { + if(fMaxValue < d) + fMaxValue = d; + } + if( std::isfinite( fMaxValue ) && + std::isfinite( fPercent )) + { + fResult = fMaxValue * fPercent / 100.0; + } + } + } + break; + case css::chart::ErrorBarStyle::STANDARD_ERROR: + fResult = StatisticsHelper::getStandardError( rData ); + break; + case css::chart::ErrorBarStyle::FROM_DATA: + { + uno::Reference< chart2::data::XDataSource > xErrorBarData( xProp, uno::UNO_QUERY ); + if( xErrorBarData.is()) + fResult = StatisticsHelper::getErrorFromDataSource( + xErrorBarData, nIndex, bPositive, bYError); + } + break; + } + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + return fResult; +} + +void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection + , std::vector>& rPoly, sal_Int32 nSequenceIndex ) +{ + double fFixedWidth = 200.0; + + aMainDirection.normalize(); + ::basegfx::B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX()); + aOrthoDirection.normalize(); + + ::basegfx::B2DVector aAnchor( rPosition.PositionX, rPosition.PositionY ); + ::basegfx::B2DVector aStart = aAnchor + aOrthoDirection*fFixedWidth/2.0; + ::basegfx::B2DVector aEnd = aAnchor - aOrthoDirection*fFixedWidth/2.0; + + AddPointToPoly( rPoly, drawing::Position3D( aStart.getX(), aStart.getY(), rPosition.PositionZ), nSequenceIndex ); + AddPointToPoly( rPoly, drawing::Position3D( aEnd.getX(), aEnd.getY(), rPosition.PositionZ), nSequenceIndex ); +} + +::basegfx::B2DVector lcl_getErrorBarMainDirection( + const drawing::Position3D& rStart + , const drawing::Position3D& rBottomEnd + , PlottingPositionHelper const * pPosHelper + , const drawing::Position3D& rUnscaledLogicPosition + , bool bYError ) +{ + ::basegfx::B2DVector aMainDirection( rStart.PositionX - rBottomEnd.PositionX + , rStart.PositionY - rBottomEnd.PositionY ); + if( !aMainDirection.getLength() ) + { + //get logic clip values: + double MinX = pPosHelper->getLogicMinX(); + double MinY = pPosHelper->getLogicMinY(); + double MaxX = pPosHelper->getLogicMaxX(); + double MaxY = pPosHelper->getLogicMaxY(); + double fZ = pPosHelper->getLogicMinZ(); + + if( bYError ) + { + //main direction has constant x value + MinX = rUnscaledLogicPosition.PositionX; + MaxX = rUnscaledLogicPosition.PositionX; + } + else + { + //main direction has constant y value + MinY = rUnscaledLogicPosition.PositionY; + MaxY = rUnscaledLogicPosition.PositionY; + } + + drawing::Position3D aStart = pPosHelper->transformLogicToScene( MinX, MinY, fZ, false ); + drawing::Position3D aEnd = pPosHelper->transformLogicToScene( MaxX, MaxY, fZ, false ); + + aMainDirection = ::basegfx::B2DVector( aStart.PositionX - aEnd.PositionX + , aStart.PositionY - aEnd.PositionY ); + } + if( !aMainDirection.getLength() ) + { + //@todo + } + return aMainDirection; +} + +drawing::Position3D lcl_transformMixedToScene( PlottingPositionHelper const * pPosHelper + , double fX /*scaled*/, double fY /*unscaled*/, double fZ /*unscaled*/ ) +{ + if(!pPosHelper) + return drawing::Position3D(0,0,0); + pPosHelper->doLogicScaling( nullptr,&fY,&fZ ); + pPosHelper->clipScaledLogicValues( &fX,&fY,&fZ ); + return pPosHelper->transformScaledLogicToScene( fX, fY, fZ, false ); +} + +} // anonymous namespace + +void VSeriesPlotter::createErrorBar( + const rtl::Reference& xTarget + , const drawing::Position3D& rUnscaledLogicPosition + , const uno::Reference< beans::XPropertySet > & xErrorBarProperties + , const VDataSeries& rVDataSeries + , sal_Int32 nIndex + , bool bYError /* = true */ + , const double* pfScaledLogicX + ) +{ + if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) ) + return; + + if( ! xErrorBarProperties.is()) + return; + + try + { + bool bShowPositive = false; + bool bShowNegative = false; + sal_Int32 nErrorBarStyle = css::chart::ErrorBarStyle::VARIANCE; + + xErrorBarProperties->getPropertyValue( "ShowPositiveError") >>= bShowPositive; + xErrorBarProperties->getPropertyValue( "ShowNegativeError") >>= bShowNegative; + xErrorBarProperties->getPropertyValue( "ErrorBarStyle") >>= nErrorBarStyle; + + if(!bShowPositive && !bShowNegative) + return; + + if(nErrorBarStyle==css::chart::ErrorBarStyle::NONE) + return; + + if (!m_pPosHelper) + return; + + drawing::Position3D aUnscaledLogicPosition(rUnscaledLogicPosition); + if(nErrorBarStyle==css::chart::ErrorBarStyle::STANDARD_DEVIATION) + { + if (bYError) + aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue(); + else + aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue(); + } + + bool bCreateNegativeBorder = false;//make a vertical line at the negative end of the error bar + bool bCreatePositiveBorder = false;//make a vertical line at the positive end of the error bar + drawing::Position3D aMiddle(aUnscaledLogicPosition); + const double fX = aUnscaledLogicPosition.PositionX; + const double fY = aUnscaledLogicPosition.PositionY; + const double fZ = aUnscaledLogicPosition.PositionZ; + double fScaledX = fX; + if( pfScaledLogicX ) + fScaledX = *pfScaledLogicX; + else + m_pPosHelper->doLogicScaling( &fScaledX, nullptr, nullptr ); + + aMiddle = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fY, fZ ); + + drawing::Position3D aNegative(aMiddle); + drawing::Position3D aPositive(aMiddle); + + uno::Sequence< double > aData( bYError ? rVDataSeries.getAllY() : rVDataSeries.getAllX() ); + + if( bShowPositive ) + { + double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, true, bYError ); + if( std::isfinite( fLength ) ) + { + double fLocalX = fX; + double fLocalY = fY; + if( bYError ) + { + fLocalY+=fLength; + aPositive = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ ); + } + else + { + fLocalX+=fLength; + aPositive = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true ); + } + bCreatePositiveBorder = m_pPosHelper->isLogicVisible(fLocalX, fLocalY, fZ); + } + else + bShowPositive = false; + } + + if( bShowNegative ) + { + double fLength = lcl_getErrorBarLogicLength( aData, xErrorBarProperties, nErrorBarStyle, nIndex, false, bYError ); + if( std::isfinite( fLength ) ) + { + double fLocalX = fX; + double fLocalY = fY; + if( bYError ) + { + fLocalY-=fLength; + aNegative = lcl_transformMixedToScene( m_pPosHelper, fScaledX, fLocalY, fZ ); + } + else + { + fLocalX-=fLength; + aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true ); + } + if (std::isfinite(aNegative.PositionX) && + std::isfinite(aNegative.PositionY) && + std::isfinite(aNegative.PositionZ)) { + bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ); + } else { + // If error bars result in a numerical problem (e.g., an + // error bar on a logarithmic chart that results in a point + // <= 0) then just turn off the error bar. + // + // TODO: This perhaps should display a warning, so the user + // knows why a bar is not appearing. + // TODO: This test could also be added to the positive case, + // though a numerical overflow there is less likely. + bShowNegative = false; + } + } + else + bShowNegative = false; + } + + if(!bShowPositive && !bShowNegative) + return; + + std::vector> aPoly; + + sal_Int32 nSequenceIndex=0; + if( bShowNegative ) + AddPointToPoly( aPoly, aNegative, nSequenceIndex ); + AddPointToPoly( aPoly, aMiddle, nSequenceIndex ); + if( bShowPositive ) + AddPointToPoly( aPoly, aPositive, nSequenceIndex ); + + if( bShowNegative && bCreateNegativeBorder ) + { + ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aNegative, m_pPosHelper, aUnscaledLogicPosition, bYError ); + nSequenceIndex++; + lcl_AddErrorBottomLine( aNegative, aMainDirection, aPoly, nSequenceIndex ); + } + if( bShowPositive && bCreatePositiveBorder ) + { + ::basegfx::B2DVector aMainDirection = lcl_getErrorBarMainDirection( aMiddle, aPositive, m_pPosHelper, aUnscaledLogicPosition, bYError ); + nSequenceIndex++; + lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex ); + } + + rtl::Reference xShape = ShapeFactory::createLine2D( xTarget, aPoly ); + PropertyMapper::setMappedProperties( *xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() ); + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + +} + +void VSeriesPlotter::addErrorBorder( + const drawing::Position3D& rPos0 + ,const drawing::Position3D& rPos1 + ,const rtl::Reference& rTarget + ,const uno::Reference< beans::XPropertySet >& rErrorBorderProp ) +{ + std::vector> aPoly { { rPos0, rPos1} }; + rtl::Reference xShape = ShapeFactory::createLine2D( + rTarget, aPoly ); + PropertyMapper::setMappedProperties( *xShape, rErrorBorderProp, + PropertyMapper::getPropertyNameMapForLineProperties() ); +} + +void VSeriesPlotter::createErrorRectangle( + const drawing::Position3D& rUnscaledLogicPosition + ,VDataSeries& rVDataSeries + ,sal_Int32 nIndex + ,const rtl::Reference& rTarget + ,bool bUseXErrorData + ,bool bUseYErrorData ) +{ + if ( m_nDimension != 2 ) + return; + + // error border properties + Reference< beans::XPropertySet > xErrorBorderPropX, xErrorBorderPropY; + if ( bUseXErrorData ) + { + xErrorBorderPropX = rVDataSeries.getXErrorBarProperties( nIndex ); + if ( !xErrorBorderPropX.is() ) + return; + } + rtl::Reference xErrorBorder_ShapesX = + getErrorBarsGroupShape( rVDataSeries, rTarget, false ); + + if ( bUseYErrorData ) + { + xErrorBorderPropY = rVDataSeries.getYErrorBarProperties( nIndex ); + if ( !xErrorBorderPropY.is() ) + return; + } + rtl::Reference xErrorBorder_ShapesY = + getErrorBarsGroupShape( rVDataSeries, rTarget, true ); + + if( !ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ) ) + return; + + try + { + bool bShowXPositive = false; + bool bShowXNegative = false; + bool bShowYPositive = false; + bool bShowYNegative = false; + + sal_Int32 nErrorBorderStyleX = css::chart::ErrorBarStyle::VARIANCE; + sal_Int32 nErrorBorderStyleY = css::chart::ErrorBarStyle::VARIANCE; + + if ( bUseXErrorData ) + { + xErrorBorderPropX->getPropertyValue( "ErrorBarStyle" ) >>= nErrorBorderStyleX; + xErrorBorderPropX->getPropertyValue( "ShowPositiveError") >>= bShowXPositive; + xErrorBorderPropX->getPropertyValue( "ShowNegativeError") >>= bShowXNegative; + } + if ( bUseYErrorData ) + { + xErrorBorderPropY->getPropertyValue( "ErrorBarStyle" ) >>= nErrorBorderStyleY; + xErrorBorderPropY->getPropertyValue( "ShowPositiveError") >>= bShowYPositive; + xErrorBorderPropY->getPropertyValue( "ShowNegativeError") >>= bShowYNegative; + } + + if ( bUseXErrorData && nErrorBorderStyleX == css::chart::ErrorBarStyle::NONE ) + bUseXErrorData = false; + if ( bUseYErrorData && nErrorBorderStyleY == css::chart::ErrorBarStyle::NONE ) + bUseYErrorData = false; + + if ( !bShowXPositive && !bShowXNegative && !bShowYPositive && !bShowYNegative ) + return; + + if ( !m_pPosHelper ) + return; + + drawing::Position3D aUnscaledLogicPosition( rUnscaledLogicPosition ); + if ( bUseXErrorData && nErrorBorderStyleX == css::chart::ErrorBarStyle::STANDARD_DEVIATION ) + aUnscaledLogicPosition.PositionX = rVDataSeries.getXMeanValue(); + if ( bUseYErrorData && nErrorBorderStyleY == css::chart::ErrorBarStyle::STANDARD_DEVIATION ) + aUnscaledLogicPosition.PositionY = rVDataSeries.getYMeanValue(); + + const double fX = aUnscaledLogicPosition.PositionX; + const double fY = aUnscaledLogicPosition.PositionY; + const double fZ = aUnscaledLogicPosition.PositionZ; + double fScaledX = fX; + m_pPosHelper->doLogicScaling( &fScaledX, nullptr, nullptr ); + + uno::Sequence< double > aDataX( rVDataSeries.getAllX() ); + uno::Sequence< double > aDataY( rVDataSeries.getAllY() ); + + double fPosX = 0.0; + double fPosY = 0.0; + double fNegX = 0.0; + double fNegY = 0.0; + if ( bUseXErrorData ) + { + if ( bShowXPositive ) + fPosX = lcl_getErrorBarLogicLength( aDataX, xErrorBorderPropX, + nErrorBorderStyleX, nIndex, true, false ); + if ( bShowXNegative ) + fNegX = lcl_getErrorBarLogicLength( aDataX, xErrorBorderPropX, + nErrorBorderStyleX, nIndex, false, false ); + } + + if ( bUseYErrorData ) + { + if ( bShowYPositive ) + fPosY = lcl_getErrorBarLogicLength( aDataY, xErrorBorderPropY, + nErrorBorderStyleY, nIndex, true, true ); + if ( bShowYNegative ) + fNegY = lcl_getErrorBarLogicLength( aDataY, xErrorBorderPropY, + nErrorBorderStyleY, nIndex, false, true ); + } + + if ( !( std::isfinite( fPosX ) && + std::isfinite( fPosY ) && + std::isfinite( fNegX ) && + std::isfinite( fNegY ) ) ) + return; + + drawing::Position3D aBottomLeft( lcl_transformMixedToScene( m_pPosHelper, + fX - fNegX, fY - fNegY, fZ ) ); + drawing::Position3D aTopLeft( lcl_transformMixedToScene( m_pPosHelper, + fX - fNegX, fY + fPosY, fZ ) ); + drawing::Position3D aTopRight( lcl_transformMixedToScene( m_pPosHelper, + fX + fPosX, fY + fPosY, fZ ) ); + drawing::Position3D aBottomRight( lcl_transformMixedToScene( m_pPosHelper, + fX + fPosX, fY - fNegY, fZ ) ); + if ( bUseXErrorData ) + { + // top border + addErrorBorder( aTopLeft, aTopRight, xErrorBorder_ShapesX, xErrorBorderPropX ); + + // bottom border + addErrorBorder( aBottomRight, aBottomLeft, xErrorBorder_ShapesX, xErrorBorderPropX ); + } + + if ( bUseYErrorData ) + { + // left border + addErrorBorder( aBottomLeft, aTopLeft, xErrorBorder_ShapesY, xErrorBorderPropY ); + + // right border + addErrorBorder( aTopRight, aBottomRight, xErrorBorder_ShapesY, xErrorBorderPropY ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2", "Exception in createErrorRectangle(). "); + } +} + +void VSeriesPlotter::createErrorBar_X( const drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries, sal_Int32 nPointIndex + , const rtl::Reference& xTarget ) +{ + if(m_nDimension!=2) + return; + // error bars + uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getXErrorBarProperties(nPointIndex)); + if( xErrorBarProp.is()) + { + rtl::Reference xErrorBarsGroup_Shapes = + getErrorBarsGroupShape(rVDataSeries, xTarget, false); + + createErrorBar( xErrorBarsGroup_Shapes + , rUnscaledLogicPosition, xErrorBarProp + , rVDataSeries, nPointIndex + , false /* bYError */ + , nullptr ); + } +} + +void VSeriesPlotter::createErrorBar_Y( const drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries, sal_Int32 nPointIndex + , const rtl::Reference& xTarget + , double const * pfScaledLogicX ) +{ + if(m_nDimension!=2) + return; + // error bars + uno::Reference< beans::XPropertySet > xErrorBarProp(rVDataSeries.getYErrorBarProperties(nPointIndex)); + if( xErrorBarProp.is()) + { + rtl::Reference xErrorBarsGroup_Shapes = + getErrorBarsGroupShape(rVDataSeries, xTarget, true); + + createErrorBar( xErrorBarsGroup_Shapes + , rUnscaledLogicPosition, xErrorBarProp + , rVDataSeries, nPointIndex + , true /* bYError */ + , pfScaledLogicX ); + } +} + +void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries const & rVDataSeries, + const rtl::Reference& xTarget, + const rtl::Reference& xEquationTarget, + bool bMaySkipPoints ) +{ + if(m_nDimension!=2) + return; + rtl::Reference< DataSeries > xContainer( rVDataSeries.getModel() ); + if(!xContainer.is()) + return; + + if (!m_pPosHelper) + return; + + const std::vector< rtl::Reference< ::chart::RegressionCurveModel > > & aCurveList = xContainer->getRegressionCurves2(); + + for(std::size_t nN=0; nN xCalculator( rCurve->getCalculator() ); + if( !xCalculator.is()) + continue; + + bool bAverageLine = RegressionCurveHelper::isMeanValueLine( rCurve ); + + sal_Int32 aDegree = 2; + sal_Int32 aPeriod = 2; + sal_Int32 aMovingAverageType = css::chart2::MovingAverageType::Prior; + double aExtrapolateForward = 0.0; + double aExtrapolateBackward = 0.0; + bool bForceIntercept = false; + double aInterceptValue = 0.0; + + if ( !bAverageLine ) + { + rCurve->getPropertyValue( "PolynomialDegree") >>= aDegree; + rCurve->getPropertyValue( "MovingAveragePeriod") >>= aPeriod; + rCurve->getPropertyValue( "MovingAverageType") >>= aMovingAverageType; + rCurve->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward; + rCurve->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward; + rCurve->getPropertyValue( "ForceIntercept") >>= bForceIntercept; + if (bForceIntercept) + rCurve->getPropertyValue( "InterceptValue") >>= aInterceptValue; + } + + double fChartMinX = m_pPosHelper->getLogicMinX(); + double fChartMaxX = m_pPosHelper->getLogicMaxX(); + + double fMinX = fChartMinX; + double fMaxX = fChartMaxX; + + double fPointScale = 1.0; + + if( !bAverageLine ) + { + rVDataSeries.getMinMaxXValue(fMinX, fMaxX); + fMaxX += aExtrapolateForward; + fMinX -= aExtrapolateBackward; + + fPointScale = (fMaxX - fMinX) / (fChartMaxX - fChartMinX); + // sanitize the value, tdf#119922 + fPointScale = std::min(fPointScale, 1000.0); + } + + xCalculator->setRegressionProperties(aDegree, bForceIntercept, aInterceptValue, aPeriod, + aMovingAverageType); + xCalculator->recalculateRegression(rVDataSeries.getAllX(), rVDataSeries.getAllY()); + sal_Int32 nPointCount = 100 * fPointScale; + + if ( nPointCount < 2 ) + nPointCount = 2; + + std::vector< ExplicitScaleData > aScales( m_pPosHelper->getScales()); + uno::Reference< chart2::XScaling > xScalingX; + uno::Reference< chart2::XScaling > xScalingY; + if( aScales.size() >= 2 ) + { + xScalingX.set( aScales[0].Scaling ); + xScalingY.set( aScales[1].Scaling ); + } + + const uno::Sequence< geometry::RealPoint2D > aCalculatedPoints( + xCalculator->getCurveValues( + fMinX, fMaxX, nPointCount, + xScalingX, xScalingY, bMaySkipPoints )); + + nPointCount = aCalculatedPoints.getLength(); + + drawing::PolyPolygonShape3D aRegressionPoly; + aRegressionPoly.SequenceX.realloc(1); + aRegressionPoly.SequenceY.realloc(1); + aRegressionPoly.SequenceZ.realloc(1); + auto pSequenceX = aRegressionPoly.SequenceX.getArray(); + auto pSequenceY = aRegressionPoly.SequenceY.getArray(); + auto pSequenceZ = aRegressionPoly.SequenceZ.getArray(); + pSequenceX[0].realloc(nPointCount); + pSequenceY[0].realloc(nPointCount); + auto pSequenceX0 = pSequenceX[0].getArray(); + auto pSequenceY0 = pSequenceY[0].getArray(); + + sal_Int32 nRealPointCount = 0; + + for(geometry::RealPoint2D const & p : aCalculatedPoints) + { + double fLogicX = p.X; + double fLogicY = p.Y; + double fLogicZ = 0.0; //dummy + + // fdo#51656: don't scale mean value lines + if(!bAverageLine) + m_pPosHelper->doLogicScaling( &fLogicX, &fLogicY, &fLogicZ ); + + if(!std::isnan(fLogicX) && !std::isinf(fLogicX) && + !std::isnan(fLogicY) && !std::isinf(fLogicY) && + !std::isnan(fLogicZ) && !std::isinf(fLogicZ) ) + { + pSequenceX0[nRealPointCount] = fLogicX; + pSequenceY0[nRealPointCount] = fLogicY; + nRealPointCount++; + } + } + pSequenceX[0].realloc(nRealPointCount); + pSequenceY[0].realloc(nRealPointCount); + pSequenceZ[0].realloc(nRealPointCount); + + drawing::PolyPolygonShape3D aClippedPoly; + Clipping::clipPolygonAtRectangle( aRegressionPoly, m_pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly ); + aRegressionPoly = aClippedPoly; + m_pPosHelper->transformScaledLogicToScene( aRegressionPoly ); + + awt::Point aDefaultPos; + if( aRegressionPoly.SequenceX.hasElements() && aRegressionPoly.SequenceX[0].hasElements() ) + { + VLineProperties aVLineProperties; + aVLineProperties.initFromPropertySet( rCurve ); + + //create an extra group shape for each curve for selection handling + rtl::Reference xRegressionGroupShapes = + createGroupShape( xTarget, rVDataSeries.getDataCurveCID( nN, bAverageLine ) ); + rtl::Reference xShape = ShapeFactory::createLine2D( + xRegressionGroupShapes, PolyToPointSequence( aRegressionPoly ), &aVLineProperties ); + ShapeFactory::setShapeName( xShape, "MarkHandles" ); + aDefaultPos = xShape->getPosition(); + } + + // curve equation and correlation coefficient + uno::Reference< beans::XPropertySet > xEquationProperties( rCurve->getEquationProperties()); + if( xEquationProperties.is()) + { + createRegressionCurveEquationShapes( + rVDataSeries.getDataCurveEquationCID( nN ), + xEquationProperties, xEquationTarget, xCalculator, + aDefaultPos ); + } + } +} + +static sal_Int32 lcl_getOUStringMaxLineLength ( OUStringBuffer const & aString ) +{ + const sal_Int32 nStringLength = aString.getLength(); + sal_Int32 nMaxLineLength = 0; + + for ( sal_Int32 i=0; i nMaxLineLength ) + nMaxLineLength = nLineLength; + i = indexSep; + } + + return nMaxLineLength; +} + +void VSeriesPlotter::createRegressionCurveEquationShapes( + const OUString & rEquationCID, + const uno::Reference< beans::XPropertySet > & xEquationProperties, + const rtl::Reference& xEquationTarget, + const uno::Reference< chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator, + awt::Point aDefaultPos ) +{ + OSL_ASSERT( xEquationProperties.is()); + if( !xEquationProperties.is()) + return; + + bool bShowEquation = false; + bool bShowCorrCoeff = false; + if(!(( xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation ) && + ( xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowCorrCoeff ))) + return; + + if( ! (bShowEquation || bShowCorrCoeff)) + return; + + OUStringBuffer aFormula; + sal_Int32 nNumberFormatKey = 0; + sal_Int32 nFormulaWidth = 0; + xEquationProperties->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nNumberFormatKey; + bool bResizeEquation = true; + sal_Int32 nMaxIteration = 2; + if ( bShowEquation ) + { + OUString aXName, aYName; + if ( !(xEquationProperties->getPropertyValue( "XName" ) >>= aXName) ) + aXName = OUString( "x" ); + if ( !(xEquationProperties->getPropertyValue( "YName" ) >>= aYName) ) + aYName = OUString( "f(x)" ); + xRegressionCurveCalculator->setXYNames( aXName, aYName ); + } + + for ( sal_Int32 nCountIteration = 0; bResizeEquation && nCountIteration < nMaxIteration ; nCountIteration++ ) + { + bResizeEquation = false; + if( bShowEquation ) + { + if (m_apNumberFormatterWrapper) + { // iteration 0: default representation (no wrap) + // iteration 1: expected width (nFormulaWidth) is calculated + aFormula = xRegressionCurveCalculator->getFormattedRepresentation( + m_apNumberFormatterWrapper->getNumberFormatsSupplier(), + nNumberFormatKey, nFormulaWidth ); + nFormulaWidth = lcl_getOUStringMaxLineLength( aFormula ); + } + else + { + aFormula = xRegressionCurveCalculator->getRepresentation(); + } + + if( bShowCorrCoeff ) + { + aFormula.append( "\n" ); + } + } + if( bShowCorrCoeff ) + { + aFormula.append( "R" + OUStringChar( aSuperscriptFigures[2] ) + " = " ); + double fR( xRegressionCurveCalculator->getCorrelationCoefficient()); + if (m_apNumberFormatterWrapper) + { + Color nLabelCol; + bool bColChanged; + aFormula.append( + m_apNumberFormatterWrapper->getFormattedString( + nNumberFormatKey, fR*fR, nLabelCol, bColChanged )); + //@todo: change color of label if bColChanged is true + } + else + { + const LocaleDataWrapper& rLocaleDataWrapper = Application::GetSettings().GetLocaleDataWrapper(); + const OUString& aNumDecimalSep = rLocaleDataWrapper.getNumDecimalSep(); + sal_Unicode aDecimalSep = aNumDecimalSep[0]; + aFormula.append( ::rtl::math::doubleToUString( + fR*fR, rtl_math_StringFormat_G, 4, aDecimalSep, true )); + } + } + + awt::Point aScreenPosition2D; + chart2::RelativePosition aRelativePosition; + if( xEquationProperties->getPropertyValue( "RelativePosition") >>= aRelativePosition ) + { + //@todo decide whether x is primary or secondary + double fX = aRelativePosition.Primary*m_aPageReferenceSize.Width; + double fY = aRelativePosition.Secondary*m_aPageReferenceSize.Height; + aScreenPosition2D.X = static_cast< sal_Int32 >( ::rtl::math::round( fX )); + aScreenPosition2D.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY )); + } + else + aScreenPosition2D = aDefaultPos; + + if( !aFormula.isEmpty()) + { + // set fill and line properties on creation + tNameSequence aNames; + tAnySequence aValues; + PropertyMapper::getPreparedTextShapePropertyLists( xEquationProperties, aNames, aValues ); + + rtl::Reference xTextShape = ShapeFactory::createText( + xEquationTarget, aFormula.makeStringAndClear(), + aNames, aValues, ShapeFactory::makeTransformation( aScreenPosition2D )); + + ShapeFactory::setShapeName( xTextShape, rEquationCID ); + awt::Size aSize( xTextShape->getSize() ); + awt::Point aPos( RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + aScreenPosition2D, aSize, aRelativePosition.Anchor ) ); + //ensure that the equation is fully placed within the page (if possible) + if( (aPos.X + aSize.Width) > m_aPageReferenceSize.Width ) + aPos.X = m_aPageReferenceSize.Width - aSize.Width; + if( aPos.X < 0 ) + { + aPos.X = 0; + if ( nFormulaWidth > 0 ) + { + bResizeEquation = true; + if ( nCountIteration < nMaxIteration-1 ) + xEquationTarget->remove( xTextShape ); // remove equation + nFormulaWidth *= m_aPageReferenceSize.Width / static_cast< double >(aSize.Width); + nFormulaWidth -= nCountIteration; + if ( nFormulaWidth < 0 ) + nFormulaWidth = 0; + } + } + if( (aPos.Y + aSize.Height) > m_aPageReferenceSize.Height ) + aPos.Y = m_aPageReferenceSize.Height - aSize.Height; + if( aPos.Y < 0 ) + aPos.Y = 0; + if ( !bResizeEquation || nCountIteration == nMaxIteration-1 ) + xTextShape->setPosition(aPos); // if equation was not removed + } + } +} + +void VSeriesPlotter::setTimeResolutionOnXAxis( tools::Long TimeResolution, const Date& rNullDate ) +{ + m_nTimeResolution = TimeResolution; + m_aNullDate = rNullDate; +} + +// MinimumAndMaximumSupplier +tools::Long VSeriesPlotter::calculateTimeResolutionOnXAxis() +{ + tools::Long nRet = css::chart::TimeUnit::YEAR; + if (!m_pExplicitCategoriesProvider) + return nRet; + + const std::vector& rDateCategories = m_pExplicitCategoriesProvider->getDateCategories(); + if (rDateCategories.empty()) + return nRet; + + std::vector::const_iterator aIt = rDateCategories.begin(), aEnd = rDateCategories.end(); + + aIt = std::find_if(aIt, aEnd, [](const double& rDateCategory) { return !std::isnan(rDateCategory); }); + if (aIt == aEnd) + return nRet; + + Date aNullDate(30,12,1899); + if (m_apNumberFormatterWrapper) + aNullDate = m_apNumberFormatterWrapper->getNullDate(); + + Date aPrevious(aNullDate); aPrevious.AddDays(rtl::math::approxFloor(*aIt)); + ++aIt; + for(;aIt!=aEnd;++aIt) + { + if (std::isnan(*aIt)) + continue; + + Date aCurrent(aNullDate); aCurrent.AddDays(rtl::math::approxFloor(*aIt)); + if( nRet == css::chart::TimeUnit::YEAR ) + { + if( DateHelper::IsInSameYear( aPrevious, aCurrent ) ) + nRet = css::chart::TimeUnit::MONTH; + } + if( nRet == css::chart::TimeUnit::MONTH ) + { + if( DateHelper::IsInSameMonth( aPrevious, aCurrent ) ) + nRet = css::chart::TimeUnit::DAY; + } + if( nRet == css::chart::TimeUnit::DAY ) + break; + aPrevious=aCurrent; + } + + return nRet; +} +double VSeriesPlotter::getMinimumX() +{ + double fMinimum, fMaximum; + getMinimumAndMaximumX( fMinimum, fMaximum ); + return fMinimum; +} +double VSeriesPlotter::getMaximumX() +{ + double fMinimum, fMaximum; + getMinimumAndMaximumX( fMinimum, fMaximum ); + return fMaximum; +} + +double VSeriesPlotter::getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) ) + { + double fMinY, fMaxY; + getMinimumAndMaximumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex ); + return fMinY; + } + + double fMinimum = std::numeric_limits::infinity(); + double fMaximum = -std::numeric_limits::infinity(); + for(std::vector & rXSlots : m_aZSlots) + { + for(VDataSeriesGroup & rXSlot : rXSlots) + { + double fLocalMinimum, fLocalMaximum; + rXSlot.calculateYMinAndMaxForCategoryRange( + static_cast(fMinimumX-1.0) //first category (index 0) matches with real number 1.0 + , static_cast(fMaximumX-1.0) //first category (index 0) matches with real number 1.0 + , isSeparateStackingForDifferentSigns( 1 ) + , fLocalMinimum, fLocalMaximum, nAxisIndex ); + if(fMaximumfLocalMinimum) + fMinimum=fLocalMinimum; + } + } + if(std::isinf(fMinimum)) + return std::numeric_limits::quiet_NaN(); + return fMinimum; +} + +double VSeriesPlotter::getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) +{ + if( !m_bCategoryXAxis || ( m_pExplicitCategoriesProvider && m_pExplicitCategoriesProvider->isDateAxis() ) ) + { + double fMinY, fMaxY; + getMinimumAndMaximumYInContinuousXRange( fMinY, fMaxY, fMinimumX, fMaximumX, nAxisIndex ); + return fMaxY; + } + + double fMinimum = std::numeric_limits::infinity(); + double fMaximum = -std::numeric_limits::infinity(); + for( std::vector< VDataSeriesGroup > & rXSlots : m_aZSlots) + { + for(VDataSeriesGroup & rXSlot : rXSlots) + { + double fLocalMinimum, fLocalMaximum; + rXSlot.calculateYMinAndMaxForCategoryRange( + static_cast(fMinimumX-1.0) //first category (index 0) matches with real number 1.0 + , static_cast(fMaximumX-1.0) //first category (index 0) matches with real number 1.0 + , isSeparateStackingForDifferentSigns( 1 ) + , fLocalMinimum, fLocalMaximum, nAxisIndex ); + if(fMaximumfLocalMinimum) + fMinimum=fLocalMinimum; + } + } + if(std::isinf(fMaximum)) + return std::numeric_limits::quiet_NaN(); + return fMaximum; +} + +double VSeriesPlotter::getMinimumZ() +{ + //this is the default for all charts without a meaningful z axis + return 1.0; +} +double VSeriesPlotter::getMaximumZ() +{ + if( m_nDimension!=3 || m_aZSlots.empty() ) + return getMinimumZ()+1; + return m_aZSlots.size(); +} + +namespace +{ + bool lcl_isValueAxis( sal_Int32 nDimensionIndex, bool bCategoryXAxis ) + { + // default implementation: true for Y axes, and for value X axis + if( nDimensionIndex == 0 ) + return !bCategoryXAxis; + return nDimensionIndex == 1; + } +} + +bool VSeriesPlotter::isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) +{ + return lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis ); +} + +bool VSeriesPlotter::isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) +{ + // do not expand axes in 3D charts + return (m_nDimension < 3) && lcl_isValueAxis( nDimensionIndex, m_bCategoryXAxis ); +} + +bool VSeriesPlotter::isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) +{ + // default implementation: only for Y axis + return nDimensionIndex == 1; +} + +bool VSeriesPlotter::isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) +{ + // default implementation: only for Y axis + return nDimensionIndex == 1; +} + +bool VSeriesPlotter::isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) +{ + // default implementation: only for Y axis + return nDimensionIndex == 1; +} + +void VSeriesPlotter::getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const +{ + rfMinimum = std::numeric_limits::infinity(); + rfMaximum = -std::numeric_limits::infinity(); + + for (auto const& ZSlot : m_aZSlots) + { + for (auto const& XSlot : ZSlot) + { + double fLocalMinimum, fLocalMaximum; + XSlot.getMinimumAndMaximumX( fLocalMinimum, fLocalMaximum ); + if( !std::isnan(fLocalMinimum) && fLocalMinimum< rfMinimum ) + rfMinimum = fLocalMinimum; + if( !std::isnan(fLocalMaximum) && fLocalMaximum> rfMaximum ) + rfMaximum = fLocalMaximum; + } + } + if(std::isinf(rfMinimum)) + rfMinimum = std::numeric_limits::quiet_NaN(); + if(std::isinf(rfMaximum)) + rfMaximum = std::numeric_limits::quiet_NaN(); +} + +void VSeriesPlotter::getMinimumAndMaximumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const +{ + rfMinY = std::numeric_limits::infinity(); + rfMaxY = -std::numeric_limits::infinity(); + + for (auto const& ZSlot : m_aZSlots) + { + for (auto const& XSlot : ZSlot) + { + double fLocalMinimum, fLocalMaximum; + XSlot.getMinimumAndMaximumYInContinuousXRange( fLocalMinimum, fLocalMaximum, fMinX, fMaxX, nAxisIndex ); + if( !std::isnan(fLocalMinimum) && fLocalMinimum< rfMinY ) + rfMinY = fLocalMinimum; + if( !std::isnan(fLocalMaximum) && fLocalMaximum> rfMaxY ) + rfMaxY = fLocalMaximum; + } + } + if(std::isinf(rfMinY)) + rfMinY = std::numeric_limits::quiet_NaN(); + if(std::isinf(rfMaxY)) + rfMaxY = std::numeric_limits::quiet_NaN(); +} + +sal_Int32 VSeriesPlotter::getPointCount() const +{ + sal_Int32 nRet = 0; + + for (auto const& ZSlot : m_aZSlots) + { + for (auto const& XSlot : ZSlot) + { + sal_Int32 nPointCount = XSlot.getPointCount(); + if( nPointCount>nRet ) + nRet = nPointCount; + } + } + return nRet; +} + +void VSeriesPlotter::setNumberFormatsSupplier( + const uno::Reference< util::XNumberFormatsSupplier > & xNumFmtSupplier ) +{ + m_apNumberFormatterWrapper.reset( new NumberFormatterWrapper( xNumFmtSupplier )); +} + +void VSeriesPlotter::setColorScheme( const uno::Reference< XColorScheme >& xColorScheme ) +{ + m_xColorScheme = xColorScheme; +} + +void VSeriesPlotter::setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider ) +{ + m_pExplicitCategoriesProvider = pExplicitCategoriesProvider; +} + +sal_Int32 VDataSeriesGroup::getPointCount() const +{ + if(!m_bMaxPointCountDirty) + return m_nMaxPointCount; + + sal_Int32 nRet = 0; + + for (std::unique_ptr const & pSeries : m_aSeriesVector) + { + sal_Int32 nPointCount = pSeries->getTotalPointCount(); + if( nPointCount>nRet ) + nRet = nPointCount; + } + m_nMaxPointCount=nRet; + m_aListOfCachedYValues.clear(); + m_aListOfCachedYValues.resize(m_nMaxPointCount); + m_bMaxPointCountDirty=false; + return nRet; +} + +sal_Int32 VDataSeriesGroup::getAttachedAxisIndexForFirstSeries() const +{ + sal_Int32 nRet = 0; + + if (!m_aSeriesVector.empty()) + nRet = m_aSeriesVector[0]->getAttachedAxisIndex(); + + return nRet; +} + +void VDataSeriesGroup::getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const +{ + + rfMinimum = std::numeric_limits::infinity(); + rfMaximum = -std::numeric_limits::infinity(); + + for (std::unique_ptr const & pSeries : m_aSeriesVector) + { + sal_Int32 nPointCount = pSeries->getTotalPointCount(); + for(sal_Int32 nN=0;nNgetXValue( nN ); + if( std::isnan(fX) ) + continue; + if(rfMaximumfX) + rfMinimum=fX; + } + } + if(std::isinf(rfMinimum)) + rfMinimum = std::numeric_limits::quiet_NaN(); + if(std::isinf(rfMaximum)) + rfMaximum = std::numeric_limits::quiet_NaN(); +} + +namespace { + +/** + * Keep track of minimum and maximum Y values for one or more data series. + * When multiple data series exist, that indicates that the data series are + * stacked. + * + *

For each X value, we calculate separate Y value ranges for each data + * series in the first pass. In the second pass, we calculate the minimum Y + * value by taking the absolute minimum value of all data series, whereas + * the maximum Y value is the sum of all the series maximum Y values.

+ * + *

Once that's done for all X values, the final min / max Y values get + * calculated by taking the absolute min / max Y values across all the X + * values.

+ */ +class PerXMinMaxCalculator +{ + typedef std::pair MinMaxType; + typedef std::map SeriesMinMaxType; + typedef std::map GroupMinMaxType; + typedef std::unordered_map TotalStoreType; + GroupMinMaxType m_SeriesGroup; + size_t mnCurSeries; + +public: + PerXMinMaxCalculator() : mnCurSeries(0) {} + + void nextSeries() { ++mnCurSeries; } + + void setValue(double fX, double fY) + { + SeriesMinMaxType* pStore = getByXValue(fX); // get storage for given X value. + if (!pStore) + // This shouldn't happen! + return; + + SeriesMinMaxType::iterator it = pStore->lower_bound(mnCurSeries); + if (it != pStore->end() && !pStore->key_comp()(mnCurSeries, it->first)) + { + MinMaxType& r = it->second; + // A min-max pair already exists for this series. Update it. + if (fY < r.first) + r.first = fY; + if (r.second < fY) + r.second = fY; + } + else + { + // No existing pair. Insert a new one. + pStore->insert( + it, SeriesMinMaxType::value_type( + mnCurSeries, MinMaxType(fY,fY))); + } + } + + void getTotalRange(double& rfMin, double& rfMax) const + { + TotalStoreType aStore; + getTotalStore(aStore); + + if (aStore.empty()) + { + rfMin = std::numeric_limits::quiet_NaN(); + rfMax = std::numeric_limits::quiet_NaN(); + return; + } + + TotalStoreType::const_iterator it = aStore.begin(), itEnd = aStore.end(); + rfMin = it->second.first; + rfMax = it->second.second; + for (++it; it != itEnd; ++it) + { + if (rfMin > it->second.first) + rfMin = it->second.first; + if (rfMax < it->second.second) + rfMax = it->second.second; + } + } + +private: + /** + * Parse all data and reduce them into a set of global Y value ranges per + * X value. + */ + void getTotalStore(TotalStoreType& rStore) const + { + TotalStoreType aStore; + for (auto const& it : m_SeriesGroup) + { + double fX = it.first; + + const SeriesMinMaxType& rSeries = it.second; + for (auto const& series : rSeries) + { + double fYMin = series.second.first, fYMax = series.second.second; + TotalStoreType::iterator itr = aStore.find(fX); + if (itr == aStore.end()) + // New min-max pair for give X value. + aStore.emplace(fX, std::pair(fYMin,fYMax)); + else + { + MinMaxType& r = itr->second; + if (fYMin < r.first) + r.first = fYMin; // min y-value + + r.second += fYMax; // accumulative max y-value. + } + } + } + rStore.swap(aStore); + } + + SeriesMinMaxType* getByXValue(double fX) + { + GroupMinMaxType::iterator it = m_SeriesGroup.find(fX); + if (it == m_SeriesGroup.end()) + { + std::pair r = + m_SeriesGroup.insert(std::make_pair(fX, SeriesMinMaxType{})); + + if (!r.second) + // insertion failed. + return nullptr; + + it = r.first; + } + + return &it->second; + } +}; + +} + +void VDataSeriesGroup::getMinimumAndMaximumYInContinuousXRange( + double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const +{ + rfMinY = std::numeric_limits::quiet_NaN(); + rfMaxY = std::numeric_limits::quiet_NaN(); + + if (m_aSeriesVector.empty()) + // No data series. Bail out. + return; + + PerXMinMaxCalculator aRangeCalc; + for (const std::unique_ptr & pSeries : m_aSeriesVector) + { + if (!pSeries) + continue; + + for (sal_Int32 i = 0, n = pSeries->getTotalPointCount(); i < n; ++i) + { + if (nAxisIndex != pSeries->getAttachedAxisIndex()) + continue; + + double fX = pSeries->getXValue(i); + if (std::isnan(fX)) + continue; + + if (fX < fMinX || fX > fMaxX) + // Outside specified X range. Skip it. + continue; + + double fY = pSeries->getYValue(i); + if (std::isnan(fY)) + continue; + + aRangeCalc.setValue(fX, fY); + } + aRangeCalc.nextSeries(); + } + + aRangeCalc.getTotalRange(rfMinY, rfMaxY); +} + +void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex + , bool bSeparateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) const +{ + assert(nCategoryIndex >= 0); + assert(nCategoryIndex < getPointCount()); + + rfMinimumY = std::numeric_limits::infinity(); + rfMaximumY = -std::numeric_limits::infinity(); + + if(m_aSeriesVector.empty()) + return; + + CachedYValues aCachedYValues = m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]; + if( !aCachedYValues.m_bValuesDirty ) + { + //return cached values + rfMinimumY = aCachedYValues.m_fMinimumY; + rfMaximumY = aCachedYValues.m_fMaximumY; + return; + } + + double fTotalSum = std::numeric_limits::quiet_NaN(); + double fPositiveSum = std::numeric_limits::quiet_NaN(); + double fNegativeSum = std::numeric_limits::quiet_NaN(); + double fFirstPositiveY = std::numeric_limits::quiet_NaN(); + double fFirstNegativeY = std::numeric_limits::quiet_NaN(); + + if( bSeparateStackingForDifferentSigns ) + { + for (const std::unique_ptr & pSeries: m_aSeriesVector) + { + if( nAxisIndex != pSeries->getAttachedAxisIndex() ) + continue; + + double fValueMinY = pSeries->getMinimumofAllDifferentYValues( nCategoryIndex ); + double fValueMaxY = pSeries->getMaximumofAllDifferentYValues( nCategoryIndex ); + + if( fValueMaxY >= 0 ) + { + if( std::isnan( fPositiveSum ) ) + fPositiveSum = fFirstPositiveY = fValueMaxY; + else + fPositiveSum += fValueMaxY; + } + if( fValueMinY < 0 ) + { + if(std::isnan( fNegativeSum )) + fNegativeSum = fFirstNegativeY = fValueMinY; + else + fNegativeSum += fValueMinY; + } + } + rfMinimumY = std::isnan( fNegativeSum ) ? fFirstPositiveY : fNegativeSum; + rfMaximumY = std::isnan( fPositiveSum ) ? fFirstNegativeY : fPositiveSum; + } + else + { + for (const std::unique_ptr & pSeries: m_aSeriesVector) + { + if( nAxisIndex != pSeries->getAttachedAxisIndex() ) + continue; + + double fValueMinY = pSeries->getMinimumofAllDifferentYValues( nCategoryIndex ); + double fValueMaxY = pSeries->getMaximumofAllDifferentYValues( nCategoryIndex ); + + if( std::isnan( fTotalSum ) ) + { + rfMinimumY = fValueMinY; + rfMaximumY = fTotalSum = fValueMaxY; + } + else + { + fTotalSum += fValueMaxY; + if( rfMinimumY > fTotalSum ) + rfMinimumY = fTotalSum; + if( rfMaximumY < fTotalSum ) + rfMaximumY = fTotalSum; + } + } + } + + aCachedYValues.m_fMinimumY = rfMinimumY; + aCachedYValues.m_fMaximumY = rfMaximumY; + aCachedYValues.m_bValuesDirty = false; + m_aListOfCachedYValues[nCategoryIndex][nAxisIndex]=aCachedYValues; +} + +void VDataSeriesGroup::calculateYMinAndMaxForCategoryRange( + sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex + , bool bSeparateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) +{ + //@todo maybe cache these values + rfMinimumY = std::numeric_limits::infinity(); + rfMaximumY = -std::numeric_limits::infinity(); + + //iterate through the given categories + if(nStartCategoryIndex<0) + nStartCategoryIndex=0; + const sal_Int32 nPointCount = getPointCount();//necessary to create m_aListOfCachedYValues + if(nPointCount <= 0) + return; + if (nEndCategoryIndex >= nPointCount) + nEndCategoryIndex = nPointCount - 1; + if(nEndCategoryIndex<0) + nEndCategoryIndex=0; + for( sal_Int32 nCatIndex = nStartCategoryIndex; nCatIndex <= nEndCategoryIndex; nCatIndex++ ) + { + double fMinimumY = std::numeric_limits::quiet_NaN(); + double fMaximumY = std::numeric_limits::quiet_NaN(); + + calculateYMinAndMaxForCategory( nCatIndex + , bSeparateStackingForDifferentSigns, fMinimumY, fMaximumY, nAxisIndex ); + + if(rfMinimumY > fMinimumY) + rfMinimumY = fMinimumY; + if(rfMaximumY < fMaximumY) + rfMaximumY = fMaximumY; + } +} + +double VSeriesPlotter::getTransformedDepth() const +{ + double MinZ = m_pMainPosHelper->getLogicMinZ(); + double MaxZ = m_pMainPosHelper->getLogicMaxZ(); + m_pMainPosHelper->doLogicScaling( nullptr, nullptr, &MinZ ); + m_pMainPosHelper->doLogicScaling( nullptr, nullptr, &MaxZ ); + return FIXED_SIZE_FOR_3D_CHART_VOLUME/(MaxZ-MinZ); +} + +void VSeriesPlotter::addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex ) +{ + if( nAxisIndex<1 ) + return; + + m_aSecondaryValueScales[nAxisIndex]=rScale; +} + +PlottingPositionHelper& VSeriesPlotter::getPlottingPositionHelper( sal_Int32 nAxisIndex ) const +{ + PlottingPositionHelper* pRet = nullptr; + if(nAxisIndex>0) + { + tSecondaryPosHelperMap::const_iterator aPosIt = m_aSecondaryPosHelperMap.find( nAxisIndex ); + if( aPosIt != m_aSecondaryPosHelperMap.end() ) + { + pRet = aPosIt->second.get(); + } + else if (m_pPosHelper) + { + tSecondaryValueScales::const_iterator aScaleIt = m_aSecondaryValueScales.find( nAxisIndex ); + if( aScaleIt != m_aSecondaryValueScales.end() ) + { + m_aSecondaryPosHelperMap[nAxisIndex] = m_pPosHelper->createSecondaryPosHelper( aScaleIt->second ); + pRet = m_aSecondaryPosHelperMap[nAxisIndex].get(); + } + } + } + if( !pRet ) + pRet = m_pMainPosHelper; + pRet->setTimeResolution( m_nTimeResolution, m_aNullDate ); + return *pRet; +} + +void VSeriesPlotter::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& /*rPageSize*/ ) +{ +} + +VDataSeries* VSeriesPlotter::getFirstSeries() const +{ + for (std::vector const & rGroup : m_aZSlots) + { + if (!rGroup.empty()) + { + if (!rGroup[0].m_aSeriesVector.empty()) + { + VDataSeries* pSeries = rGroup[0].m_aSeriesVector[0].get(); + if (pSeries) + return pSeries; + } + } + } + return nullptr; +} + +OUString VSeriesPlotter::getCategoryName( sal_Int32 nPointIndex ) const +{ + if (m_pExplicitCategoriesProvider) + { + Sequence< OUString > aCategories(m_pExplicitCategoriesProvider->getSimpleCategories()); + if (nPointIndex >= 0 && nPointIndex < aCategories.getLength()) + { + return aCategories[nPointIndex]; + } + } + return OUString(); +} + +std::vector VSeriesPlotter::getAllSeries() const +{ + std::vector aAllSeries; + for (std::vector const & rXSlot : m_aZSlots) + { + for(VDataSeriesGroup const & rGroup : rXSlot) + { + for (std::unique_ptr const & p : rGroup.m_aSeriesVector) + aAllSeries.push_back(p.get()); + } + } + return aAllSeries; +} + +std::vector VSeriesPlotter::getAllSeries() +{ + std::vector aAllSeries; + for (std::vector const & rXSlot : m_aZSlots) + { + for(VDataSeriesGroup const & rGroup : rXSlot) + { + for (std::unique_ptr const & p : rGroup.m_aSeriesVector) + aAllSeries.push_back(p.get()); + } + } + return aAllSeries; +} + +uno::Sequence VSeriesPlotter::getSeriesNames() const +{ + std::vector aRetVector; + + OUString aRole; + if (m_xChartTypeModel.is()) + aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel(); + + for (auto const& rGroup : m_aZSlots) + { + if (!rGroup.empty()) + { + VDataSeriesGroup const & rSeriesGroup(rGroup[0]); + if (!rSeriesGroup.m_aSeriesVector.empty()) + { + VDataSeries const * pSeries = rSeriesGroup.m_aSeriesVector[0].get(); + rtl::Reference< DataSeries > xSeries( pSeries ? pSeries->getModel() : nullptr ); + if( xSeries.is() ) + { + OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) ); + aRetVector.push_back( aSeriesName ); + } + } + } + } + return comphelper::containerToSequence( aRetVector ); +} + +void VSeriesPlotter::setPageReferenceSize( const css::awt::Size & rPageRefSize ) +{ + m_aPageReferenceSize = rPageRefSize; + + // set reference size also at all data series + + for (auto const & outer : m_aZSlots) + for (VDataSeriesGroup const & rGroup : outer) + { + for (std::unique_ptr const & pSeries : rGroup.m_aSeriesVector) + { + pSeries->setPageReferenceSize(m_aPageReferenceSize); + } + } +} + +//better performance for big data +void VSeriesPlotter::setCoordinateSystemResolution( const Sequence< sal_Int32 >& rCoordinateSystemResolution ) +{ + m_aCoordinateSystemResolution = rCoordinateSystemResolution; +} + +bool VSeriesPlotter::WantToPlotInFrontOfAxisLine() +{ + return ChartTypeHelper::isSeriesInFrontOfAxisLine( m_xChartTypeModel ); +} + +bool VSeriesPlotter::shouldSnapRectToUsedArea() +{ + return m_nDimension != 3; +} + +std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries( + const awt::Size& rEntryKeyAspectRatio + , LegendPosition eLegendPosition + , const Reference< beans::XPropertySet >& xTextProperties + , const rtl::Reference& xTarget + , const Reference< uno::XComponentContext >& xContext + , ChartModel& rModel + ) +{ + std::vector< ViewLegendEntry > aResult; + + if( xTarget.is() ) + { + rtl::Reference< Diagram > xDiagram = rModel.getFirstChartDiagram(); + rtl::Reference< BaseCoordinateSystem > xCooSys(xDiagram->getBaseCoordinateSystems()[0]); + bool bSwapXAndY = false; + + try + { + xCooSys->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndY; + } + catch( const uno::Exception& ) + { + } + + //iterate through all series + bool bBreak = false; + bool bFirstSeries = true; + + + for (std::vector const & rGroupVector : m_aZSlots) + { + for (VDataSeriesGroup const & rGroup : rGroupVector) + { + for (std::unique_ptr const & pSeries : rGroup.m_aSeriesVector) + { + if (!pSeries) + continue; + + if (!pSeries->getPropertiesOfSeries()->getPropertyValue("ShowLegendEntry").get()) + { + continue; + } + + std::vector aSeriesEntries( + createLegendEntriesForSeries( + rEntryKeyAspectRatio, *pSeries, xTextProperties, + xTarget, xContext)); + + //add series entries to the result now + + // use only the first series if VaryColorsByPoint is set for the first series + if (bFirstSeries && pSeries->isVaryColorsByPoint()) + bBreak = true; + bFirstSeries = false; + + // add entries reverse if chart is stacked in y-direction and the legend position is right or left. + // If the legend is top or bottom and we have a stacked bar-chart the normal order + // is the correct one, unless the chart type is horizontal bar-chart. + bool bReverse = false; + if ( bSwapXAndY ) + { + StackingDirection eStackingDirection( pSeries->getStackingDirection() ); + bReverse = ( eStackingDirection != StackingDirection_Y_STACKING ); + } + else if ( eLegendPosition == LegendPosition_LINE_START || eLegendPosition == LegendPosition_LINE_END ) + { + StackingDirection eStackingDirection( pSeries->getStackingDirection() ); + bReverse = ( eStackingDirection == StackingDirection_Y_STACKING ); + } + + if (bReverse) + aResult.insert( aResult.begin(), aSeriesEntries.begin(), aSeriesEntries.end() ); + else + aResult.insert( aResult.end(), aSeriesEntries.begin(), aSeriesEntries.end() ); + } + if (bBreak) + return aResult; + } + } + } + + return aResult; +} + +namespace +{ +bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bool& rbHasDashedLine ) +{ + bool bHasVisibleLine = false; + rbHasDashedLine = false; + drawing::LineStyle aLineStyle = drawing::LineStyle_NONE; + if( xProps.is() && ( xProps->getPropertyValue( "LineStyle") >>= aLineStyle ) ) + { + if( aLineStyle != drawing::LineStyle_NONE ) + bHasVisibleLine = true; + if( aLineStyle == drawing::LineStyle_DASH ) + rbHasDashedLine = true; + } + return bHasVisibleLine; +} + +bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine ) +{ + bool bHasRegressionCurves = false; + rtl::Reference< DataSeries > xRegrCont( rSeries.getModel() ); + for( const rtl::Reference< RegressionCurveModel > & rCurve : xRegrCont->getRegressionCurves2() ) + { + bHasRegressionCurves = true; + lcl_HasVisibleLine( rCurve, rbHasDashedLine ); + } + return bHasRegressionCurves; +} +} +LegendSymbolStyle VSeriesPlotter::getLegendSymbolStyle() +{ + return LegendSymbolStyle::Box; +} + +awt::Size VSeriesPlotter::getPreferredLegendKeyAspectRatio() +{ + awt::Size aRet(1000,1000); + if( m_nDimension==3 ) + return aRet; + + bool bSeriesAllowsLines = (getLegendSymbolStyle() == LegendSymbolStyle::Line); + bool bHasLines = false; + bool bHasDashedLines = false; + //iterate through all series + for (VDataSeries* pSeries : getAllSeries()) + { + if( bSeriesAllowsLines ) + { + bool bCurrentDashed = false; + if( lcl_HasVisibleLine( pSeries->getPropertiesOfSeries(), bCurrentDashed ) ) + { + bHasLines = true; + if( bCurrentDashed ) + { + bHasDashedLines = true; + break; + } + } + } + bool bRegressionHasDashedLines=false; + if( lcl_HasRegressionCurves( *pSeries, bRegressionHasDashedLines ) ) + { + bHasLines = true; + if( bRegressionHasDashedLines ) + { + bHasDashedLines = true; + break; + } + } + } + if( bHasLines ) + { + if( bHasDashedLines ) + aRet = awt::Size(1600,-1); + else + aRet = awt::Size(800,-1); + } + return aRet; +} + +uno::Any VSeriesPlotter::getExplicitSymbol( const VDataSeries& /*rSeries*/, sal_Int32 /*nPointIndex*/ ) +{ + return uno::Any(); +} + +rtl::Reference VSeriesPlotter::createLegendSymbolForSeries( + const awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , const rtl::Reference& xTarget ) +{ + + LegendSymbolStyle eLegendSymbolStyle = getLegendSymbolStyle(); + uno::Any aExplicitSymbol( getExplicitSymbol( rSeries, -1 ) ); + + VLegendSymbolFactory::PropertyType ePropType = + VLegendSymbolFactory::PropertyType::FilledSeries; + + // todo: maybe the property-style does not solely depend on the + // legend-symbol type + switch( eLegendSymbolStyle ) + { + case LegendSymbolStyle::Line: + ePropType = VLegendSymbolFactory::PropertyType::LineSeries; + break; + default: + break; + } + rtl::Reference xShape = VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio, + xTarget, eLegendSymbolStyle, + rSeries.getPropertiesOfSeries(), ePropType, aExplicitSymbol ); + + return xShape; +} + +rtl::Reference< SvxShapeGroup > VSeriesPlotter::createLegendSymbolForPoint( + const awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , sal_Int32 nPointIndex + , const rtl::Reference& xTarget ) +{ + + LegendSymbolStyle eLegendSymbolStyle = getLegendSymbolStyle(); + uno::Any aExplicitSymbol( getExplicitSymbol(rSeries,nPointIndex) ); + + VLegendSymbolFactory::PropertyType ePropType = + VLegendSymbolFactory::PropertyType::FilledSeries; + + // todo: maybe the property-style does not solely depend on the + // legend-symbol type + switch( eLegendSymbolStyle ) + { + case LegendSymbolStyle::Line: + ePropType = VLegendSymbolFactory::PropertyType::LineSeries; + break; + default: + break; + } + + // the default properties for the data point are the data series properties. + // If a data point has own attributes overwrite them + Reference< beans::XPropertySet > xSeriesProps( rSeries.getPropertiesOfSeries() ); + Reference< beans::XPropertySet > xPointSet( xSeriesProps ); + if( rSeries.isAttributedDataPoint( nPointIndex ) ) + xPointSet.set( rSeries.getPropertiesOfPoint( nPointIndex )); + + // if a data point has no own color use a color from the diagram's color scheme + if( ! rSeries.hasPointOwnColor( nPointIndex )) + { + Reference< util::XCloneable > xCloneable( xPointSet,uno::UNO_QUERY ); + if( xCloneable.is() && m_xColorScheme.is() ) + { + xPointSet.set( xCloneable->createClone(), uno::UNO_QUERY ); + Reference< container::XChild > xChild( xPointSet, uno::UNO_QUERY ); + if( xChild.is()) + xChild->setParent( xSeriesProps ); + + OSL_ASSERT( xPointSet.is()); + xPointSet->setPropertyValue( + "Color", uno::Any( m_xColorScheme->getColorByIndex( nPointIndex ))); + } + } + + rtl::Reference< SvxShapeGroup > xShape = VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio, + xTarget, eLegendSymbolStyle, xPointSet, ePropType, aExplicitSymbol ); + + return xShape; +} + +std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries( + const awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , const Reference< beans::XPropertySet >& xTextProperties + , const rtl::Reference& xTarget + , const Reference< uno::XComponentContext >& xContext + ) +{ + std::vector< ViewLegendEntry > aResult; + + if( ! ( xTarget.is() && xContext.is() ) ) + return aResult; + + try + { + ViewLegendEntry aEntry; + OUString aLabelText; + bool bVaryColorsByPoint = rSeries.isVaryColorsByPoint(); + bool bIsPie = m_xChartTypeModel->getChartType().equalsIgnoreAsciiCase( + CHART2_SERVICE_NAME_CHARTTYPE_PIE); + try + { + if (bIsPie) + { + bool bDonut = false; + if ((m_xChartTypeModel->getPropertyValue("UseRings") >>= bDonut) && bDonut) + bIsPie = false; + } + } + catch (const uno::Exception&) + { + } + + if (bVaryColorsByPoint || bIsPie) + { + Sequence< OUString > aCategoryNames; + if( m_pExplicitCategoriesProvider ) + aCategoryNames = m_pExplicitCategoriesProvider->getSimpleCategories(); + Sequence deletedLegendEntries; + try + { + rSeries.getPropertiesOfSeries()->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntries; + } + catch (const uno::Exception&) + { + } + for( sal_Int32 nIdx=0; nIdx xSymbolGroup(ShapeFactory::createGroup2D( xTarget )); + + // create the symbol + rtl::Reference< SvxShapeGroup > xShape = createLegendSymbolForPoint( rEntryKeyAspectRatio, + rSeries, nIdx, xSymbolGroup ); + + // set CID to symbol for selection + if( xShape.is() ) + { + aEntry.xSymbol = xSymbolGroup; + + OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_DATA_POINT, nIdx ) ); + aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) ); + OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle ); + ShapeFactory::setShapeName( xShape, aCID ); + } + + // label + aLabelText = aCategoryNames[nIdx]; + if( xShape.is() || !aLabelText.isEmpty() ) + { + aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties ); + aResult.push_back(aEntry); + } + } + } + else + { + // symbol + rtl::Reference< SvxShapeGroup > xSymbolGroup(ShapeFactory::createGroup2D( xTarget )); + + // create the symbol + rtl::Reference xShape = createLegendSymbolForSeries( + rEntryKeyAspectRatio, rSeries, xSymbolGroup ); + + // set CID to symbol for selection + if( xShape.is()) + { + aEntry.xSymbol = xSymbolGroup; + + OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) ); + OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle ); + ShapeFactory::setShapeName( xShape, aCID ); + } + + // label + aLabelText = DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y"); + aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties ); + + aResult.push_back(aEntry); + } + + // don't show legend entry of regression curve & friends if this type of chart + // doesn't support statistics #i63016#, fdo#37197 + if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension )) + return aResult; + + rtl::Reference< DataSeries > xRegrCont = rSeries.getModel(); + if( xRegrCont.is()) + { + const std::vector< rtl::Reference< RegressionCurveModel > > & aCurves = xRegrCont->getRegressionCurves2(); + sal_Int32 i = 0, nCount = aCurves.size(); + for( i=0; i xSymbolGroup(ShapeFactory::createGroup2D( xTarget )); + + // create the symbol + rtl::Reference xShape = VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio, + xSymbolGroup, LegendSymbolStyle::Line, + aCurves[i], + VLegendSymbolFactory::PropertyType::Line, uno::Any() ); + + // set CID to symbol for selection + if( xShape.is()) + { + aEntry.xSymbol = xSymbolGroup; + + bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] ); + ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE; + OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) ); + aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) ); + OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle ); + ShapeFactory::setShapeName( xShape, aCID ); + } + + aResult.push_back(aEntry); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + return aResult; +} + +VSeriesPlotter* VSeriesPlotter::createSeriesPlotter( + const rtl::Reference& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bExcludingPositioning ) +{ + if (!xChartTypeModel.is()) + return nullptr; + + OUString aChartType = xChartTypeModel->getChartType(); + + VSeriesPlotter* pRet=nullptr; + if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ) ) + pRet = new BarChart(xChartTypeModel,nDimensionCount); + else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_BAR ) ) + pRet = new BarChart(xChartTypeModel,nDimensionCount); + else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_AREA ) ) + pRet = new AreaChart(xChartTypeModel,nDimensionCount,true); + else if( aChartType.equalsIgnoreAsciiCase( CHART2_SERVICE_NAME_CHARTTYPE_LINE ) ) + pRet = new AreaChart(xChartTypeModel,nDimensionCount,true,true); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER) ) + pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE) ) + pRet = new BubbleChart(xChartTypeModel,nDimensionCount); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) ) + pRet = new PieChart(xChartTypeModel,nDimensionCount, bExcludingPositioning ); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_NET) ) + pRet = new NetChart(xChartTypeModel,nDimensionCount,true,std::make_unique()); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) ) + pRet = new NetChart(xChartTypeModel,nDimensionCount,false,std::make_unique()); + else if( aChartType.equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK) ) + pRet = new CandleStickChart(xChartTypeModel,nDimensionCount); + else + pRet = new AreaChart(xChartTypeModel,nDimensionCount,false,true); + return pRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/diagram/VDiagram.cxx b/chart2/source/view/diagram/VDiagram.cxx new file mode 100644 index 000000000..2ce114676 --- /dev/null +++ b/chart2/source/view/diagram/VDiagram.cxx @@ -0,0 +1,703 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VDiagram::VDiagram( + const rtl::Reference & xDiagram, const drawing::Direction3D& rPreferredAspectRatio, + sal_Int32 nDimension ) + : m_nDimensionCount(nDimension) + , m_xDiagram(xDiagram) + , m_aPreferredAspectRatio(rPreferredAspectRatio) + , m_fXAnglePi(0) + , m_fYAnglePi(0) + , m_fZAnglePi(0) + , m_bRightAngledAxes(false) +{ + if( m_nDimensionCount != 3) + return; + + ThreeDHelper::getRotationAngleFromDiagram( xDiagram, m_fXAnglePi, m_fYAnglePi, m_fZAnglePi ); + if( ChartTypeHelper::isSupportingRightAngledAxes( + DiagramHelper::getChartTypeByIndex( m_xDiagram, 0 ) ) ) + { + if(xDiagram.is()) + xDiagram->getPropertyValue("RightAngledAxes") >>= m_bRightAngledAxes; + if( m_bRightAngledAxes ) + { + ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fXAnglePi, m_fYAnglePi ); + m_fZAnglePi=0.0; + } + } +} + +VDiagram::~VDiagram() +{ +} + +void VDiagram::init( const rtl::Reference& xTarget ) +{ + m_xTarget = xTarget; +} + +void VDiagram::createShapes( const awt::Point& rPos, const awt::Size& rSize ) +{ + m_aAvailablePosIncludingAxes = rPos; + m_aAvailableSizeIncludingAxes = rSize; + + if( m_nDimensionCount == 3 ) + createShapes_3d(); + else + createShapes_2d(); +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize( const awt::Point& rPos, const awt::Size& rSize ) +{ + ::basegfx::B2IRectangle aAllowedRect( BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes,m_aAvailableSizeIncludingAxes) ); + ::basegfx::B2IRectangle aNewInnerRect( BaseGFXHelper::makeRectangle(rPos,rSize) ); + aNewInnerRect.intersect( aAllowedRect ); + + if( m_nDimensionCount == 3 ) + aNewInnerRect = adjustPosAndSize_3d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); + else + aNewInnerRect = adjustPosAndSize_2d( BaseGFXHelper::B2IRectangleToAWTPoint(aNewInnerRect), BaseGFXHelper::B2IRectangleToAWTSize(aNewInnerRect) ); + + return aNewInnerRect; +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize_2d( const awt::Point& rPos, const awt::Size& rAvailableSize ) +{ + m_aCurrentPosWithoutAxes = rPos; + m_aCurrentSizeWithoutAxes = rAvailableSize; + if( m_aPreferredAspectRatio.DirectionX > 0 && m_aPreferredAspectRatio.DirectionY > 0) + { + //do not change aspect ratio + awt::Size aAspectRatio( static_cast(m_aPreferredAspectRatio.DirectionX*FIXED_SIZE_FOR_3D_CHART_VOLUME), + static_cast(m_aPreferredAspectRatio.DirectionY*FIXED_SIZE_FOR_3D_CHART_VOLUME )); + m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, aAspectRatio ); + //center diagram position + m_aCurrentPosWithoutAxes = ShapeFactory::calculateTopLeftPositionToCenterObject( + rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ); + + } + + if( m_xWall2D.is() ) + { + m_xWall2D->setSize( m_aCurrentSizeWithoutAxes); + m_xWall2D->setPosition(m_aCurrentPosWithoutAxes); + } + + return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); +} + +void VDiagram::createShapes_2d() +{ + OSL_PRECOND(m_xTarget.is(), "is not proper initialized"); + if (!m_xTarget.is()) + return; + + //create group shape + rtl::Reference xOuterGroup_Shapes = ShapeFactory::createGroup2D(m_xTarget); + m_xOuterGroupShape = xOuterGroup_Shapes; + + rtl::Reference xGroupForWall( ShapeFactory::createGroup2D(xOuterGroup_Shapes,"PlotAreaExcludingAxes") ); + + //create independent group shape as container for datapoints and such things + m_xCoordinateRegionShape = ShapeFactory::createGroup2D(xOuterGroup_Shapes,"testonly;CooContainer=XXX_CID"); + + bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram ); + + //add back wall + { + m_xWall2D = ShapeFactory::createRectangle( xGroupForWall ); + + try + { + OSL_ENSURE( m_xDiagram.is(), "Invalid Diagram model" ); + if( m_xDiagram.is() ) + { + uno::Reference< beans::XPropertySet > xWallProp( m_xDiagram->getWall()); + if( xWallProp.is()) + PropertyMapper::setMappedProperties( *m_xWall2D, xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties() ); + } + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( m_xWall2D ); + } + else + { + //CID for selection handling + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + m_xWall2D->SvxShape::setPropertyValue( UNO_NAME_MISC_OBJ_NAME, uno::Any( aWallCID ) ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + //position and size for diagram + adjustPosAndSize_2d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); +} + +static E3dScene* lcl_getE3dScene( const rtl::Reference& xShape ) +{ + return dynamic_cast< E3dScene* >(xShape->GetSdrObject()); +} + +static void lcl_setLightSources( + const uno::Reference< beans::XPropertySet > & xSource, + const uno::Reference< beans::XPropertySet > & xDest ) +{ + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8)); + + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_1)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_3)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_4)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_5)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_6)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_7)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_8)); + + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_1, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_1)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_3, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_3)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_4, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_4)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_5, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_5)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_6, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_6)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_7, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_7)); + xDest->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_8, + xSource->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_8)); +} + +namespace +{ + +void lcl_ensureScaleValue( double& rfScale ) +{ + OSL_ENSURE(rfScale>0, "calculation error for automatic 3D height in chart"); + if( rfScale<0 ) + rfScale = 1.0; + else if( rfScale<0.2 ) + rfScale = 0.2; + else if( rfScale>5.0 ) + rfScale = 5.0; +} + +} + +void VDiagram::adjustAspectRatio3d( const awt::Size& rAvailableSize ) +{ + OSL_PRECOND(m_xAspectRatio3D.is(), "created shape offers no XPropertySet"); + if( !m_xAspectRatio3D.is()) + return; + + try + { + double fScaleX = m_aPreferredAspectRatio.DirectionX; + double fScaleY = m_aPreferredAspectRatio.DirectionY; + double fScaleZ = m_aPreferredAspectRatio.DirectionZ; + + //normalize scale factors + { + double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); + fScaleX/=fMax; + fScaleY/=fMax; + fScaleZ/=fMax; + } + + if( fScaleX<0 || fScaleY<0 || fScaleZ<0 ) + { + //calculate automatic 3D aspect ratio that fits good into the given 2D area + double fW = rAvailableSize.Width; + double fH = rAvailableSize.Height; + + double sx = fabs(sin(m_fXAnglePi)); + double sy = fabs(sin(m_fYAnglePi)); + double cz = fabs(cos(m_fZAnglePi)); + double sz = fabs(sin(m_fZAnglePi)); + + if(m_bRightAngledAxes) + { + //base equations: + //fH*zoomfactor == sx*fScaleZ + fScaleY; + //fW*zoomfactor == sy*fScaleZ + fScaleX; + + if( fScaleX>0 && fScaleZ>0 ) + { + //calculate fScaleY: + if( !::basegfx::fTools::equalZero(fW) ) + { + fScaleY = (fH/fW)*(sy*fScaleZ+fScaleX)-(sx*fScaleZ); + lcl_ensureScaleValue( fScaleY ); + } + else + fScaleY = 1.0;//looking from top or bottom the height is irrelevant + } + else if( fScaleY>0 && fScaleZ>0 ) + { + //calculate fScaleX: + if( !::basegfx::fTools::equalZero(fH) ) + { + fScaleX = (fW/fH)*(sx*fScaleZ+fScaleY)-(sy*fScaleZ); + lcl_ensureScaleValue(fScaleX); + } + else + fScaleX = 1.0;//looking from top or bottom height is irrelevant + } + else + { + //todo + OSL_FAIL("not implemented yet"); + + if( fScaleX<0 ) + fScaleX = 1.0; + if( fScaleY<0 ) + fScaleY = 1.0; + if( fScaleZ<0 ) + fScaleZ = 1.0; + } + } + else + { + //base equations: + //fH*zoomfactor == cz*fScaleY + sz*fScaleX; + //fW*zoomfactor == cz*fScaleX + sz*fScaleY; + //==> fScaleY*(fH*sz-fW*cz) == fScaleX*(fW*sz-fH*cz); + if( fScaleX>0 && fScaleZ>0 ) + { + //calculate fScaleY: + double fDivide = fH*sz-fW*cz; + if( !::basegfx::fTools::equalZero(fDivide) ) + { + fScaleY = fScaleX*(fW*sz-fH*cz) / fDivide; + lcl_ensureScaleValue(fScaleY); + } + else + fScaleY = 1.0;//looking from top or bottom the height is irrelevant + + } + else if( fScaleY>0 && fScaleZ>0 ) + { + //calculate fScaleX: + double fDivide = fW*sz-fH*cz; + if( !::basegfx::fTools::equalZero(fDivide) ) + { + fScaleX = fScaleY*(fH*sz-fW*cz) / fDivide; + lcl_ensureScaleValue(fScaleX); + } + else + fScaleX = 1.0;//looking from top or bottom height is irrelevant + } + else + { + //todo + OSL_FAIL("not implemented yet"); + + if( fScaleX<0 ) + fScaleX = 1.0; + if( fScaleY<0 ) + fScaleY = 1.0; + if( fScaleZ<0 ) + fScaleZ = 1.0; + } + } + } + + //normalize scale factors + { + double fMax = std::max( std::max( fScaleX, fScaleY) , fScaleZ ); + fScaleX/=fMax; + fScaleY/=fMax; + fScaleZ/=fMax; + } + + // identity matrix + ::basegfx::B3DHomMatrix aResult; + aResult.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + aResult.scale( fScaleX, fScaleY, fScaleZ ); + aResult.translate( FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, + FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 ); + + // To get the 3D aspect ratio's effect on the 2D scene size, the scene's 2D size needs to be adapted to + // 3D content changes here. The tooling class remembers the current 3D transformation stack + // and in its destructor, calculates a new 2D SnapRect for the scene and it's modified 3D geometry. + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); + + m_xAspectRatio3D->setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX + , uno::Any(BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aResult )) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +::basegfx::B2IRectangle VDiagram::adjustPosAndSize_3d( const awt::Point& rPos, const awt::Size& rAvailableSize ) +{ + adjustAspectRatio3d( rAvailableSize ); + + //do not change aspect ratio of 3D scene with 2D bound rect + m_aCurrentSizeWithoutAxes = ShapeFactory::calculateNewSizeRespectingAspectRatio( + rAvailableSize, m_xOuterGroupShape->getSize() ); + m_xOuterGroupShape->setSize( m_aCurrentSizeWithoutAxes ); + + //center diagram position + m_aCurrentPosWithoutAxes= ShapeFactory::calculateTopLeftPositionToCenterObject( + rPos, rAvailableSize, m_aCurrentSizeWithoutAxes ); + m_xOuterGroupShape->setPosition(m_aCurrentPosWithoutAxes); + + return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); +} + +void VDiagram::createShapes_3d() +{ + OSL_PRECOND(m_xTarget.is(), "is not proper initialized"); + if (!m_xTarget.is()) + return; + + //create shape + rtl::Reference xShapes = ShapeFactory::createGroup3D( m_xTarget, "PlotAreaExcludingAxes" ); + m_xOuterGroupShape = xShapes; + + rtl::Reference xOuterGroup_Shapes = m_xOuterGroupShape; + + //create additional group to manipulate the aspect ratio of the whole diagram: + xOuterGroup_Shapes = ShapeFactory::createGroup3D( xOuterGroup_Shapes ); + + m_xAspectRatio3D = xOuterGroup_Shapes; + + bool bAddFloorAndWall = DiagramHelper::isSupportingFloorAndWall( m_xDiagram ); + + const bool bDoubleSided = false; + + //add walls + { + uno::Reference< beans::XPropertySet > xWallProp; + if( m_xDiagram.is() ) + xWallProp.set( m_xDiagram->getWall() ); + + OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model + if( !bAddFloorAndWall ) + aWallCID.clear(); + rtl::Reference xWallGroup_Shapes = ShapeFactory::createGroup3D( xOuterGroup_Shapes, aWallCID ); + + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( m_xDiagram ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( m_xDiagram ) ); + + //add left wall + { + short nRotatedTexture = ( eBackWallPos==CuboidPlanePosition_Front ) ? 3 : 1; + double xPos = 0.0; + if( eLeftWallPos==CuboidPlanePosition_Right ) + xPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; + Stripe aStripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); + if( eLeftWallPos==CuboidPlanePosition_Right ) + { + nRotatedTexture = ( eBackWallPos==CuboidPlanePosition_Front ) ? 2 : 0; + aStripe = Stripe( drawing::Position3D(xPos,FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) ); + } + aStripe.InvertNormal(true); + + rtl::Reference xShape = + ShapeFactory::createStripe( xWallGroup_Shapes, aStripe + , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture ); + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + } + //add back wall + { + short nRotatedTexture = 0; + double zPos = 0.0; + if( eBackWallPos==CuboidPlanePosition_Front ) + zPos = FIXED_SIZE_FOR_3D_CHART_VOLUME; + Stripe aStripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); + if( eBackWallPos==CuboidPlanePosition_Front ) + { + aStripe = Stripe( drawing::Position3D(0,FIXED_SIZE_FOR_3D_CHART_VOLUME,zPos) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) + , drawing::Direction3D(0,-FIXED_SIZE_FOR_3D_CHART_VOLUME,0) ); + nRotatedTexture = 3; + } + aStripe.InvertNormal(true); + + rtl::Reference xShape = + ShapeFactory::createStripe(xWallGroup_Shapes, aStripe + , xWallProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided, nRotatedTexture ); + if( !bAddFloorAndWall ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + } + } + + try + { + //perspective + { + //ignore distance and focal length from file format and model completely + //use vrp only to indicate the distance of the camera and thus influence the perspective + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_DISTANCE, uno::Any( + static_cast(ThreeDHelper::getCameraDistance( m_xDiagram )))); + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_PERSPECTIVE, + m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_PERSPECTIVE)); + } + + //light + { + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_SHADE_MODE, + m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_SHADE_MODE)); + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR, + m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR)); + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING, + m_xDiagram->getPropertyValue( UNO_NAME_3D_SCENE_TWO_SIDED_LIGHTING)); + lcl_setLightSources( m_xDiagram, m_xOuterGroupShape ); + } + + //rotation + { + //set diagrams rotation is set exclusively via the transformation matrix + //don't set a camera at all! + //the camera's rotation is incorporated into this matrix + + ::basegfx::B3DHomMatrix aEffectiveTransformation; + aEffectiveTransformation.translate(-FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0, -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0); + + if(!m_bRightAngledAxes) + aEffectiveTransformation.rotate(m_fXAnglePi,m_fYAnglePi,m_fZAnglePi); + else + aEffectiveTransformation.shearXY(m_fYAnglePi,-m_fXAnglePi); + + //#i98497# 3D charts are rendered with wrong size + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); + + m_xOuterGroupShape->setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX, + uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aEffectiveTransformation ) ) ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } + + //add floor plate + { + uno::Reference< beans::XPropertySet > xFloorProp; + if( m_xDiagram.is() ) + xFloorProp.set( m_xDiagram->getFloor() ); + + Stripe aStripe( drawing::Position3D(0,0,0) + , drawing::Direction3D(0,0,FIXED_SIZE_FOR_3D_CHART_VOLUME) + , drawing::Direction3D(FIXED_SIZE_FOR_3D_CHART_VOLUME,0,0) ); + aStripe.InvertNormal(true); + + rtl::Reference xShape = + ShapeFactory::createStripe(xOuterGroup_Shapes, aStripe + , xFloorProp, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), bDoubleSided ); + + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( m_xDiagram ) ); + if( !bAddFloorAndWall || (eBottomPos!=CuboidPlanePosition_Bottom) ) + { + //we always need this object as dummy object for correct scene dimensions + //but it should not be visible in this case: + ShapeFactory::makeShapeInvisible( xShape ); + } + else + { + OUString aFloorCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_FLOOR, u"" ) );//@todo read CID from model + ShapeFactory::setShapeName( xShape, aFloorCID ); + } + } + + //create an additional scene for the smaller inner coordinate region: + { + rtl::Reference xShapes2 = ShapeFactory::createGroup3D( xOuterGroup_Shapes,"testonly;CooContainer=XXX_CID" ); + m_xCoordinateRegionShape = xShapes2; + + try + { + double fXScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + double fYScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + double fZScale = (FIXED_SIZE_FOR_3D_CHART_VOLUME -GRID_TO_WALL_DISTANCE) /FIXED_SIZE_FOR_3D_CHART_VOLUME; + + ::basegfx::B3DHomMatrix aM; + aM.translate(GRID_TO_WALL_DISTANCE/fXScale, GRID_TO_WALL_DISTANCE/fYScale, GRID_TO_WALL_DISTANCE/fZScale); + aM.scale( fXScale, fYScale, fZScale ); + E3DModifySceneSnapRectUpdater aUpdater(lcl_getE3dScene(m_xOuterGroupShape)); + + xShapes2->SvxShape::setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX + , uno::Any(BaseGFXHelper::B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + m_aCurrentPosWithoutAxes = m_aAvailablePosIncludingAxes; + m_aCurrentSizeWithoutAxes = m_aAvailableSizeIncludingAxes; + adjustPosAndSize_3d( m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes ); +} + +basegfx::B2IRectangle VDiagram::getCurrentRectangle() const +{ + return BaseGFXHelper::makeRectangle(m_aCurrentPosWithoutAxes,m_aCurrentSizeWithoutAxes); +} + +void VDiagram::reduceToMinimumSize() +{ + if( !m_xOuterGroupShape.is() ) + return; + + awt::Size aMaxSize( m_aAvailableSizeIncludingAxes ); + awt::Point aMaxPos( m_aAvailablePosIncludingAxes ); + + sal_Int32 nNewWidth = std::round(aMaxSize.Width/2.2); + sal_Int32 nNewHeight = std::round(aMaxSize.Height/2.2); + awt::Size aNewSize( nNewWidth, nNewHeight ); + awt::Point aNewPos( aMaxPos ); + aNewPos.X += nNewWidth; + aNewPos.Y += nNewHeight; + + adjustPosAndSize( aNewPos, aNewSize ); +} + +::basegfx::B2IRectangle VDiagram::adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect ) +{ + awt::Point aNewPos = m_aCurrentPosWithoutAxes; + awt::Size aNewSize = m_aCurrentSizeWithoutAxes; + + basegfx::B2IRectangle aAvailableOuterRect = + BaseGFXHelper::makeRectangle(m_aAvailablePosIncludingAxes, m_aAvailableSizeIncludingAxes); + + sal_Int32 nDeltaWidth = aAvailableOuterRect.getWidth() - rConsumedOuterRect.getWidth(); + sal_Int32 nDeltaHeight = aAvailableOuterRect.getHeight() - rConsumedOuterRect.getHeight(); + if( (aNewSize.Width + nDeltaWidth) < aAvailableOuterRect.getWidth()/3 ) + nDeltaWidth = aAvailableOuterRect.getWidth()/3 - aNewSize.Width; + aNewSize.Width += nDeltaWidth; + + if( (aNewSize.Height + nDeltaHeight) < aAvailableOuterRect.getHeight()/3 ) + nDeltaHeight = aAvailableOuterRect.getHeight()/3 - aNewSize.Height; + aNewSize.Height += nDeltaHeight; + + sal_Int32 nDiffLeft = rConsumedOuterRect.getMinX() - aAvailableOuterRect.getMinX(); + sal_Int32 nDiffRight = aAvailableOuterRect.getMaxX() - rConsumedOuterRect.getMaxX(); + if( nDiffLeft >= 0 ) + aNewPos.X -= nDiffLeft; + else if( nDiffRight >= 0 ) + { + if( nDiffRight > -nDiffLeft ) + aNewPos.X += abs(nDiffLeft); + else if( nDiffRight > abs(nDeltaWidth) ) + aNewPos.X += nDiffRight; + else + aNewPos.X += abs(nDeltaWidth); + } + + sal_Int32 nDiffUp = rConsumedOuterRect.getMinY() - aAvailableOuterRect.getMinY(); + sal_Int32 nDiffDown = aAvailableOuterRect.getMaxY() - rConsumedOuterRect.getMaxY(); + if( nDiffUp >= 0 ) + aNewPos.Y -= nDiffUp; + else if( nDiffDown >= 0 ) + { + if( nDiffDown > -nDiffUp ) + aNewPos.Y += abs(nDiffUp); + else if( nDiffDown > abs(nDeltaHeight) ) + aNewPos.Y += nDiffDown; + else + aNewPos.Y += abs(nDeltaHeight); + } + + return adjustPosAndSize( aNewPos, aNewSize ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/Clipping.hxx b/chart2/source/view/inc/Clipping.hxx new file mode 100644 index 000000000..e816e7aa7 --- /dev/null +++ b/chart2/source/view/inc/Clipping.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } +namespace com::sun::star::drawing { struct Position3D; } + +namespace chart +{ + +class Clipping +{ + /** This class uses the 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. + */ + +public: + /** @descr The intersection between an open polygon and a rectangle is + calculated and the resulting lines are placed into the poly-polygon aResult. + @param rPolygon The polygon is required to be open, ie. its start and end point + have different coordinates and that it is continuous, ie. has no holes. + @param rRectangle The clipping area. + @param aResult The resulting lines that are the parts of the given polygon lying inside + the clipping area are stored into aResult whose prior content is deleted first. + */ + static void clipPolygonAtRectangle( + const css::drawing::PolyPolygonShape3D& rPolygon + , const ::basegfx::B2DRectangle& rRectangle + , css::drawing::PolyPolygonShape3D& aResult + , bool bSplitPiecesToDifferentPolygons = true ); + static void clipPolygonAtRectangle( + const std::vector>& rPolygon + , const ::basegfx::B2DRectangle& rRectangle + , std::vector>& aResult + , bool bSplitPiecesToDifferentPolygons = true ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/ConfigAccess.hxx b/chart2/source/view/inc/ConfigAccess.hxx new file mode 100644 index 000000000..df59b16a3 --- /dev/null +++ b/chart2/source/view/inc/ConfigAccess.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +namespace chart::ConfigAccess +{ +/** @descr Retrieve the setting for showing errors in charts from the registry + settings of the Calc application. + + If this setting is not found, it is set to false (the default setting). + + @return boolean UseErrorRectangle. + */ +bool getUseErrorRectangle(); + +} //namespace chart::ConfigAccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/DateHelper.hxx b/chart2/source/view/inc/DateHelper.hxx new file mode 100644 index 000000000..8c37851b7 --- /dev/null +++ b/chart2/source/view/inc/DateHelper.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace chart +{ + +class DateHelper +{ +public: + static bool IsInSameYear( const Date& rD1, const Date& rD2 ); + static bool IsInSameMonth( const Date& rD1, const Date& rD2 ); + + static Date GetDateSomeMonthsAway( const Date& rD, sal_Int32 nMonthDistance ); + static Date GetDateSomeYearsAway( const Date& rD, sal_Int32 nYearDistance ); + static bool IsLessThanOneMonthAway( const Date& rD1, const Date& rD2 ); + static bool IsLessThanOneYearAway( const Date& rD1, const Date& rD2 ); + + static double RasterizeDateValue( double fValue, const Date& rNullDate, tools::Long TimeResolution ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/LabelAlignment.hxx b/chart2/source/view/inc/LabelAlignment.hxx new file mode 100644 index 000000000..425f5c6c3 --- /dev/null +++ b/chart2/source/view/inc/LabelAlignment.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +namespace chart +{ +enum LabelAlignment +{ + LABEL_ALIGN_CENTER, + LABEL_ALIGN_LEFT, + LABEL_ALIGN_TOP, + LABEL_ALIGN_RIGHT, + LABEL_ALIGN_BOTTOM, + LABEL_ALIGN_LEFT_TOP, + LABEL_ALIGN_LEFT_BOTTOM, + LABEL_ALIGN_RIGHT_TOP, + LABEL_ALIGN_RIGHT_BOTTOM +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/LabelPositionHelper.hxx b/chart2/source/view/inc/LabelPositionHelper.hxx new file mode 100644 index 000000000..63125d621 --- /dev/null +++ b/chart2/source/view/inc/LabelPositionHelper.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "LabelAlignment.hxx" +#include "PropertyMapper.hxx" +#include +#include +#include + +namespace com::sun::star::drawing { struct Position3D; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::drawing { class XShape; } + +namespace chart +{ + +class LabelPositionHelper +{ +public: + LabelPositionHelper() = delete; + LabelPositionHelper( + sal_Int32 nDimensionCount + , const rtl::Reference& xLogicTarget ); + virtual ~LabelPositionHelper(); + + css::awt::Point transformSceneToScreenPosition( + const css::drawing::Position3D& rScenePosition3D ) const; + + static void changeTextAdjustment( tAnySequence& rPropValues, const tNameSequence& rPropNames, LabelAlignment eAlignment); + static void doDynamicFontResize( tAnySequence& rPropValues, const tNameSequence& rPropNames + , const css::uno::Reference< css::beans::XPropertySet >& xAxisModelProps + , const css::awt::Size& rNewReferenceSize ); + + static void correctPositionForRotation( const rtl::Reference& xShape2DText + , LabelAlignment eLabelAlignment, const double fRotationAngle, bool bRotateAroundCenter ); + +protected: + sal_Int32 m_nDimensionCount; + +private: + //these members are only necessary for transformation from 3D to 2D + rtl::Reference m_xLogicTarget; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/LegendEntryProvider.hxx b/chart2/source/view/inc/LegendEntryProvider.hxx new file mode 100644 index 000000000..e0133771c --- /dev/null +++ b/chart2/source/view/inc/LegendEntryProvider.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +enum class LegendSymbolStyle +{ + /** A square box with border. + */ + Box, + + /** A line like with a symbol. + */ + Line, + + /** A bordered circle which has the same bounding-box as the + BOX. + */ + Circle +}; + +struct ViewLegendEntry +{ + /** The legend symbol that represents a data series or other + information contained in the legend + */ + rtl::Reference< SvxShapeGroup > xSymbol; + + /** The descriptive text for a legend entry. + */ + css::uno::Sequence< + css::uno::Reference< css::chart2::XFormattedString2 > > aLabel; +}; + +class LegendEntryProvider +{ +public: + virtual css::awt::Size getPreferredLegendKeyAspectRatio()=0; + + virtual std::vector< ViewLegendEntry > createLegendEntries( + const css::awt::Size& rEntryKeyAspectRatio, + css::chart2::LegendPosition eLegendPosition, + const css::uno::Reference< css::beans::XPropertySet >& xTextProperties, + const rtl::Reference& xTarget, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + ChartModel& rModel + ) = 0; + +protected: + ~LegendEntryProvider() {} +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/Linear3DTransformation.hxx b/chart2/source/view/inc/Linear3DTransformation.hxx new file mode 100644 index 000000000..456f6e4c4 --- /dev/null +++ b/chart2/source/view/inc/Linear3DTransformation.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PlottingPositionHelper.hxx" +#include + +namespace chart +{ + +class Linear3DTransformation final : public XTransformation2 +{ +public: + Linear3DTransformation( const css::drawing::HomogenMatrix& rHomMatrix, bool bSwapXAndY ); + virtual ~Linear3DTransformation() override; + + // ____ XTransformation2 ____ + virtual css::drawing::Position3D transform( + const css::drawing::Position3D& rSourceValues ) const override; + virtual css::drawing::Position3D transform( + const css::uno::Sequence< double >& rSourceValues ) const override; + +private: + css::drawing::HomogenMatrix m_Matrix; + bool m_bSwapXAndY; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx b/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx new file mode 100644 index 000000000..cbb5e55ba --- /dev/null +++ b/chart2/source/view/inc/MinimumAndMaximumSupplier.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace chart +{ + +class MinimumAndMaximumSupplier +{ +public: + virtual double getMinimumX() = 0; + virtual double getMaximumX() = 0; + + //problem y maybe not is always the second border to ask for + virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) = 0; + virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) = 0; + + //problem: z maybe not independent in future + virtual double getMinimumZ() = 0; + virtual double getMaximumZ() = 0; + + virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) = 0; + virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) = 0; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) = 0; + + //return a constant out of css::chart::TimeUnit that allows to display the smallest distance between occurring dates + virtual tools::Long calculateTimeResolutionOnXAxis() = 0; + virtual void setTimeResolutionOnXAxis( tools::Long nTimeResolution, const Date& rNullDate ) = 0; + +protected: + ~MinimumAndMaximumSupplier() {} +}; + +class MergedMinimumAndMaximumSupplier final : public MinimumAndMaximumSupplier +{ +public: + MergedMinimumAndMaximumSupplier(); + virtual ~MergedMinimumAndMaximumSupplier(); + + void addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + bool hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + void clearMinimumAndMaximumSupplierList(); + + //--MinimumAndMaximumSupplier + virtual double getMinimumX() override; + virtual double getMaximumX() override; + virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + virtual double getMinimumZ() override; + virtual double getMaximumZ() override; + + virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) override; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual tools::Long calculateTimeResolutionOnXAxis() override; + virtual void setTimeResolutionOnXAxis( tools::Long nTimeResolution, const Date& rNullDate ) override; + +private: + typedef std::set< MinimumAndMaximumSupplier* > MinimumAndMaximumSupplierSet; + MinimumAndMaximumSupplierSet m_aMinimumAndMaximumSupplierList; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/PlotterBase.hxx b/chart2/source/view/inc/PlotterBase.hxx new file mode 100644 index 000000000..73695507f --- /dev/null +++ b/chart2/source/view/inc/PlotterBase.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace com::sun::star::drawing { struct HomogenMatrix; } +namespace com::sun::star::drawing { struct Position3D; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace chart { struct ExplicitScaleData; } + +namespace chart +{ + +class PlottingPositionHelper; +class ShapeFactory; + +/** This class provides methods for setting axis scales and for performing + * scene to screen transformations. It is used as the base class for all + * plotter classes. + */ +class PlotterBase +{ +public: + PlotterBase( sal_Int32 nDimension ); + virtual ~PlotterBase(); + + /// @throws css::uno::RuntimeException + virtual void initPlotter( + const rtl::Reference& xLogicTarget + , const rtl::Reference& xFinalTarget + , const OUString& rCID + ); + + virtual void setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ); + + virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix ); + + virtual void createShapes() = 0; + + static bool isValidPosition( const css::drawing::Position3D& rPos ); + +protected: //methods + rtl::Reference< SvxShapeGroupAnyD > + createGroupShape( const rtl::Reference< SvxShapeGroupAnyD >& xTarget + , const OUString& rName=OUString() ); + +protected: //member + rtl::Reference< SvxShapeGroupAnyD > m_xLogicTarget; + rtl::Reference< SvxShapeGroupAnyD > m_xFinalTarget; + OUString m_aCID; + + const sal_Int32 m_nDimension; + // needs to be created and deleted by the derived class + PlottingPositionHelper* m_pPosHelper; +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/PlottingPositionHelper.hxx b/chart2/source/view/inc/PlottingPositionHelper.hxx new file mode 100644 index 000000000..c0480a4e3 --- /dev/null +++ b/chart2/source/view/inc/PlottingPositionHelper.hxx @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::drawing { struct HomogenMatrix; } +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } + +namespace chart +{ + +class ShapeFactory; + +/** allows the transformation of numeric values from one + coordinate-system into another. Values may be transformed using + any mapping. + This is a non-UNO variant of the css::chart2::XTransformation interface, + but using more efficient calling and returning types. + */ +class XTransformation2 +{ +public: + virtual ~XTransformation2(); + /** transforms the given input data tuple, given in the source + coordinate system, according to the internal transformation + rules, into a tuple of transformed coordinates in the + destination coordinate system. + +

Note that both coordinate systems may have different + dimensions, e.g., if a transformation does simply a projection + into a lower-dimensional space.

+ + @param aValues a source tuple of data that is to be + transformed. The length of this sequence must be + equivalent to the dimension of the source coordinate + system. + + @return the transformed data tuple. The length of this + sequence is equal to the dimension of the output + coordinate system. + + @throws ::com::sun::star::lang::IllegalArgumentException + if the dimension of the input vector is not equal to the + dimension given in getSourceDimension(). + */ + virtual css::drawing::Position3D transform( + const css::drawing::Position3D& rSourceValues ) const = 0; + virtual css::drawing::Position3D transform( + const css::uno::Sequence< double >& rSourceValues ) const = 0; +}; + + +class PlottingPositionHelper +{ +public: + PlottingPositionHelper(); + PlottingPositionHelper( const PlottingPositionHelper& rSource ); + virtual ~PlottingPositionHelper(); + + virtual std::unique_ptr clone() const; + std::unique_ptr createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale ); + + virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix); + + virtual void setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ); + const std::vector< ExplicitScaleData >& getScales() const { return m_aScales;} + + //better performance for big data + inline void setCoordinateSystemResolution( const css::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ); + inline bool isSameForGivenResolution( double fX, double fY, double fZ + , double fX2, double fY2, double fZ2 ); + + inline bool isStrongLowerRequested( sal_Int32 nDimensionIndex ) const; + inline bool isLogicVisible( double fX, double fY, double fZ ) const; + inline void doLogicScaling( double* pX, double* pY, double* pZ ) const; + inline void doUnshiftedLogicScaling( double* pX, double* pY, double* pZ ) const; + inline void clipLogicValues( double* pX, double* pY, double* pZ ) const; + void clipScaledLogicValues( double* pX, double* pY, double* pZ ) const; + inline bool clipYRange( double& rMin, double& rMax ) const; + + inline void doLogicScaling( css::drawing::Position3D& rPos ) const; + + virtual ::chart::XTransformation2* + getTransformationScaledLogicToScene() const; + + virtual css::drawing::Position3D + transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + + virtual css::drawing::Position3D + transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const; + + void transformScaledLogicToScene( css::drawing::PolyPolygonShape3D& rPoly ) const; + void transformScaledLogicToScene( std::vector>& rPoly ) const; + + static css::awt::Point transformSceneToScreenPosition( + const css::drawing::Position3D& rScenePosition3D + , const rtl::Reference& xSceneTarget + , sal_Int32 nDimensionCount ); + + inline double getLogicMinX() const; + inline double getLogicMinY() const; + inline double getLogicMinZ() const; + inline double getLogicMaxX() const; + inline double getLogicMaxY() const; + inline double getLogicMaxZ() const; + + inline bool isMathematicalOrientationX() const; + inline bool isMathematicalOrientationY() const; + inline bool isMathematicalOrientationZ() const; + + ::basegfx::B2DRectangle getScaledLogicClipDoubleRect() const; + css::drawing::Direction3D getScaledLogicWidth() const; + + inline bool isSwapXAndY() const; + + bool isPercentY() const; + + double getBaseValueY() const; + + inline bool maySkipPointsInRegressionCalculation() const; + + void setTimeResolution( tools::Long nTimeResolution, const Date& rNullDate ); + virtual void setScaledCategoryWidth( double fScaledCategoryWidth ); + void AllowShiftXAxisPos( bool bAllowShift ); + void AllowShiftZAxisPos( bool bAllowShift ); + +protected: //member + std::vector< ExplicitScaleData > m_aScales; + ::basegfx::B3DHomMatrix m_aMatrixScreenToScene; + + //this is calculated based on m_aScales and m_aMatrixScreenToScene + mutable std::unique_ptr< ::chart::XTransformation2 > m_xTransformationLogicToScene; + + bool m_bSwapXAndY;//e.g. true for bar chart and false for column chart + + sal_Int32 m_nXResolution; + sal_Int32 m_nYResolution; + sal_Int32 m_nZResolution; + + bool m_bMaySkipPointsInRegressionCalculation; + + bool m_bDateAxis; + tools::Long m_nTimeResolution; + Date m_aNullDate; + + double m_fScaledCategoryWidth; + bool m_bAllowShiftXAxisPos; + bool m_bAllowShiftZAxisPos; +}; + +class PolarPlottingPositionHelper : public PlottingPositionHelper +{ +public: + PolarPlottingPositionHelper(); + PolarPlottingPositionHelper( const PolarPlottingPositionHelper& rSource ); + virtual ~PolarPlottingPositionHelper() override; + + virtual std::unique_ptr clone() const override; + + virtual void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix) override; + virtual void setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) override; + + const ::basegfx::B3DHomMatrix& getUnitCartesianToScene() const { return m_aUnitCartesianToScene;} + + virtual ::chart::XTransformation2* + getTransformationScaledLogicToScene() const override; + + //the resulting values provided by the following 3 methods should be used + //for input to the transformation received with + //'getTransformationScaledLogicToScene' + + /** Given a value in the radius axis scale range, it returns the normalized + * value. + */ + double transformToRadius( double fLogicValueOnRadiusAxis, bool bDoScaling=true ) const; + + /** Given a value in the angle axis scale range (e.g. [0,1] for pie charts) + * this method returns the related angle in degree. + */ + double transformToAngleDegree( double fLogicValueOnAngleAxis, bool bDoScaling=true ) const; + + /** Given 2 values in the angle axis scale range (e.g. [0,1] for pie charts) + * this method returns the angle between the 2 values keeping into account + * the correct axis orientation; (for instance, this method is used for + * computing the angle width of a pie slice). + */ + double getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const; + + virtual css::drawing::Position3D + transformLogicToScene( double fX, double fY, double fZ, bool bClip ) const override; + virtual css::drawing::Position3D + transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const override; + css::drawing::Position3D + transformAngleRadiusToScene( double fLogicValueOnAngleAxis, double fLogicValueOnRadiusAxis, double fLogicZ, bool bDoScaling=true ) const; + + /** It returns the scene coordinates of the passed point: this point is + * described through a normalized cylindrical coordinate system. + * (For a pie chart the origin of the coordinate system is the pie center). + */ + css::drawing::Position3D + transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius, double fLogicZ ) const; + + using PlottingPositionHelper::transformScaledLogicToScene; + + double getOuterLogicRadius() const; + + inline bool isMathematicalOrientationAngle() const; + inline bool isMathematicalOrientationRadius() const; +public: + ///m_bSwapXAndY (inherited): by default the X axis (scale[0]) represents + ///the angle axis and the Y axis (scale[1]) represents the radius axis; + ///when this parameter is true, the opposite happens (this is the case for + ///pie charts). + + ///Offset for radius axis in absolute logic scaled values (1.0 == 1 category) + ///For a donut, it represents the non-normalized inner radius (see notes for + ///transformToRadius) + double m_fRadiusOffset; + ///Offset for angle axis in real degree. + ///For a pie it represents the angle offset at which the first slice have to + ///start; + double m_fAngleDegreeOffset; + +private: + ::basegfx::B3DHomMatrix m_aUnitCartesianToScene; + + ::basegfx::B3DHomMatrix impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const; +}; + +bool PolarPlottingPositionHelper::isMathematicalOrientationAngle() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[2]; + if( css::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return true; + return false; +} +bool PolarPlottingPositionHelper::isMathematicalOrientationRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( css::chart2::AxisOrientation_MATHEMATICAL==rScale.Orientation ) + return true; + return false; +} + +//better performance for big data +void PlottingPositionHelper::setCoordinateSystemResolution( const css::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ) +{ + m_nXResolution = 1000; + m_nYResolution = 1000; + m_nZResolution = 1000; + if( rCoordinateSystemResolution.getLength() > 0 ) + m_nXResolution = rCoordinateSystemResolution[0]; + if( rCoordinateSystemResolution.getLength() > 1 ) + m_nYResolution = rCoordinateSystemResolution[1]; + if( rCoordinateSystemResolution.getLength() > 2 ) + m_nZResolution = rCoordinateSystemResolution[2]; +} + +bool PlottingPositionHelper::isSameForGivenResolution( double fX, double fY, double fZ + , double fX2, double fY2, double fZ2 /*these values are all expected tp be scaled already*/ ) +{ + if( !std::isfinite(fX) || !std::isfinite(fY) || !std::isfinite(fZ) + || !std::isfinite(fX2) || !std::isfinite(fY2) || !std::isfinite(fZ2) ) + return false; + + double fScaledMinX = getLogicMinX(); + double fScaledMinY = getLogicMinY(); + double fScaledMinZ = getLogicMinZ(); + double fScaledMaxX = getLogicMaxX(); + double fScaledMaxY = getLogicMaxY(); + double fScaledMaxZ = getLogicMaxZ(); + + doLogicScaling( &fScaledMinX, &fScaledMinY, &fScaledMinZ ); + doLogicScaling( &fScaledMaxX, &fScaledMaxY, &fScaledMaxZ); + + bool bSameX = ( static_cast(m_nXResolution*(fX - fScaledMinX)/(fScaledMaxX-fScaledMinX)) + == static_cast(m_nXResolution*(fX2 - fScaledMinX)/(fScaledMaxX-fScaledMinX)) ); + + bool bSameY = ( static_cast(m_nYResolution*(fY - fScaledMinY)/(fScaledMaxY-fScaledMinY)) + == static_cast(m_nYResolution*(fY2 - fScaledMinY)/(fScaledMaxY-fScaledMinY)) ); + + bool bSameZ = ( static_cast(m_nZResolution*(fZ - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ)) + == static_cast(m_nZResolution*(fZ2 - fScaledMinZ)/(fScaledMaxZ-fScaledMinZ)) ); + + return (bSameX && bSameY && bSameZ); +} + +bool PlottingPositionHelper::isStrongLowerRequested( sal_Int32 nDimensionIndex ) const +{ + if( m_aScales.empty() ) + return false; + if( 0==nDimensionIndex ) + return m_bAllowShiftXAxisPos && m_aScales[nDimensionIndex].m_bShiftedCategoryPosition; + else if( 2==nDimensionIndex ) + return m_bAllowShiftZAxisPos && m_aScales[nDimensionIndex].m_bShiftedCategoryPosition; + return false; +} + +bool PlottingPositionHelper::isLogicVisible( + double fX, double fY, double fZ ) const +{ + return fX >= m_aScales[0].Minimum && ( isStrongLowerRequested(0) ? fX < m_aScales[0].Maximum : fX <= m_aScales[0].Maximum ) + && fY >= m_aScales[1].Minimum && fY <= m_aScales[1].Maximum + && fZ >= m_aScales[2].Minimum && ( isStrongLowerRequested(2) ? fZ < m_aScales[2].Maximum : fZ <= m_aScales[2].Maximum ); +} + +void PlottingPositionHelper::doLogicScaling( double* pX, double* pY, double* pZ ) const +{ + if(pX) + { + if( m_aScales[0].Scaling.is()) + *pX = m_aScales[0].Scaling->doScaling(*pX); + if( m_bAllowShiftXAxisPos && m_aScales[0].m_bShiftedCategoryPosition ) + (*pX) += m_fScaledCategoryWidth/2.0; + } + if(pY && m_aScales[1].Scaling.is()) + *pY = m_aScales[1].Scaling->doScaling(*pY); + if(pZ) + { + if( m_aScales[2].Scaling.is()) + *pZ = m_aScales[2].Scaling->doScaling(*pZ); + if( m_bAllowShiftZAxisPos && m_aScales[2].m_bShiftedCategoryPosition) + (*pZ) += 0.5; + } +} + +void PlottingPositionHelper::doUnshiftedLogicScaling( double* pX, double* pY, double* pZ ) const +{ + if(pX && m_aScales[0].Scaling.is()) + *pX = m_aScales[0].Scaling->doScaling(*pX); + if(pY && m_aScales[1].Scaling.is()) + *pY = m_aScales[1].Scaling->doScaling(*pY); + if(pZ && m_aScales[2].Scaling.is()) + *pZ = m_aScales[2].Scaling->doScaling(*pZ); +} + +void PlottingPositionHelper::doLogicScaling( css::drawing::Position3D& rPos ) const +{ + doLogicScaling( &rPos.PositionX, &rPos.PositionY, &rPos.PositionZ ); +} + +void PlottingPositionHelper::clipLogicValues( double* pX, double* pY, double* pZ ) const +{ + if(pX) + { + if( *pX < m_aScales[0].Minimum ) + *pX = m_aScales[0].Minimum; + else if( *pX > m_aScales[0].Maximum ) + *pX = m_aScales[0].Maximum; + } + if(pY) + { + if( *pY < m_aScales[1].Minimum ) + *pY = m_aScales[1].Minimum; + else if( *pY > m_aScales[1].Maximum ) + *pY = m_aScales[1].Maximum; + } + if(pZ) + { + if( *pZ < m_aScales[2].Minimum ) + *pZ = m_aScales[2].Minimum; + else if( *pZ > m_aScales[2].Maximum ) + *pZ = m_aScales[2].Maximum; + } +} + +inline bool PlottingPositionHelper::clipYRange( double& rMin, double& rMax ) const +{ + //returns true if something remains + if( rMin > rMax ) + { + double fHelp = rMin; + rMin = rMax; + rMax = fHelp; + } + if( rMin > getLogicMaxY() ) + return false; + if( rMax < getLogicMinY() ) + return false; + if( rMin < getLogicMinY() ) + rMin = getLogicMinY(); + if( rMax > getLogicMaxY() ) + rMax = getLogicMaxY(); + return true; +} + +inline double PlottingPositionHelper::getLogicMinX() const +{ + return m_aScales[0].Minimum; +} +inline double PlottingPositionHelper::getLogicMinY() const +{ + return m_aScales[1].Minimum; +} +inline double PlottingPositionHelper::getLogicMinZ() const +{ + return m_aScales[2].Minimum; +} + +inline double PlottingPositionHelper::getLogicMaxX() const +{ + return m_aScales[0].Maximum; +} +inline double PlottingPositionHelper::getLogicMaxY() const +{ + return m_aScales[1].Maximum; +} +inline double PlottingPositionHelper::getLogicMaxZ() const +{ + return m_aScales[2].Maximum; +} +inline bool PlottingPositionHelper::isMathematicalOrientationX() const +{ + return css::chart2::AxisOrientation_MATHEMATICAL == m_aScales[0].Orientation; +} +inline bool PlottingPositionHelper::isMathematicalOrientationY() const +{ + return css::chart2::AxisOrientation_MATHEMATICAL == m_aScales[1].Orientation; +} +inline bool PlottingPositionHelper::isMathematicalOrientationZ() const +{ + return css::chart2::AxisOrientation_MATHEMATICAL == m_aScales[2].Orientation; +} +inline bool PlottingPositionHelper::isSwapXAndY() const +{ + return m_bSwapXAndY; +} +inline bool PlottingPositionHelper::maySkipPointsInRegressionCalculation() const +{ + return m_bMaySkipPointsInRegressionCalculation; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/PolarLabelPositionHelper.hxx b/chart2/source/view/inc/PolarLabelPositionHelper.hxx new file mode 100644 index 000000000..84f4ff1dc --- /dev/null +++ b/chart2/source/view/inc/PolarLabelPositionHelper.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "LabelPositionHelper.hxx" +#include + +namespace chart +{ + +class PolarPlottingPositionHelper; + +class PolarLabelPositionHelper final : public LabelPositionHelper +{ +public: + PolarLabelPositionHelper( + PolarPlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const rtl::Reference& xLogicTarget ); + virtual ~PolarLabelPositionHelper() override; + + css::awt::Point getLabelScreenPositionAndAlignmentForLogicValues( + LabelAlignment& rAlignment + , double fLogicValueOnAngleAxis + , double fLogicValueOnRadiusAxis + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const; + + /** Calculate the anchor point position for a text label. + * When the requested label placement is of `INSIDE` or `OUTSIDE` type the + * returned anchor point for the text label is the middle point of the + * outer arc for the given slice; when the requested label placement is of + * `CENTER` type the returned anchor point for the text label is the + * middle point of the line segment bisecting the slice. + * The text alignment is always centered when the requested label + * placement is of `CENTER` type else it is dependent on the value of the + * angle defined by the horizontal axis and the ray bisecting the slice. + * + */ + css::awt::Point getLabelScreenPositionAndAlignmentForUnitCircleValues( + LabelAlignment& rAlignment, sal_Int32 nLabelPlacement /*see css::chart::DataLabelPlacement*/ + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , double fLogicZ + , sal_Int32 nScreenValueOffsetInRadiusDirection ) const; + +private: + PolarPlottingPositionHelper* m_pPosHelper; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/PropertyMapper.hxx b/chart2/source/view/inc/PropertyMapper.hxx new file mode 100644 index 000000000..c4d9a1fa2 --- /dev/null +++ b/chart2/source/view/inc/PropertyMapper.hxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +class SvxShape; + +namespace chart +{ + +typedef std::unordered_map tPropertyNameMap; +typedef std::unordered_map tPropertyNameValueMap; +typedef css::uno::Sequence< OUString > tNameSequence; +typedef css::uno::Sequence< css::uno::Any > tAnySequence; + +/** + * PropertyMapper provides easy mapping of the property names of various + * objects in the chart model, to the property names of the destination + * shape objects (those whose service names begin with + * com.sun.star.drawing.). + */ +class PropertyMapper +{ +public: + static void setMappedProperties( + const css::uno::Reference< css::beans::XPropertySet >& xTarget + , const css::uno::Reference< css::beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap ); + + static void setMappedProperties( + SvxShape& xTarget + , const css::uno::Reference< css::beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap ); + + /** + * Fetch property values from the source object and map it to the + * destination container. Only those properties that are explicitly set + * will be inserted into the destination container. + * + * @param rValueMap destination container + * @param rNameMap property name mapping rule + * @param xSourceProp source object from which the property values are + * pulled. + */ + static void getValueMap( + tPropertyNameValueMap& rValueMap + , const tPropertyNameMap& rNameMap + , const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + ); + + static void getMultiPropertyListsFromValueMap( + tNameSequence& rNames + , tAnySequence& rValues + , const tPropertyNameValueMap& rValueMap + ); + + static css::uno::Any* + getValuePointer( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , std::u16string_view rPropName ); + + static css::uno::Any* + getValuePointerForLimitedSpace( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , bool bLimitedHeight ); + + static void setMultiProperties( + const tNameSequence& rNames + , const tAnySequence& rValues + , SvxShape& xTarget ); + + static const tPropertyNameMap& getPropertyNameMapForCharacterProperties(); + static const tPropertyNameMap& getPropertyNameMapForParagraphProperties(); + static const tPropertyNameMap& getPropertyNameMapForFillProperties(); + static const tPropertyNameMap& getPropertyNameMapForLineProperties(); + static const tPropertyNameMap& getPropertyNameMapForFillAndLineProperties(); + static const tPropertyNameMap& getPropertyNameMapForTextShapeProperties(); + + static const tPropertyNameMap& getPropertyNameMapForFilledSeriesProperties(); + static const tPropertyNameMap& getPropertyNameMapForLineSeriesProperties(); + static const tPropertyNameMap& getPropertyNameMapForTextLabelProperties(); + + static void getTextLabelMultiPropertyLists( + const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues + , bool bName=true + , sal_Int32 nLimitedSpace=-1 + , bool bLimitedHeight=false + , bool bSupportsLabelBorder = true); + + /** adds line-, fill- and character properties and sets some suitable + defaults for auto-grow properties + */ + static void getPreparedTextShapePropertyLists( + const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames + , tAnySequence& rPropValues ); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/ScaleAutomatism.hxx b/chart2/source/view/inc/ScaleAutomatism.hxx new file mode 100644 index 000000000..1141c9e87 --- /dev/null +++ b/chart2/source/view/inc/ScaleAutomatism.hxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +namespace chart { struct ExplicitIncrementData; } +namespace chart { struct ExplicitScaleData; } + +namespace chart +{ + +/** This class implements the calculation of automatic axis limits. + * + * This class is used for calculating axis scales and increments in the form + * of instances of `ExplicitScaleData` and `ExplicitIncrementData` classes. + * When a `ScaleAutomatism` instance is created a `ScaleData` object is passed + * to the constructor. Objects of `ScaleData` type are initialized by + * the `createCoordinateSystem` method of some chart type (e.g. + * the `PieChartType` class) and belong to some `Axis` object, they can be + * accessed through the `XAxis` interface (`XAxis::getScaleData`). + */ +class ScaleAutomatism +{ +public: + explicit ScaleAutomatism( + const css::chart2::ScaleData& rSourceScale, const Date& rNullDate ); + + /** Expands own value range with the passed minimum and maximum. + * + * It allows to set up the `m_fValueMinimum` and the `m_fValueMaximum` + * parameters which are used by the `calculateExplicitScaleAndIncrement` + * method for initializing the `Minimum` and `Maximum` properties of the + * explicit scale when the same properties of the `ScaleData` object are + * undefined (that is empty `uno::Any` objects). + */ + void expandValueRange( double fMinimum, double fMaximum ); + void resetValueRange(); + + /** Sets additional auto scaling options. + @param bExpandBorderToIncrementRhythm If true, expands automatic + borders to the fixed or calculated increment rhythm. + @param bExpandIfValuesCloseToBorder If true, expands automatic borders + if values are too close (closer than 1/21 of visible area). + @param bExpandWideValuesToZero If true, expands automatic border to + zero, if source values are positive only or negative only, and if + the absolute values are wide spread (at least one value is less + than 5/6 of absolute maximum), or if all values are equal. + @param bExpandNarrowValuesTowardZero If true, expands automatic border + toward zero (50% of the visible range), if source values are + positive only or negative only, and if the absolute values are + close to the absolute maximum (no value is less than 5/6 of + absolute maximum). */ + void setAutoScalingOptions( + bool bExpandBorderToIncrementRhythm, + bool bExpandIfValuesCloseToBorder, + bool bExpandWideValuesToZero, + bool bExpandNarrowValuesTowardZero ); + + /** Sets the maximum allowed number of automatic main increments. + @descr The number of main increments may be limited e.g. by the length + of the axis and the font size of the axis caption text. */ + void setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount ); + + /** Sets the time resolution to be used in case it is not set explicitly within the scale + */ + void setAutomaticTimeResolution( sal_Int32 nTimeResolution ); + + /** Fills the passed scale data and increment data according to the own settings. + * + * It performs the initialization of the passed explicit scale and + * explicit increment parameters, mainly the initialization is achieved by + * using the `ScaleData` object as data source. However other parameters + * which affect the behavior of this method can be set through + * the `setAutoScalingOptions` and the `expandValueRange` methods. + */ + void calculateExplicitScaleAndIncrement( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement ) const; + + const css::chart2::ScaleData& getScale() const { return m_aSourceScale;} + const Date& getNullDate() const { return m_aNullDate;} + +private: + /** Fills the passed scale data and increment data for category scaling. */ + void calculateExplicitIncrementAndScaleForCategory( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for logarithmic scaling. */ + void calculateExplicitIncrementAndScaleForLogarithmic( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for linear scaling. */ + void calculateExplicitIncrementAndScaleForLinear( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + + /** Fills the passed scale data and increment data for date-time axis. */ + void calculateExplicitIncrementAndScaleForDateTimeAxis( + ExplicitScaleData& rExplicitScale, + ExplicitIncrementData& rExplicitIncrement, + bool bAutoMinimum, bool bAutoMaximum ) const; + +private: + css::chart2::ScaleData m_aSourceScale; + + double m_fValueMinimum; /// Minimum of all source values. + double m_fValueMaximum; /// Maximum of all source values. + sal_Int32 m_nMaximumAutoMainIncrementCount; /// Maximum number of automatic main increments. + bool m_bExpandBorderToIncrementRhythm; /// true = Expand to main increments. + bool m_bExpandIfValuesCloseToBorder; /// true = Expand if values are too close to the borders. + bool m_bExpandWideValuesToZero; /// true = Expand wide spread values to zero. + bool m_bExpandNarrowValuesTowardZero; /// true = Expand narrow range toward zero (add half of range). + sal_Int32 m_nTimeResolution;// a constant out of css::chart::TimeUnit + + Date m_aNullDate; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/ShapeFactory.hxx b/chart2/source/view/inc/ShapeFactory.hxx new file mode 100644 index 000000000..d6c05af04 --- /dev/null +++ b/chart2/source/view/inc/ShapeFactory.hxx @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyMapper.hxx" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace chart { struct VLineProperties; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XFormattedString; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::drawing { struct HomogenMatrix; } +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } +namespace com::sun::star::drawing { struct Position3D; } +namespace com::sun::star::graphic { class XGraphic; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::drawing { struct Direction3D; } + +namespace chart +{ +class Stripe; + +// Be careful here not to clash with the SYMBOL_FOO #defines in +// +enum SymbolEnum { Symbol_Square=0 + , Symbol_Diamond + , Symbol_DownArrow + , Symbol_UpArrow + , Symbol_RightArrow + , Symbol_LeftArrow + , Symbol_Bowtie + , Symbol_Sandglass + , Symbol_Circle + , Symbol_Star + , Symbol_X + , Symbol_Plus + , Symbol_Asterisk + , Symbol_HorizontalBar + , Symbol_VerticalBar + , Symbol_COUNT +}; + + +class ShapeFactory +{ +public: + enum class StackPosition { Top, Bottom }; + + ShapeFactory() = delete; + + static rtl::Reference< SvxShapeGroup > + createGroup2D( + const rtl::Reference& xTarget + , const OUString& aName = OUString() ); + + static rtl::Reference< SvxShapeGroup > + createGroup2D( + const rtl::Reference& xTarget + , const OUString& aName = OUString() ); + + static rtl::Reference + createGroup3D( + const rtl::Reference& xTarget + , const OUString& aName = OUString() ); + + static rtl::Reference + createCube( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bRounded = false); + + static rtl::Reference + createCylinder( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree ); + + static rtl::Reference + createPyramid( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , double fTopHeight + , bool bRotateZ + , const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap); + + static rtl::Reference + createCone( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree ); + + static rtl::Reference + createPieSegment2D( const rtl::Reference& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const css::drawing::Direction3D& rOffset + , const css::drawing::HomogenMatrix& rUnitCircleToScene ); + + static rtl::Reference + createPieSegment( const rtl::Reference& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const css::drawing::Direction3D& rOffset + , const css::drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ); + + static rtl::Reference + createStripe( const rtl::Reference& xTarget + , const Stripe& rStripe + , const css::uno::Reference< css::beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bDoubleSided + , short nRotatedTexture = 0 //0 to 7 are the different possibilities + , bool bFlatNormals=true ); + + static rtl::Reference + createArea3D( const rtl::Reference& xTarget + , const std::vector>& rPolyPolygon + , double fDepth); + + static rtl::Reference + createArea2D( const rtl::Reference& xTarget + , const std::vector>& rPolyPolygon); + + static rtl::Reference + createSymbol2D( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPos + , const css::drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor + , sal_Int32 nFillColor ); + + static rtl::Reference + createGraphic2D( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPos + , const css::drawing::Direction3D& rSize + , const css::uno::Reference< css::graphic::XGraphic >& xGraphic ); + + static rtl::Reference + createLine2D( const rtl::Reference& xTarget + , const css::drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties = nullptr ); + static rtl::Reference + createLine2D( const rtl::Reference& xTarget + , const std::vector>& rPoints + , const VLineProperties* pLineProperties = nullptr ); + + static rtl::Reference + createLine ( const rtl::Reference& xTarget, + const css::awt::Size& rSize, const css::awt::Point& rPosition ); + + static rtl::Reference + createLine3D( const rtl::Reference& xTarget + , const std::vector>& rPoints + , const VLineProperties& rLineProperties ); + + static rtl::Reference + createCircle2D( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPos + , const css::drawing::Direction3D& rSize ); + + static rtl::Reference + createCircle( const rtl::Reference& xTarget + , const css::awt::Size& rSize + , const css::awt::Point& rPosition ); + + static rtl::Reference + createText( const rtl::Reference& xTarget2D + , const OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const css::uno::Any& rATransformation + ); + + static rtl::Reference + createText(const rtl::Reference& xTarget + , const css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& xFormattedString + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const css::uno::Any& rATransformation); + + static rtl::Reference + createText( const rtl::Reference& xTarget2D, + const css::awt::Size& rSize, + const css::awt::Point& rPosition, + css::uno::Sequence< css::uno::Reference< css::chart2::XFormattedString > >& xFormattedString, + const css::uno::Reference< css::beans::XPropertySet > & xTextProperties, + double nRotation, const OUString& aName, sal_Int32 nTextMaxWidth ); + + static rtl::Reference createTable(rtl::Reference const& xTarget); + + static rtl::Reference + createInvisibleRectangle( + const rtl::Reference& xTarget + , const css::awt::Size& rSize ); + + static rtl::Reference + createRectangle( + const rtl::Reference& xTarget, + const css::awt::Size& rSize, + const css::awt::Point& rPosition, + const tNameSequence& rPropNames, + const tAnySequence& rPropValues, + StackPosition ePos = StackPosition::Top ); + + static rtl::Reference + createRectangle( + const rtl::Reference& xTarget ); + + static rtl::Reference + getOrCreateChartRootShape( const rtl::Reference& xPage ); + + static void setPageSize(const rtl::Reference& xChartShapes, + const css::awt::Size& rSize); + + static rtl::Reference + getChartRootShape( const rtl::Reference& xPage ); + + static void makeShapeInvisible( const rtl::Reference< SvxShape >& rShape ); + + static void setShapeName( const rtl::Reference< SvxShape >& xShape + , const OUString& rName ); + + static OUString getShapeName( const css::uno::Reference< css::drawing::XShape >& xShape ); + + static css::uno::Any makeTransformation( const css::awt::Point& rScreenPosition2D, double fRotationAnglePi=0.0 ); + + static OUString getStackedString( const OUString& rString, bool bStacked ); + + static bool hasPolygonAnyLines( const std::vector>& rPoly ); + static bool isPolygonEmptyOrSinglePoint( const css::drawing::PolyPolygonShape3D& rPoly ); + static bool isPolygonEmptyOrSinglePoint( const std::vector>& rPoly ); + static void closePolygon( css::drawing::PolyPolygonShape3D& rPoly ); + static void closePolygon( std::vector>& rPoly ); + + static css::awt::Size calculateNewSizeRespectingAspectRatio( + const css::awt::Size& rTargetSize + , const css::awt::Size& rSourceSizeWithCorrectAspectRatio ); + + static css::awt::Point calculateTopLeftPositionToCenterObject( + const css::awt::Point& rTargetAreaPosition + , const css::awt::Size& rTargetAreaSize + , const css::awt::Size& rObjectSize ); + + static ::basegfx::B2IRectangle getRectangleOfShape( SvxShape& rShape ); + + static css::awt::Size getSizeAfterRotation( + SvxShape& rShape, double fRotationAngleDegree ); + + static void removeSubShapes( const rtl::Reference& xShapes ); + + static sal_Int32 getSymbolCount() { return Symbol_COUNT; } + +private: + static rtl::Reference + impl_createCube( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize, sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ); + + static rtl::Reference + impl_createConeOrCylinder( const rtl::Reference& xTarget + , const css::drawing::Position3D& rPosition + , const css::drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , bool bCylinder); +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/Stripe.hxx b/chart2/source/view/inc/Stripe.hxx new file mode 100644 index 000000000..0da5e0b5d --- /dev/null +++ b/chart2/source/view/inc/Stripe.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart +{ + +/** A Stripe represents a 2 dimensional foursquare plane in a 3 dimensional room. + +@todo could: it is not necessary to have 4 point members here; it would be sufficient to have one point and 2 directions +*/ + +class Stripe +{ +public: + Stripe( const css::drawing::Position3D& rPoint1 + , const css::drawing::Direction3D& rDirectionToPoint2 + , const css::drawing::Direction3D& rDirectionToPoint4 ); + + Stripe( const css::drawing::Position3D& rPoint1 + , const css::drawing::Position3D& rPoint2 + , double fDepth ); + + Stripe( const css::drawing::Position3D& rPoint1 + , const css::drawing::Position3D& rPoint2 + , const css::drawing::Position3D& rPoint3 + , const css::drawing::Position3D& rPoint4 ); + + void SetManualNormal( const css::drawing::Direction3D& rNormal ); + css::drawing::Direction3D getNormal() const; + + void InvertNormal( bool bInvertNormal ); + + css::uno::Any getPolyPolygonShape3D() const; + css::uno::Any getNormalsPolygon() const; + static css::uno::Any getTexturePolygon( short nRotatedTexture ); //0 to 7 are the different possibilities + +private: + css::drawing::Position3D m_aPoint1; + css::drawing::Position3D m_aPoint2; + css::drawing::Position3D m_aPoint3; + css::drawing::Position3D m_aPoint4; + + bool m_bInvertNormal; + bool m_bManualNormalSet; + css::drawing::Direction3D m_aManualNormal; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VCoordinateSystem.hxx b/chart2/source/view/inc/VCoordinateSystem.hxx new file mode 100644 index 000000000..0664a5462 --- /dev/null +++ b/chart2/source/view/inc/VCoordinateSystem.hxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "MinimumAndMaximumSupplier.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace chart { class ExplicitCategoriesProvider; } +namespace chart { class ScaleAutomatism; } +namespace chart { class ChartModel; } +namespace com::sun::star::awt { struct Rectangle; } +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XAxis; } +namespace com::sun::star::chart2 { class XChartDocument; } +namespace com::sun::star::chart2 { class XCoordinateSystem; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + + +namespace chart +{ +class Axis; +class BaseCoordinateSystem; +class VAxisBase; + +class VCoordinateSystem +{ +public: + virtual ~VCoordinateSystem(); + + static std::unique_ptr createCoordinateSystem( const rtl::Reference< + ::chart::BaseCoordinateSystem >& xCooSysModel ); + + /// @throws css::uno::RuntimeException + void initPlottingTargets( + const rtl::Reference< SvxShapeGroupAnyD >& xLogicTarget + , const rtl::Reference< SvxShapeGroupAnyD >& xFinalTarget + , rtl::Reference& xLogicTargetForSeriesBehindAxis ); + + void setParticle( const OUString& rCooSysParticle ); + + void setTransformationSceneToScreen( const css::drawing::HomogenMatrix& rMatrix ); + const css::drawing::HomogenMatrix& getTransformationSceneToScreen() const { return m_aMatrixSceneToScreen;} + + //better performance for big data + virtual css::uno::Sequence< sal_Int32 > getCoordinateSystemResolution( const css::awt::Size& rPageSize + , const css::awt::Size& rPageResolution ); + + ExplicitScaleData getExplicitScale( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + ExplicitIncrementData getExplicitIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + + void setExplicitCategoriesProvider( ExplicitCategoriesProvider* /*takes ownership*/ ); + ExplicitCategoriesProvider* getExplicitCategoriesProvider(); + + // returns a complete scale set for a given dimension and index; for example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary x axis, main y axis and main z axis + std::vector< ExplicitScaleData > getExplicitScales( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + // returns a complete increment set for a given dimension and index; for example if nDimensionIndex==1 and nAxisIndex==2 you get returned the secondary x axis, main y axis and main z axis + std::vector< ExplicitIncrementData > getExplicitIncrements( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + + void addMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + bool hasMinimumAndMaximumSupplier( MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier ); + void clearMinimumAndMaximumSupplierList(); + + /** + * It sets the scaling parameters for the passed `ScaleAutomatism` object. + * Especially it sets the `m_fValueMinimum` and the `m_fValueMaximum` + * parameters (see `ScaleAutomatism::expandValueRange`). + * The value to be assigned to these two parameters is retrieved by + * invoking the `getMinimum` and `getMaximum` methods of the minimum-maximum + * supplier object that belongs to the given coordinate system. + * The minimum-maximum supplier object is set in the + * `SeriesPlotterContainer::initializeCooSysAndSeriesPlotter` method to the + * series plotter which is based on the coordinate system (see notes for + * the method). For instance for a pie chart the `m_fValueMinimum` and the + * `m_fValueMaximum` parameters are initialized by the `PieChart::getMinimum` + * and `PieChart::getMaximum` methods. + */ + void prepareAutomaticAxisScaling( ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ); + + void setExplicitScaleAndIncrement( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex + , const ExplicitScaleData& rExplicitScale + , const ExplicitIncrementData& rExplicitIncrement ); + + void set3DWallPositions( CuboidPlanePosition eLeftWallPos, CuboidPlanePosition eBackWallPos, CuboidPlanePosition eBottomPos ); + + const rtl::Reference< ::chart::BaseCoordinateSystem >& + getModel() const { return m_xCooSysModel;} + + /** + * Create "view" axis objects 'VAxis' from the coordinate system model. + */ + virtual void createVAxisList( + const rtl::Reference<::chart::ChartModel> & xChartDoc + , const css::awt::Size& rFontReferenceSize + , const css::awt::Rectangle& rMaximumSpaceForLabels + , bool bLimitSpaceForLabels ); + + virtual void initVAxisInList(); + virtual void updateScalesAndIncrementsOnAxes(); + + void createMaximumAxesLabels(); + void createAxesLabels(); + void updatePositions(); + void createAxesShapes(); + + virtual void createGridShapes(); + + bool getPropertySwapXAndYAxis() const; + + sal_Int32 getMaximumAxisIndexByDimension( sal_Int32 nDimensionIndex ) const; + + bool needSeriesNamesForAxis() const; + void setSeriesNamesForAxis( const css::uno::Sequence< OUString >& rSeriesNames ); + +protected: //methods + VCoordinateSystem( const rtl::Reference< ::chart::BaseCoordinateSystem >& xCooSys ); + + rtl::Reference< ::chart::Axis > + getAxisByDimension( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) const; + static std::vector< css::uno::Reference< css::beans::XPropertySet > > + getGridListFromAxis( const rtl::Reference< ::chart::Axis >& xAxis ); + + VAxisBase* getVAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + OUString createCIDForAxis( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + OUString createCIDForGrid( sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ); + + sal_Int32 getNumberFormatKeyForAxis( const rtl::Reference< ::chart::Axis >& xAxis + , const rtl::Reference<::chart::ChartModel>& xChartDoc); + +private: //methods + static void impl_adjustDimension( sal_Int32& rDimensionIndex ); + void impl_adjustDimensionAndIndex( sal_Int32& rDimensionIndex, sal_Int32& rAxisIndex ) const; + +protected: //member + rtl::Reference< ::chart::BaseCoordinateSystem > m_xCooSysModel; + + OUString m_aCooSysParticle; + + typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; //first index is the dimension, second index is the axis index that indicates whether this is a main or secondary axis + + rtl::Reference m_xLogicTargetForGrids; + rtl::Reference m_xLogicTargetForAxes; + rtl::Reference m_xFinalTarget; + css::drawing::HomogenMatrix m_aMatrixSceneToScreen; + + CuboidPlanePosition m_eLeftWallPos; + CuboidPlanePosition m_eBackWallPos; + CuboidPlanePosition m_eBottomPos; + + /** + * Collection of min-max suppliers which are basically different chart + * types present in the same coordinate system. This is used only for + * auto-scaling purposes. + */ + MergedMinimumAndMaximumSupplier m_aMergedMinMaxSupplier; + + css::uno::Sequence< OUString > m_aSeriesNamesForZAxis; + + typedef std::map< tFullAxisIndex, std::shared_ptr< VAxisBase > > tVAxisMap; + + tVAxisMap m_aAxisMap; + +private: + std::vector< ExplicitScaleData > m_aExplicitScales; + std::vector< ExplicitIncrementData > m_aExplicitIncrements; + + typedef std::map< tFullAxisIndex, ExplicitScaleData > tFullExplicitScaleMap; + typedef std::map< tFullAxisIndex, ExplicitIncrementData > tFullExplicitIncrementMap; + + tFullExplicitScaleMap m_aSecondaryExplicitScales; + tFullExplicitIncrementMap m_aSecondaryExplicitIncrements; + + std::unique_ptr< ExplicitCategoriesProvider > m_apExplicitCategoriesProvider; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VDataSeries.hxx b/chart2/source/view/inc/VDataSeries.hxx new file mode 100644 index 000000000..29a71918b --- /dev/null +++ b/chart2/source/view/inc/VDataSeries.hxx @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PropertyMapper.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XChartType; } +namespace com::sun::star::chart2 { class XDataSeries; } +namespace com::sun::star::chart2::data { class XDataSequence; } +namespace com::sun::star::chart2 { struct DataPointLabel; } +namespace com::sun::star::chart2 { struct Symbol; } +namespace com::sun::star::drawing { class XShapes; } + +namespace chart +{ +class ChartType; +class DataSeries; + +class VDataSequence +{ +public: + void init( const css::uno::Reference& xModel ); + bool is() const; + void clear(); + double getValue( sal_Int32 index ) const; + sal_Int32 detectNumberFormatKey( sal_Int32 index ) const; + sal_Int32 getLength() const; + + css::uno::Reference m_xModel; + mutable css::uno::Sequence m_aValues; +}; + +class VDataSeries final +{ +public: + VDataSeries( const rtl::Reference<::chart::DataSeries>& xDataSeries ); + + ~VDataSeries(); + + VDataSeries(const VDataSeries&) = delete; + const VDataSeries& operator=(const VDataSeries&) = delete; + + const rtl::Reference<::chart::DataSeries>& getModel() const; + + void setCategoryXAxis(); + void setXValues( const css::uno::Reference& xValues ); + void setXValuesIfNone( const css::uno::Reference& xValues ); + void setParticle( const OUString& rSeriesParticle ); + void setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex ); + void setPageReferenceSize( const css::awt::Size & rPageRefSize ); + + sal_Int32 getTotalPointCount() const { return m_nPointCount;} + double getXValue( sal_Int32 index ) const; + double getYValue( sal_Int32 index ) const; + + void getMinMaxXValue( double& fMin, double& fMax ) const; + + double getY_Min( sal_Int32 index ) const; + double getY_Max( sal_Int32 index ) const; + double getY_First( sal_Int32 index ) const; + double getY_Last( sal_Int32 index ) const; + + double getBubble_Size( sal_Int32 index ) const; + + double getMinimumofAllDifferentYValues( sal_Int32 index ) const; + double getMaximumofAllDifferentYValues( sal_Int32 index ) const; + + double getValueByProperty( sal_Int32 index, const OUString& rPropName ) const; + + bool hasPropertyMapping( const OUString& rPropName ) const; + + css::uno::Sequence< double > const & getAllX() const; + css::uno::Sequence< double > const & getAllY() const; + + double getXMeanValue() const; + double getYMeanValue() const; + + bool hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const; + sal_Int32 getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const; + sal_Int32 detectNumberFormatKey( sal_Int32 nPointIndex ) const; + + sal_Int32 getLabelPlacement( + sal_Int32 nPointIndex, const rtl::Reference<::chart::ChartType>& xChartType, + bool bSwapXAndY ) const; + + css::awt::Point getLabelPosition( css::awt::Point aTextShapePos, sal_Int32 nPointIndex ) const; + bool isLabelCustomPos( sal_Int32 nPointIndex ) const; + + css::uno::Reference getPropertiesOfPoint( sal_Int32 index ) const; + + const css::uno::Reference & getPropertiesOfSeries() const; + + css::chart2::Symbol* getSymbolProperties( sal_Int32 index ) const; + + css::uno::Reference getXErrorBarProperties( sal_Int32 index ) const; + + css::uno::Reference getYErrorBarProperties( sal_Int32 index ) const; + + bool hasPointOwnColor( sal_Int32 index ) const; + + css::chart2::StackingDirection getStackingDirection() const; + sal_Int32 getAttachedAxisIndex() const; + void setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex ); + + void doSortByXValues(); + + void setConnectBars( bool bConnectBars ); + bool getConnectBars() const; + + void setGroupBarsPerAxis( bool bGroupBarsPerAxis ); + bool getGroupBarsPerAxis() const; + + void setStartingAngle( sal_Int32 nStartingAngle ); + sal_Int32 getStartingAngle() const; + + void setRoleOfSequenceForDataLabelNumberFormatDetection( std::u16string_view rRole ); + + //this is only temporarily here for area chart: + std::vector> m_aPolyPolygonShape3D; + sal_Int32 m_nPolygonIndex; + double m_fLogicMinX; + double m_fLogicMaxX; + + //this is here for deep stacking: + double m_fLogicZPos;//from 0 to series count -1 + + const OUString& getCID() const { return m_aCID;} + const OUString& getSeriesParticle() const { return m_aSeriesParticle;} + const OUString& getPointCID_Stub() const { return m_aPointCID_Stub;} + OUString getErrorBarsCID( bool bYError ) const; + OUString getLabelsCID() const; + const OUString& getLabelCID_Stub() const { return m_aLabelCID_Stub;} + OUString getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const; + + css::chart2::DataPointLabel* getDataPointLabelIfLabel( sal_Int32 index ) const; + bool getTextLabelMultiPropertyLists( sal_Int32 index, tNameSequence*& pPropNames, tAnySequence*& pPropValues ) const; + + OUString getDataCurveEquationCID( sal_Int32 nCurveIndex ) const; + bool isAttributedDataPoint( sal_Int32 index ) const; + + bool isVaryColorsByPoint() const; + + void releaseShapes(); + + void setMissingValueTreatment( sal_Int32 nMissingValueTreatment ); + sal_Int32 getMissingValueTreatment() const; + + void setOldTimeBased( VDataSeries* pOldSeries, double nPercent ); + VDataSeries* createCopyForTimeBased() const; + +private: //methods + css::chart2::DataPointLabel* getDataPointLabel( sal_Int32 index ) const; + void adaptPointCache( sal_Int32 nNewPointIndex ) const; + + // for copies for time based charting + VDataSeries(); + +public: //member + rtl::Reference m_xGroupShape; + rtl::Reference m_xLabelsGroupShape; + rtl::Reference m_xErrorXBarsGroupShape; + rtl::Reference m_xErrorYBarsGroupShape; + + //the following group shapes will be created as children of m_xGroupShape on demand + //they can be used to assure that some parts of a series shape are always in front of others (e.g. symbols in front of lines) + rtl::Reference m_xFrontSubGroupShape; + rtl::Reference m_xBackSubGroupShape; + +private: //member + rtl::Reference<::chart::DataSeries> m_xDataSeries; + css::uno::Reference m_xDataSeriesProps; // cached + + //all points given by the model data (here are not only the visible points meant) + sal_Int32 m_nPointCount; + + VDataSequence m_aValues_X; + VDataSequence m_aValues_Y; + VDataSequence m_aValues_Z; + + VDataSequence m_aValues_Y_Min; + VDataSequence m_aValues_Y_Max; + VDataSequence m_aValues_Y_First; + VDataSequence m_aValues_Y_Last; + + VDataSequence m_aValues_Bubble_Size; + + VDataSequence* m_pValueSequenceForDataLabelNumberFormatDetection; + + std::map m_PropertyMap; + + mutable double m_fXMeanValue; + mutable double m_fYMeanValue; + + css::uno::Sequence m_aAttributedDataPointIndexList; + + css::chart2::StackingDirection m_eStackingDirection; + + sal_Int32 m_nAxisIndex;//indicates whether this is attached to a main or secondary axis + + bool m_bConnectBars; + + bool m_bGroupBarsPerAxis; + + sal_Int32 m_nStartingAngle; + + OUString m_aSeriesParticle; + OUString m_aCID; + OUString m_aPointCID_Stub; + OUString m_aLabelCID_Stub; + + sal_Int32 m_nGlobalSeriesIndex; + + //some cached values for data labels as they are very expensive + mutable std::unique_ptr + m_apLabel_Series; + mutable std::unique_ptr m_apLabelPropNames_Series; + mutable std::unique_ptr m_apLabelPropValues_Series; + mutable std::unique_ptr m_apSymbolProperties_Series; + + mutable std::unique_ptr + m_apLabel_AttributedPoint; + mutable std::unique_ptr m_apLabelPropNames_AttributedPoint; + mutable std::unique_ptr m_apLabelPropValues_AttributedPoint; + mutable std::unique_ptr m_apSymbolProperties_AttributedPoint; + mutable std::unique_ptr + m_apSymbolProperties_InvisibleSymbolForSelection; + mutable sal_Int32 m_nCurrentAttributedPoint; + css::awt::Size m_aReferenceSize; + + sal_Int32 m_nMissingValueTreatment; + bool m_bAllowPercentValueInDataLabel; + + // for time based charting + VDataSeries* mpOldSeries; + double mnPercent; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VDiagram.hxx b/chart2/source/view/inc/VDiagram.hxx new file mode 100644 index 000000000..ab391f7bc --- /dev/null +++ b/chart2/source/view/inc/VDiagram.hxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::chart2 { class XDiagram; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::drawing { class XShape; } + + +namespace chart +{ +class Diagram; +class ShapeFactory; + +/** The VDiagram is responsible to generate the visible parts of the Diagram +that is wall, floor, axes and data series. +The axes and data series are subobjects which are created and managed by the +diagram. +*/ + +class VDiagram final +{ +public: //methods + VDiagram( const rtl::Reference<::chart::Diagram>& xDiagram, + const css::drawing::Direction3D& rPreferredAspectRatio, + sal_Int32 nDimension ); + ~VDiagram(); + + void init( + const rtl::Reference& xTarget ); + + void createShapes( const css::awt::Point& rPos + , const css::awt::Size& rSize ); + + const rtl::Reference & + getCoordinateRegion() const { return m_xCoordinateRegionShape; } + + /** + * Get current bounding rectangle for the diagram without axes. + */ + basegfx::B2IRectangle getCurrentRectangle() const; + + void reduceToMinimumSize(); + + ::basegfx::B2IRectangle adjustPosAndSize( const css::awt::Point& rPos + , const css::awt::Size& rAvailableSize ); + + ::basegfx::B2IRectangle adjustInnerSize( const ::basegfx::B2IRectangle& rConsumedOuterRect ); + +private: //methods + void createShapes_2d(); + void createShapes_3d(); + + ::basegfx::B2IRectangle adjustPosAndSize_2d( const css::awt::Point& rPos + , const css::awt::Size& rAvailableSize ); + ::basegfx::B2IRectangle adjustPosAndSize_3d( const css::awt::Point& rPos + , const css::awt::Size& rAvailableSize ); + + void adjustAspectRatio3d( const css::awt::Size& rAvailableSize ); + +private: //members + VDiagram(const VDiagram& rD) = delete; + + rtl::Reference m_xTarget; + + // this is the surrounding shape which contains floor, wall and coordinate + rtl::Reference m_xOuterGroupShape; + // this is an additional inner shape that represents the coordinate region - that is - where to place data points + rtl::Reference m_xCoordinateRegionShape; + rtl::Reference m_xWall2D; + + sal_Int32 m_nDimensionCount; + rtl::Reference< ::chart::Diagram > m_xDiagram; + + css::drawing::Direction3D m_aPreferredAspectRatio; + css::uno::Reference< css::beans::XPropertySet > m_xAspectRatio3D; + + double m_fXAnglePi; + double m_fYAnglePi; + double m_fZAnglePi; + + css::awt::Point m_aAvailablePosIncludingAxes; + css::awt::Size m_aAvailableSizeIncludingAxes; + + css::awt::Point m_aCurrentPosWithoutAxes; + css::awt::Size m_aCurrentSizeWithoutAxes; + + bool m_bRightAngledAxes; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VLegendSymbolFactory.hxx b/chart2/source/view/inc/VLegendSymbolFactory.hxx new file mode 100644 index 000000000..f637a5894 --- /dev/null +++ b/chart2/source/view/inc/VLegendSymbolFactory.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "LegendEntryProvider.hxx" +#include +#include +#include + +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::uno { class Any; } + +namespace chart::VLegendSymbolFactory +{ + enum class PropertyType + { + FilledSeries, + LineSeries, + Line, + }; + + rtl::Reference< SvxShapeGroup > + createSymbol( + const css::awt::Size& rEntryKeyAspectRatio, + const rtl::Reference& rSymbolContainer, + LegendSymbolStyle eStyle, + const css::uno::Reference< css::beans::XPropertySet > & xLegendEntryProperties, + PropertyType ePropertyType, + const css::uno::Any& rExplicitSymbol /*should contain a css::chart2::Symbol without automatic symbol if the charttype does support symbols else empty*/); + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VLineProperties.hxx b/chart2/source/view/inc/VLineProperties.hxx new file mode 100644 index 000000000..aa1c88ce7 --- /dev/null +++ b/chart2/source/view/inc/VLineProperties.hxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::beans +{ +class XPropertySet; +} + +namespace chart +{ +struct VLineProperties +{ + css::uno::Any Color; //type sal_Int32 UNO_NAME_LINECOLOR + css::uno::Any LineStyle; //type drawing::LineStyle for property UNO_NAME_LINESTYLE + css::uno::Any Transparence; //type sal_Int16 for property UNO_NAME_LINETRANSPARENCE + css::uno::Any Width; //type sal_Int32 for property UNO_NAME_LINEWIDTH + css::uno::Any DashName; //type OUString for property "LineDashName" + css::uno::Any LineCap; //type drawing::LineCap for property UNO_NAME_LINECAP + + VLineProperties(); + void initFromPropertySet(const css::uno::Reference& xProp); + + bool isLineVisible() const; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VPolarTransformation.hxx b/chart2/source/view/inc/VPolarTransformation.hxx new file mode 100644 index 000000000..23f3c3b71 --- /dev/null +++ b/chart2/source/view/inc/VPolarTransformation.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "PlottingPositionHelper.hxx" + +namespace chart +{ + +class VPolarTransformation final : public XTransformation2 +{ +public: + VPolarTransformation( const PolarPlottingPositionHelper& rPositionHelper ); + virtual ~VPolarTransformation() override; + + // ____ XTransformation2 ____ + virtual css::drawing::Position3D transform( + const css::uno::Sequence< double >& rSourceValues ) const override; + virtual css::drawing::Position3D transform( + const css::drawing::Position3D& rSourceValues ) const override; + +private: + PolarPlottingPositionHelper m_aPositionHelper; + ::basegfx::B3DHomMatrix m_aUnitCartesianToScene; +}; + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/VSeriesPlotter.hxx b/chart2/source/view/inc/VSeriesPlotter.hxx new file mode 100644 index 000000000..ac911be46 --- /dev/null +++ b/chart2/source/view/inc/VSeriesPlotter.hxx @@ -0,0 +1,436 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include "PlotterBase.hxx" +#include "VDataSeries.hxx" +#include "LabelAlignment.hxx" +#include "MinimumAndMaximumSupplier.hxx" +#include "LegendEntryProvider.hxx" +#include +#include +#include +#include + +namespace com::sun::star::awt { struct Point; } +namespace com::sun::star::chart2 { class XChartType; } + + +namespace chart { class ExplicitCategoriesProvider; } +namespace chart { struct ExplicitScaleData; } +namespace chart { class ChartModel; } + +namespace com::sun::star { + namespace util { + class XNumberFormatsSupplier; + } + namespace chart2 { + class XColorScheme; + class XRegressionCurveCalculator; + } +} + +namespace chart { + +class ChartType; +class NumberFormatterWrapper; + +class AxesNumberFormats +{ +public: + AxesNumberFormats() {}; + + void setFormat( sal_Int32 nFormatKey, sal_Int32 nDimIndex, sal_Int32 nAxisIndex ) + { + m_aNumberFormatMap[tFullAxisIndex(nDimIndex,nAxisIndex)] = nFormatKey; + } + +private: + typedef std::pair< sal_Int32, sal_Int32 > tFullAxisIndex; + std::map< tFullAxisIndex, sal_Int32 > m_aNumberFormatMap; +}; + +/** + * A list of series that have the same CoordinateSystem. They are used to be + * plotted maybe in a stacked manner by a plotter. + */ +class VDataSeriesGroup final +{ +public: + VDataSeriesGroup() = delete; + VDataSeriesGroup( std::unique_ptr pSeries ); + VDataSeriesGroup(VDataSeriesGroup&&) noexcept; + ~VDataSeriesGroup(); + + void addSeries( std::unique_ptr pSeries );//takes ownership of pSeries + sal_Int32 getSeriesCount() const; + void deleteSeries(); + + sal_Int32 getPointCount() const; + sal_Int32 getAttachedAxisIndexForFirstSeries() const; + + void getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const; + void getMinimumAndMaximumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const; + + void calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex + , bool bSeparateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) const; + void calculateYMinAndMaxForCategoryRange( sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex + , bool bSeparateStackingForDifferentSigns + , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ); + + std::vector< std::unique_ptr > m_aSeriesVector; + +private: + //cached values + struct CachedYValues + { + CachedYValues(); + + bool m_bValuesDirty; + double m_fMinimumY; + double m_fMaximumY; + }; + + mutable bool m_bMaxPointCountDirty; + mutable sal_Int32 m_nMaxPointCount; + typedef std::map< sal_Int32, CachedYValues > tCachedYValuesPerAxisIndexMap; + mutable std::vector< tCachedYValuesPerAxisIndexMap > m_aListOfCachedYValues; +}; + +class VSeriesPlotter : public PlotterBase, public MinimumAndMaximumSupplier, public LegendEntryProvider +{ +public: + VSeriesPlotter() = delete; + + virtual ~VSeriesPlotter() override; + + /** + * A new series can be positioned relative to other series in a chart. + * This positioning has two dimensions. First a series can be placed + * next to each other on the category axis. This position is indicated by xSlot. + * Second a series can be stacked on top of another. This position is indicated by ySlot. + * The positions are counted from 0 on. + * xSlot < 0 : append the series to already existing x series + * xSlot > occupied : append the series to already existing x series + * + * If the xSlot is already occupied the given ySlot decides what should happen: + * ySlot < -1 : move all existing series in the xSlot to next slot + * ySlot == -1 : stack on top at given x position + * ySlot == already occupied : insert at given y and x position + * ySlot > occupied : stack on top at given x position + */ + virtual void addSeries( std::unique_ptr pSeries, sal_Int32 zSlot, sal_Int32 xSlot, sal_Int32 ySlot ); + + /** a value <= 0 for a directions means that this direction can be stretched arbitrary + */ + virtual css::drawing::Direction3D getPreferredDiagramAspectRatio() const; + + /** this enables you to handle series on the same x axis with different y axis + the property AttachedAxisIndex at a dataseries indicates which value scale is to use + (0==AttachedAxisIndex or a not set AttachedAxisIndex property indicates that this series should be scaled at the main y-axis; + 1==AttachedAxisIndex indicates that the series should be scaled at the first secondary axis if there is any otherwise at the main y axis + and so on. + The parameter nAxisIndex matches this DataSeries property 'AttachedAxisIndex'. + nAxisIndex must be greater than 0. nAxisIndex==1 refers to the first secondary axis. + ) + + @throws css::uno::RuntimeException + */ + + void addSecondaryValueScale( const ExplicitScaleData& rScale, sal_Int32 nAxisIndex ); + + // MinimumAndMaximumSupplier + + virtual double getMinimumX() override; + virtual double getMaximumX() override; + + virtual double getMinimumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + virtual double getMaximumYInRange( double fMinimumX, double fMaximumX, sal_Int32 nAxisIndex ) override; + + virtual double getMinimumZ() override; + virtual double getMaximumZ() override; + + virtual bool isExpandBorderToIncrementRhythm( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandIfValuesCloseToBorder( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandWideValuesToZero( sal_Int32 nDimensionIndex ) override; + virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) override; + virtual bool isSeparateStackingForDifferentSigns( sal_Int32 nDimensionIndex ) override; + + virtual tools::Long calculateTimeResolutionOnXAxis() override; + virtual void setTimeResolutionOnXAxis( tools::Long nTimeResolution, const Date& rNullDate ) override; + + void getMinimumAndMaximumX( double& rfMinimum, double& rfMaximum ) const; + void getMinimumAndMaximumYInContinuousXRange( double& rfMinY, double& rfMaxY, double fMinX, double fMaxX, sal_Int32 nAxisIndex ) const; + + + // Methods for handling legends and legend entries. + + virtual std::vector< ViewLegendEntry > createLegendEntries( + const css::awt::Size& rEntryKeyAspectRatio, + css::chart2::LegendPosition eLegendPosition, + const css::uno::Reference< css::beans::XPropertySet >& xTextProperties, + const rtl::Reference& xTarget, + const css::uno::Reference< css::uno::XComponentContext >& xContext, + ChartModel& rModel + ) override; + + virtual LegendSymbolStyle getLegendSymbolStyle(); + virtual css::awt::Size getPreferredLegendKeyAspectRatio() override; + + virtual css::uno::Any getExplicitSymbol( const VDataSeries& rSeries, sal_Int32 nPointIndex/*-1 for series symbol*/ ); + + rtl::Reference createLegendSymbolForSeries( + const css::awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , const rtl::Reference& xTarget ); + + rtl::Reference< SvxShapeGroup > createLegendSymbolForPoint( + const css::awt::Size& rEntryKeyAspectRatio + , const VDataSeries& rSeries + , sal_Int32 nPointIndex + , const rtl::Reference& xTarget ); + + std::vector< ViewLegendEntry > createLegendEntriesForSeries( + const css::awt::Size& rEntryKeyAspectRatio, + const VDataSeries& rSeries, + const css::uno::Reference< css::beans::XPropertySet >& xTextProperties, + const rtl::Reference& xTarget, + const css::uno::Reference< css::uno::XComponentContext >& xContext + ); + + std::vector getAllSeries(); + std::vector getAllSeries() const; + + // This method creates a series plotter of the requested type; e.g. : return new PieChart... + static VSeriesPlotter* createSeriesPlotter( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bExcludingPositioning /*for pie and donut charts labels and exploded segments are excluded from the given size*/); + + sal_Int32 getPointCount() const; + + // Methods for number formats and color schemes + + void setNumberFormatsSupplier( const css::uno::Reference< css::util::XNumberFormatsSupplier > & xNumFmtSupplier ); + + void setColorScheme( const css::uno::Reference< css::chart2::XColorScheme >& xColorScheme ); + + void setExplicitCategoriesProvider( ExplicitCategoriesProvider* pExplicitCategoriesProvider ); + + ExplicitCategoriesProvider* getExplicitCategoriesProvider() { return m_pExplicitCategoriesProvider; } + + //get series names for the z axis labels + css::uno::Sequence getSeriesNames() const; + + void setPageReferenceSize( const css::awt::Size & rPageRefSize ); + //better performance for big data + void setCoordinateSystemResolution( const css::uno::Sequence< sal_Int32 >& rCoordinateSystemResolution ); + bool PointsWereSkipped() const { return m_bPointsWereSkipped;} + void setPieLabelsAllowToMove( bool bIsPieOrDonut ) { m_bPieLabelsAllowToMove = bIsPieOrDonut; }; + void setAvailableOuterRect( const basegfx::B2IRectangle& aAvailableOuterRect ) { m_aAvailableOuterRect = aAvailableOuterRect; }; + + //return the depth for a logic 1 + double getTransformedDepth() const; + + void releaseShapes(); + + virtual void rearrangeLabelToAvoidOverlapIfRequested( const css::awt::Size& rPageSize ); + + bool WantToPlotInFrontOfAxisLine(); + virtual bool shouldSnapRectToUsedArea(); + +protected: + + VSeriesPlotter( const rtl::Reference< ::chart::ChartType >& xChartTypeModel + , sal_Int32 nDimensionCount + , bool bCategoryXAxis=true ); + + // Methods for group shapes. + + rtl::Reference + getSeriesGroupShape( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ); + + //the following group shapes will be created as children of SeriesGroupShape on demand + //they can be used to assure that some parts of a series shape are always in front of others (e.g. symbols in front of lines) + //parameter xTarget will be used as parent for the series group shape + rtl::Reference + getSeriesGroupShapeFrontChild( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ); + rtl::Reference + getSeriesGroupShapeBackChild( VDataSeries* pDataSeries + , const rtl::Reference& xTarget ); + + /// This method creates a 2D group shape for containing all text shapes + /// needed for this series; the group is added to the text target; + static rtl::Reference + getLabelsGroupShape( VDataSeries& rDataSeries + , const rtl::Reference& xTarget ); + + rtl::Reference + getErrorBarsGroupShape( VDataSeries& rDataSeries + , const rtl::Reference& xTarget, bool bYError ); + + /** This method creates a text shape for a label related to a data point + * and append it to the root text shape group (xTarget). + * + * @param xTarget + * the main root text shape group. + * @param rDataSeries + * the data series, the data point belongs to. + * @param nPointIndex + * the index of the data point the label is related to. + * @param fValue + * the value of the data point. + * @param fSumValue + * the sum of all data point values in the data series. + * @param rScreenPosition2D + * the anchor point position for the label. + * @param eAlignment + * the required alignment of the label. + * @param offset + * an optional offset depending on the label alignment. + * @param nTextWidth + * the maximum width of a text label (used for text wrapping). + * + * @return + * a reference to the created text shape. + */ + rtl::Reference + createDataLabel( const rtl::Reference& xTarget + , VDataSeries& rDataSeries + , sal_Int32 nPointIndex + , double fValue + , double fSumValue + , const css::awt::Point& rScreenPosition2D + , LabelAlignment eAlignment + , sal_Int32 nOffset=0 + , sal_Int32 nTextWidth = 0 ); + + /// This method returns a text string representation of the passed numeric + /// value by exploiting a NumberFormatterWrapper object. + OUString getLabelTextForValue( VDataSeries const & rDataSeries + , sal_Int32 nPointIndex + , double fValue + , bool bAsPercentage ); + + /** creates two T-shaped error bars in both directions (up/down or + left/right depending on the bVertical parameter) + + @param rPos + logic coordinates + + @param xErrorBarProperties + the XPropertySet returned by the DataPoint-property "ErrorBarX" or + "ErrorBarY". + + @param nIndex + the index of the data point in rData for which the calculation is + done. + + @param bVertical + for y-error bars this is true, for x-error-bars it is false. + */ + void createErrorBar( + const rtl::Reference& xTarget + , const css::drawing::Position3D & rPos + , const css::uno::Reference< css::beans::XPropertySet > & xErrorBarProperties + , const VDataSeries& rVDataSeries + , sal_Int32 nIndex + , bool bVertical + , const double* pfScaledLogicX + ); + + void createErrorRectangle( + const css::drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries + , sal_Int32 nIndex + , const rtl::Reference& rTarget + , bool bUseXErrorData + , bool bUseYErrorData + ); + + static void addErrorBorder( + const css::drawing::Position3D& rPos0 + , const css::drawing::Position3D& rPos1 + , const rtl::Reference& rTarget + , const css::uno::Reference< css::beans::XPropertySet >& rErrorBorderProp ); + + void createErrorBar_X( const css::drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries, sal_Int32 nPointIndex + , const rtl::Reference& xTarget ); + + void createErrorBar_Y( const css::drawing::Position3D& rUnscaledLogicPosition + , VDataSeries& rVDataSeries, sal_Int32 nPointIndex + , const rtl::Reference& xTarget + , double const * pfScaledLogicX ); + + void createRegressionCurvesShapes( VDataSeries const & rVDataSeries + , const rtl::Reference& xTarget + , const rtl::Reference& xEquationTarget + , bool bMaySkipPointsInRegressionCalculation ); + + void createRegressionCurveEquationShapes( const OUString & rEquationCID + , const css::uno::Reference< css::beans::XPropertySet > & xEquationProperties + , const rtl::Reference& xEquationTarget + , const css::uno::Reference< css::chart2::XRegressionCurveCalculator > & xRegressionCurveCalculator + , css::awt::Point aDefaultPos ); + + virtual PlottingPositionHelper& getPlottingPositionHelper( sal_Int32 nAxisIndex ) const;//nAxisIndex indicates whether the position belongs to the main axis ( nAxisIndex==0 ) or secondary axis ( nAxisIndex==1 ) + + VDataSeries* getFirstSeries() const; + + OUString getCategoryName( sal_Int32 nPointIndex ) const; + +protected: + PlottingPositionHelper* m_pMainPosHelper; + + rtl::Reference< ::chart::ChartType > m_xChartTypeModel; + + std::vector< std::vector< VDataSeriesGroup > > m_aZSlots; + + bool m_bCategoryXAxis;//true->xvalues are indices (this would not be necessary if series for category chart wouldn't have x-values) + tools::Long m_nTimeResolution; + Date m_aNullDate; + + std::unique_ptr< NumberFormatterWrapper > m_apNumberFormatterWrapper; + + css::uno::Reference< css::chart2::XColorScheme > m_xColorScheme; + + ExplicitCategoriesProvider* m_pExplicitCategoriesProvider; + + //better performance for big data + css::uno::Sequence< sal_Int32 > m_aCoordinateSystemResolution; + bool m_bPointsWereSkipped; + bool m_bPieLabelsAllowToMove; + basegfx::B2IRectangle m_aAvailableOuterRect; + css::awt::Size m_aPageReferenceSize; + +private: + typedef std::map< sal_Int32 , ExplicitScaleData > tSecondaryValueScales; + tSecondaryValueScales m_aSecondaryValueScales; + + typedef std::map< sal_Int32 , std::unique_ptr > tSecondaryPosHelperMap; + mutable tSecondaryPosHelperMap m_aSecondaryPosHelperMap; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/inc/ViewDefines.hxx b/chart2/source/view/inc/ViewDefines.hxx new file mode 100644 index 000000000..b8b82be95 --- /dev/null +++ b/chart2/source/view/inc/ViewDefines.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace chart +{ +#define CHART_3DOBJECT_SEGMENTCOUNT (sal_Int32(32)) +//There needs to be a little distance between grid lines and walls in 3D, otherwise the lines are partly hidden by the walls +#define GRID_TO_WALL_DISTANCE (1.0) + +const double ZDIRECTION = 1.0; +const sal_Int32 AXIS2D_TICKLENGTH = 150; //value like in old chart +const sal_Int32 AXIS2D_TICKLABELSPACING = 100; //value like in old chart + +} //end namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/AxisUsage.hxx b/chart2/source/view/main/AxisUsage.hxx new file mode 100644 index 000000000..834518707 --- /dev/null +++ b/chart2/source/view/main/AxisUsage.hxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace chart +{ +//first index is the dimension, second index is the axis index that indicates whether this is a main or secondary axis +typedef std::pair tFullAxisIndex; +typedef std::map tCoordinateSystemMap; + +/** This class handles a collection of coordinate systems and is used for + * executing some action on all coordinate systems such as + * "prepareAutomaticAxisScaling" and "setExplicitScaleAndIncrement". + * Moreover it contains the "aAutoScaling" object that is an instance of + * the "ScaleAutomatism" class. The initialization of "aAutoScaling" is + * performed in the "SeriesPlotterContainer::initAxisUsageList" method and is + * used in the "SeriesPlotterContainer::doAutoScaling" for calculating explicit + * scale and increment objects (see "SeriesPlotterContainer::doAutoScaling"). + */ +class AxisUsage +{ +public: + AxisUsage() + : aAutoScaling(AxisHelper::createDefaultScale(), Date(Date::SYSTEM)) + { + } + + void 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 + auto 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 getCoordinateSystems(sal_Int32 nDimensionIndex, + sal_Int32 nAxisIndex) + { + std::vector aRet; + + for (auto const& coordinateSystem : aCoordinateSystems) + { + if (coordinateSystem.second.first != nDimensionIndex) + continue; + if (coordinateSystem.second.second != nAxisIndex) + continue; + aRet.push_back(coordinateSystem.first); + } + + return aRet; + } + + sal_Int32 getMaxAxisIndexForDimension(sal_Int32 nDimensionIndex) + { + sal_Int32 nRet = -1; + auto aIter = aMaxIndexPerDimension.find(nDimensionIndex); + if (aIter != aMaxIndexPerDimension.end()) + nRet = aIter->second; + return nRet; + } + + void prepareAutomaticAxisScaling(ScaleAutomatism& rScaleAutomatism, sal_Int32 nDimIndex, + sal_Int32 nAxisIndex) + { + std::vector aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); + for (VCoordinateSystem* pVCoordinateSystem : aVCooSysList) + pVCoordinateSystem->prepareAutomaticAxisScaling(rScaleAutomatism, nDimIndex, + nAxisIndex); + } + + void setExplicitScaleAndIncrement(sal_Int32 nDimIndex, sal_Int32 nAxisIndex, + const ExplicitScaleData& rScale, + const ExplicitIncrementData& rInc) + { + std::vector aVCooSysList = getCoordinateSystems(nDimIndex, nAxisIndex); + for (VCoordinateSystem* pVCoordinateSystem : aVCooSysList) + pVCoordinateSystem->setExplicitScaleAndIncrement(nDimIndex, nAxisIndex, rScale, rInc); + } + + ScaleAutomatism aAutoScaling; + +private: + tCoordinateSystemMap aCoordinateSystems; + std::map aMaxIndexPerDimension; +}; + +} //end chart2 namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx new file mode 100644 index 000000000..3410bcdbf --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.cxx @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ChartItemPool.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace chart +{ + +ChartItemPool::ChartItemPool(): + SfxItemPool( "ChartItemPool" , SCHATTR_START, SCHATTR_END, nullptr, nullptr ), + pItemInfos(new SfxItemInfo[SCHATTR_END - SCHATTR_START + 1]) +{ + /************************************************************************** + * PoolDefaults + **************************************************************************/ + std::vector* ppPoolDefaults = new std::vector(SCHATTR_END - SCHATTR_START + 1); + std::vector& rPoolDefaults = *ppPoolDefaults; + rPoolDefaults[SCHATTR_DATADESCR_SHOW_NUMBER - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_NUMBER); + rPoolDefaults[SCHATTR_DATADESCR_SHOW_PERCENTAGE- SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_PERCENTAGE); + rPoolDefaults[SCHATTR_DATADESCR_SHOW_CATEGORY - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_CATEGORY); + rPoolDefaults[SCHATTR_DATADESCR_SHOW_SYMBOL - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_SYMBOL); + rPoolDefaults[SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_SHOW_DATA_SERIES_NAME); + rPoolDefaults[SCHATTR_DATADESCR_WRAP_TEXT - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_WRAP_TEXT); + rPoolDefaults[SCHATTR_DATADESCR_SEPARATOR - SCHATTR_START] = new SfxStringItem(SCHATTR_DATADESCR_SEPARATOR," "); + rPoolDefaults[SCHATTR_DATADESCR_PLACEMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_DATADESCR_PLACEMENT,0); + rPoolDefaults[SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_DATADESCR_AVAILABLE_PLACEMENTS, std::vector < sal_Int32 >() ); + rPoolDefaults[SCHATTR_DATADESCR_NO_PERCENTVALUE - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_NO_PERCENTVALUE); + rPoolDefaults[SCHATTR_DATADESCR_CUSTOM_LEADER_LINES - SCHATTR_START] = new SfxBoolItem(SCHATTR_DATADESCR_CUSTOM_LEADER_LINES, true); + rPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_VALUE - SCHATTR_START] = new SfxUInt32Item(SCHATTR_PERCENT_NUMBERFORMAT_VALUE, 0); + rPoolDefaults[SCHATTR_PERCENT_NUMBERFORMAT_SOURCE - SCHATTR_START] = new SfxBoolItem(SCHATTR_PERCENT_NUMBERFORMAT_SOURCE); + + //legend + rPoolDefaults[SCHATTR_LEGEND_POS - SCHATTR_START] = new SfxInt32Item(SCHATTR_LEGEND_POS, sal_Int32(css::chart2::LegendPosition_LINE_END) ); + rPoolDefaults[SCHATTR_LEGEND_SHOW - SCHATTR_START] = new SfxBoolItem(SCHATTR_LEGEND_SHOW, true); + rPoolDefaults[SCHATTR_LEGEND_NO_OVERLAY - SCHATTR_START] = new SfxBoolItem(SCHATTR_LEGEND_NO_OVERLAY, true); + + //text + rPoolDefaults[SCHATTR_TEXT_DEGREES - SCHATTR_START] = new SdrAngleItem(SCHATTR_TEXT_DEGREES, 0_deg100); + rPoolDefaults[SCHATTR_TEXT_STACKED - SCHATTR_START] = new SfxBoolItem(SCHATTR_TEXT_STACKED,false); + + //statistic + rPoolDefaults[SCHATTR_STAT_AVERAGE - SCHATTR_START] = new SfxBoolItem (SCHATTR_STAT_AVERAGE); + rPoolDefaults[SCHATTR_STAT_KIND_ERROR - SCHATTR_START] = new SvxChartKindErrorItem (SvxChartKindError::NONE, SCHATTR_STAT_KIND_ERROR); + rPoolDefaults[SCHATTR_STAT_PERCENT - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_PERCENT); + rPoolDefaults[SCHATTR_STAT_BIGERROR - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_BIGERROR); + rPoolDefaults[SCHATTR_STAT_CONSTPLUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTPLUS); + rPoolDefaults[SCHATTR_STAT_CONSTMINUS - SCHATTR_START] = new SvxDoubleItem (0.0, SCHATTR_STAT_CONSTMINUS); + rPoolDefaults[SCHATTR_STAT_INDICATE - SCHATTR_START] = new SvxChartIndicateItem (SvxChartIndicate::NONE, SCHATTR_STAT_INDICATE); + rPoolDefaults[SCHATTR_STAT_RANGE_POS - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_POS, OUString()); + rPoolDefaults[SCHATTR_STAT_RANGE_NEG - SCHATTR_START] = new SfxStringItem (SCHATTR_STAT_RANGE_NEG, OUString()); + rPoolDefaults[SCHATTR_STAT_ERRORBAR_TYPE - SCHATTR_START] = new SfxBoolItem(SCHATTR_STAT_ERRORBAR_TYPE, true); + + rPoolDefaults[SCHATTR_STYLE_DEEP - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_DEEP, false); + rPoolDefaults[SCHATTR_STYLE_3D - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_3D, false); + rPoolDefaults[SCHATTR_STYLE_VERTICAL - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_VERTICAL, false); + rPoolDefaults[SCHATTR_STYLE_BASETYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_STYLE_BASETYPE, 0); + rPoolDefaults[SCHATTR_STYLE_LINES - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_LINES, false); + rPoolDefaults[SCHATTR_STYLE_PERCENT - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_PERCENT, false); + rPoolDefaults[SCHATTR_STYLE_STACKED - SCHATTR_START] = new SfxBoolItem (SCHATTR_STYLE_STACKED, false); + rPoolDefaults[SCHATTR_STYLE_SPLINES - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SPLINES, 0); //Bug: was Bool! test ->Fileformat (touches only 5's) + rPoolDefaults[SCHATTR_STYLE_SYMBOL - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SYMBOL, 0); + rPoolDefaults[SCHATTR_STYLE_SHAPE - SCHATTR_START] = new SfxInt32Item (SCHATTR_STYLE_SHAPE, 0); + + rPoolDefaults[SCHATTR_AXIS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS,2); //2 = Y-Axis!!! + + //axis scale + rPoolDefaults[SCHATTR_AXISTYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXISTYPE, CHART_AXIS_REALNUMBER); + rPoolDefaults[SCHATTR_AXIS_REVERSE - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_REVERSE,false); + rPoolDefaults[SCHATTR_AXIS_AUTO_MIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MIN); + rPoolDefaults[SCHATTR_AXIS_MIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MIN); + rPoolDefaults[SCHATTR_AXIS_AUTO_MAX - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_MAX); + rPoolDefaults[SCHATTR_AXIS_MAX - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_MAX); + rPoolDefaults[SCHATTR_AXIS_AUTO_STEP_MAIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_MAIN); + rPoolDefaults[SCHATTR_AXIS_STEP_MAIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_STEP_MAIN); + rPoolDefaults[SCHATTR_AXIS_MAIN_TIME_UNIT - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_MAIN_TIME_UNIT,2); + rPoolDefaults[SCHATTR_AXIS_AUTO_STEP_HELP - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_STEP_HELP); + rPoolDefaults[SCHATTR_AXIS_STEP_HELP - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_STEP_HELP,0); + rPoolDefaults[SCHATTR_AXIS_HELP_TIME_UNIT - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_HELP_TIME_UNIT,2); + rPoolDefaults[SCHATTR_AXIS_AUTO_TIME_RESOLUTION - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_TIME_RESOLUTION); + rPoolDefaults[SCHATTR_AXIS_TIME_RESOLUTION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_TIME_RESOLUTION,2); + rPoolDefaults[SCHATTR_AXIS_LOGARITHM - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LOGARITHM); + rPoolDefaults[SCHATTR_AXIS_AUTO_DATEAXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_DATEAXIS); + rPoolDefaults[SCHATTR_AXIS_ALLOW_DATEAXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_ALLOW_DATEAXIS); + rPoolDefaults[SCHATTR_AXIS_AUTO_ORIGIN - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_AUTO_ORIGIN); + rPoolDefaults[SCHATTR_AXIS_ORIGIN - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_ORIGIN); + + //axis position + rPoolDefaults[SCHATTR_AXIS_TICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_TICKS,CHAXIS_MARK_OUTER); + rPoolDefaults[SCHATTR_AXIS_HELPTICKS - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_HELPTICKS,0); + rPoolDefaults[SCHATTR_AXIS_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_POSITION,0); + rPoolDefaults[SCHATTR_AXIS_POSITION_VALUE - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_AXIS_POSITION_VALUE); + rPoolDefaults[SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT - SCHATTR_START] = new SfxUInt32Item(SCHATTR_AXIS_CROSSING_MAIN_AXIS_NUMBERFORMAT,0); + rPoolDefaults[SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHIFTED_CATEGORY_POSITION,false); + rPoolDefaults[SCHATTR_AXIS_LABEL_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_LABEL_POSITION,0); + rPoolDefaults[SCHATTR_AXIS_MARK_POSITION - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_MARK_POSITION,0); + + //axis label + rPoolDefaults[SCHATTR_AXIS_SHOWDESCR - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_SHOWDESCR,false); + rPoolDefaults[SCHATTR_AXIS_LABEL_ORDER - SCHATTR_START] = new SvxChartTextOrderItem(SvxChartTextOrder::SideBySide, SCHATTR_AXIS_LABEL_ORDER); + rPoolDefaults[SCHATTR_AXIS_LABEL_OVERLAP - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LABEL_OVERLAP,false); + rPoolDefaults[SCHATTR_AXIS_LABEL_BREAK - SCHATTR_START] = new SfxBoolItem(SCHATTR_AXIS_LABEL_BREAK, false ); + + rPoolDefaults[SCHATTR_SYMBOL_BRUSH - SCHATTR_START] = new SvxBrushItem(SCHATTR_SYMBOL_BRUSH); + rPoolDefaults[SCHATTR_STOCK_VOLUME - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_VOLUME,false); + rPoolDefaults[SCHATTR_STOCK_UPDOWN - SCHATTR_START] = new SfxBoolItem(SCHATTR_STOCK_UPDOWN,false); + rPoolDefaults[SCHATTR_SYMBOL_SIZE - SCHATTR_START] = new SvxSizeItem(SCHATTR_SYMBOL_SIZE,Size(0,0)); + rPoolDefaults[SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY - SCHATTR_START] = new SfxBoolItem(SCHATTR_HIDE_DATA_POINT_LEGEND_ENTRY, false); + + // new for New Chart + rPoolDefaults[SCHATTR_BAR_OVERLAP - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_OVERLAP,0); + rPoolDefaults[SCHATTR_BAR_GAPWIDTH - SCHATTR_START] = new SfxInt32Item(SCHATTR_BAR_GAPWIDTH,0); + rPoolDefaults[SCHATTR_BAR_CONNECT - SCHATTR_START] = new SfxBoolItem(SCHATTR_BAR_CONNECT, false); + rPoolDefaults[SCHATTR_NUM_OF_LINES_FOR_BAR - SCHATTR_START] = new SfxInt32Item( SCHATTR_NUM_OF_LINES_FOR_BAR, 0 ); + rPoolDefaults[SCHATTR_SPLINE_ORDER - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_ORDER, 3 ); + rPoolDefaults[SCHATTR_SPLINE_RESOLUTION - SCHATTR_START] = new SfxInt32Item( SCHATTR_SPLINE_RESOLUTION, 20 ); + rPoolDefaults[SCHATTR_GROUP_BARS_PER_AXIS - SCHATTR_START] = new SfxBoolItem(SCHATTR_GROUP_BARS_PER_AXIS, false); + rPoolDefaults[SCHATTR_STARTING_ANGLE - SCHATTR_START] = new SdrAngleItem( SCHATTR_STARTING_ANGLE, 9000_deg100 ); + rPoolDefaults[SCHATTR_CLOCKWISE - SCHATTR_START] = new SfxBoolItem( SCHATTR_CLOCKWISE, false ); + + rPoolDefaults[SCHATTR_MISSING_VALUE_TREATMENT - SCHATTR_START] = new SfxInt32Item(SCHATTR_MISSING_VALUE_TREATMENT, 0); + rPoolDefaults[SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS - SCHATTR_START] = new SfxIntegerListItem(SCHATTR_AVAILABLE_MISSING_VALUE_TREATMENTS, std::vector < sal_Int32 >() ); + rPoolDefaults[SCHATTR_INCLUDE_HIDDEN_CELLS - SCHATTR_START] = new SfxBoolItem(SCHATTR_INCLUDE_HIDDEN_CELLS, true); + rPoolDefaults[SCHATTR_HIDE_LEGEND_ENTRY - SCHATTR_START] = new SfxBoolItem(SCHATTR_HIDE_LEGEND_ENTRY, false); + + rPoolDefaults[SCHATTR_AXIS_FOR_ALL_SERIES - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_FOR_ALL_SERIES, 0); + + rPoolDefaults[SCHATTR_REGRESSION_TYPE - SCHATTR_START] = new SvxChartRegressItem (SvxChartRegress::NONE, SCHATTR_REGRESSION_TYPE); + rPoolDefaults[SCHATTR_REGRESSION_SHOW_EQUATION - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_EQUATION, false); + rPoolDefaults[SCHATTR_REGRESSION_SHOW_COEFF - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_COEFF, false); + rPoolDefaults[SCHATTR_REGRESSION_DEGREE - SCHATTR_START] = new SfxInt32Item(SCHATTR_REGRESSION_DEGREE, 2); + rPoolDefaults[SCHATTR_REGRESSION_PERIOD - SCHATTR_START] = new SfxInt32Item(SCHATTR_REGRESSION_PERIOD, 2); + rPoolDefaults[SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD); + rPoolDefaults[SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD); + rPoolDefaults[SCHATTR_REGRESSION_SET_INTERCEPT - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SET_INTERCEPT, false); + rPoolDefaults[SCHATTR_REGRESSION_INTERCEPT_VALUE - SCHATTR_START] = new SvxDoubleItem(0.0, SCHATTR_REGRESSION_INTERCEPT_VALUE); + rPoolDefaults[SCHATTR_REGRESSION_CURVE_NAME - SCHATTR_START] = new SfxStringItem(SCHATTR_REGRESSION_CURVE_NAME, OUString()); + rPoolDefaults[SCHATTR_REGRESSION_XNAME - SCHATTR_START] = new SfxStringItem(SCHATTR_REGRESSION_XNAME, "x"); + rPoolDefaults[SCHATTR_REGRESSION_YNAME - SCHATTR_START] = new SfxStringItem(SCHATTR_REGRESSION_YNAME, "f(x)"); + rPoolDefaults[SCHATTR_REGRESSION_MOVING_TYPE - SCHATTR_START] = new SfxInt32Item(SCHATTR_REGRESSION_MOVING_TYPE, css::chart2::MovingAverageType::Prior); + + /************************************************************************** + * ItemInfos + **************************************************************************/ + const sal_uInt16 nMax = SCHATTR_END - SCHATTR_START + 1; + for( sal_uInt16 i = 0; i < nMax; i++ ) + { + pItemInfos[i]._nSID = 0; + pItemInfos[i]._bPoolable = true; + } + + // 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.get()); +} + +ChartItemPool::ChartItemPool(const ChartItemPool& rPool): + SfxItemPool(rPool) +{ +} + +ChartItemPool::~ChartItemPool() +{ + Delete(); + // release and delete static pool default items + ReleaseDefaults(true); +} + +rtl::Reference ChartItemPool::Clone() const +{ + return new ChartItemPool(*this); +} + +MapUnit ChartItemPool::GetMetric(sal_uInt16 /* nWhich */) const +{ + return MapUnit::Map100thMM; +} + +rtl::Reference ChartItemPool::CreateChartItemPool() +{ + return new ChartItemPool(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ChartItemPool.hxx b/chart2/source/view/main/ChartItemPool.hxx new file mode 100644 index 000000000..74a7ab1eb --- /dev/null +++ b/chart2/source/view/main/ChartItemPool.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace chart +{ +class ChartItemPool : public SfxItemPool +{ +private: + std::unique_ptr pItemInfos; + +public: + ChartItemPool(); + ChartItemPool(const ChartItemPool& rPool); + virtual ~ChartItemPool() override; + + virtual rtl::Reference Clone() const override; + MapUnit GetMetric(sal_uInt16 nWhich) const override; + + /// creates a pure chart item pool + static rtl::Reference CreateChartItemPool(); +}; + +} // namespace chart + +// INCLUDED_CHART2_SOURCE_VIEW_MAIN_CHARTITEMPOOL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ChartView.cxx b/chart2/source/view/main/ChartView.cxx new file mode 100644 index 000000000..3f96a68b2 --- /dev/null +++ b/chart2/source/view/main/ChartView.cxx @@ -0,0 +1,2035 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "SeriesPlotterContainer.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include "VTitle.hxx" +#include "VButton.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "VLegend.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AxisUsage.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include +#include + +#include +#include + +namespace com::sun::star::chart2 { class XChartDocument; } + +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; + +struct CreateShapeParam2D +{ + css::awt::Rectangle maRemainingSpace; + + std::shared_ptr mpSeriesPlotterContainer; + + std::shared_ptr mpVTitleX; + std::shared_ptr mpVTitleY; + std::shared_ptr mpVTitleZ; + + std::shared_ptr mpVTitleSecondX; + std::shared_ptr mpVTitleSecondY; + + rtl::Reference mxMarkHandles; + rtl::Reference mxPlotAreaWithAxes; + + rtl::Reference mxDiagramWithAxesShapes; + + bool mbAutoPosTitleX; + bool mbAutoPosTitleY; + bool mbAutoPosTitleZ; + + bool mbAutoPosSecondTitleX; + bool mbAutoPosSecondTitleY; + + bool mbUseFixedInnerSize; + + CreateShapeParam2D() : + mbAutoPosTitleX(true), + mbAutoPosTitleY(true), + mbAutoPosTitleZ(true), + mbAutoPosSecondTitleX(true), + mbAutoPosSecondTitleY(true), + mbUseFixedInnerSize(false) {} +}; + + + +ChartView::ChartView( + uno::Reference const & xContext, + ChartModel& rModel) + : m_xCC(xContext) + , mrChartModel(rModel) + , 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(false) + , m_aResultingDiagramRectangleExcludingAxes(0,0,0,0) +{ + init(); +} + +void ChartView::init() +{ + if( !m_pDrawModelWrapper ) + { + SolarMutexGuard aSolarGuard; + m_pDrawModelWrapper = std::make_shared< DrawModelWrapper >(); + m_xShapeFactory = m_pDrawModelWrapper->getShapeFactory(); + m_xDrawPage = m_pDrawModelWrapper->getMainDrawPage(); + StartListening( m_pDrawModelWrapper->getSdrModel() ); + } +} + +void SAL_CALL ChartView::initialize( const uno::Sequence< uno::Any >& ) +{ + init(); +} + +ChartView::~ChartView() +{ + maTimeBased.maTimer.Stop(); + // #i120831#. In ChartView::initialize(), m_xShapeFactory is created from SdrModel::getUnoModel() and indirectly + // from SfxBaseModel, it needs call dispose() to make sure SfxBaseModel object is freed correctly. + uno::Reference< lang::XComponent > xComp( m_xShapeFactory, uno::UNO_QUERY); + if ( xComp.is() ) + xComp->dispose(); + + if( m_pDrawModelWrapper ) + { + SolarMutexGuard aSolarGuard; + EndListening( m_pDrawModelWrapper->getSdrModel() ); + m_pDrawModelWrapper.reset(); + } + m_xDrawPage = nullptr; + impl_deleteCoordinateSystems(); +} + +void ChartView::impl_deleteCoordinateSystems() +{ + //delete all coordinate systems + m_aVCooSysList.clear(); +} + +// datatransfer::XTransferable +namespace +{ +constexpr OUStringLiteral lcl_aGDIMetaFileMIMEType( + u"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"" ); +constexpr OUStringLiteral lcl_aGDIMetaFileMIMETypeHighContrast( + u"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; + + // creating the graphic exporter + uno::Reference< drawing::XGraphicExportFilter > xExporter = drawing::GraphicExportFilter::create( m_xCC ); + + uno::Sequence< beans::PropertyValue > aFilterData{ + comphelper::makePropertyValue("ExportOnlyBackground", false), + comphelper::makePropertyValue("HighContrast", bUseHighContrast), + comphelper::makePropertyValue("Version", sal_Int32(SOFFICE_FILEFORMAT_50)), + comphelper::makePropertyValue("CurrentPage", uno::Reference< uno::XInterface >( static_cast(m_xDrawPage.get()), uno::UNO_QUERY )), + //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100% + comphelper::makePropertyValue("ScaleXNumerator", m_nScaleXNumerator), + comphelper::makePropertyValue("ScaleXDenominator", m_nScaleXDenominator), + comphelper::makePropertyValue("ScaleYNumerator", m_nScaleYNumerator), + comphelper::makePropertyValue("ScaleYDenominator", m_nScaleYDenominator) + }; + + uno::Sequence< beans::PropertyValue > aProps{ + comphelper::makePropertyValue("FilterName", OUString("SVM")), + comphelper::makePropertyValue("OutputStream", xOutStream), + comphelper::makePropertyValue("FilterData", aFilterData) + }; + + xExporter->setSourceDocument( m_xDrawPage ); + if( xExporter->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 ) +{ + bool bHighContrastMetaFile( aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast); + uno::Any aRet; + if( ! (bHighContrastMetaFile || aFlavor.MimeType == lcl_aGDIMetaFileMIMEType) ) + return aRet; + + update(); + + SvMemoryStream aStream( 1024, 1024 ); + rtl::Reference pStreamWrapper = new utl::OStreamWrapper( aStream ); + + this->getMetaFile( pStreamWrapper, bHighContrastMetaFile ); + + pStreamWrapper->seek(0); + sal_Int32 nBytesToRead = pStreamWrapper->available(); + uno::Sequence< sal_Int8 > aSeq( nBytesToRead ); + pStreamWrapper->readBytes( aSeq, nBytesToRead); + aRet <<= aSeq; + pStreamWrapper->closeInput(); + + return aRet; +} +uno::Sequence< datatransfer::DataFlavor > SAL_CALL ChartView::getTransferDataFlavors() +{ + return + { + { lcl_aGDIMetaFileMIMEType, "GDIMetaFile", cppu::UnoType>::get() }, + { lcl_aGDIMetaFileMIMETypeHighContrast, "GDIMetaFile", cppu::UnoType>::get() } + }; +} +sal_Bool SAL_CALL ChartView::isDataFlavorSupported( const datatransfer::DataFlavor& aFlavor ) +{ + return ( aFlavor.MimeType == lcl_aGDIMetaFileMIMEType || + aFlavor.MimeType == lcl_aGDIMetaFileMIMETypeHighContrast ); +} + +// ____ XUnoTunnel ___ +::sal_Int64 SAL_CALL ChartView::getSomething( const uno::Sequence< ::sal_Int8 >& aIdentifier ) +{ + return comphelper::getSomethingImpl(aIdentifier, this); +} + +// lang::XServiceInfo + +OUString SAL_CALL ChartView::getImplementationName() +{ + return CHART_VIEW_SERVICE_IMPLEMENTATION_NAME; +} + +sal_Bool SAL_CALL ChartView::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ChartView::getSupportedServiceNames() +{ + return { CHART_VIEW_SERVICE_NAME }; +} + +static ::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; +} + +namespace +{ + +bool lcl_IsPieOrDonut( const rtl::Reference< Diagram >& 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( const std::shared_ptr< DrawModelWrapper >& pDrawModelWrapper, ChartModel& rModel) +{ + //get writing mode from parent document: + if( !SvtCTLOptions().IsCTLFontEnabled() ) + return; + + try + { + sal_Int16 nWritingMode=-1; + uno::Reference< beans::XPropertySet > xParentProps( rModel.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( "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( "com.sun.star.drawing.Defaults" ), uno::UNO_QUERY ); + if( xDrawDefaults.is() ) + xDrawDefaults->getPropertyValue( "WritingMode" ) >>= nWritingMode; + } + } + else + { + uno::Reference< container::XNameAccess > xPageStyles( xStylesFamilies->getByName( "PageStyles" ), uno::UNO_QUERY ); + if( xPageStyles.is() ) + { + 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< OUString > aNames( xEmbeddedObjects->getElementNames() ); + + sal_Int32 nCount = aNames.getLength(); + for( sal_Int32 nN=0; nN xEmbeddedProps( xEmbeddedObjects->getByName( aNames[nN] ), uno::UNO_QUERY ); + if( xEmbeddedProps.is() ) + { + static OUString aChartCLSID = SvGlobalName( SO3_SCH_CLASSID ).GetHexName(); + OUString aCLSID; + xEmbeddedProps->getPropertyValue( "CLSID" ) >>= aCLSID; + if( aCLSID == aChartCLSID ) + { + 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( "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( "PageStyleName" ) >>= aPageStyle; + } + } + } + break; + } + } + } + } + } + if( aPageStyle.isEmpty() ) + { + 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( "PageStyleName" ) >>= aPageStyle; + } + } + if(aPageStyle.isEmpty()) + aPageStyle = "Standard"; + } + else + { + //Calc is parent document + Reference< com::sun::star::beans::XPropertySetInfo > xInfo = xParentProps->getPropertySetInfo(); + if (xInfo->hasPropertyByName("PageStyle")) + { + xParentProps->getPropertyValue( "PageStyle" ) >>= aPageStyle; + } + if(aPageStyle.isEmpty()) + aPageStyle = "Default"; + } + if( nWritingMode == -1 || nWritingMode == text::WritingMode2::PAGE ) + { + uno::Reference< beans::XPropertySet > xPageStyle( xPageStyles->getByName( aPageStyle ), uno::UNO_QUERY ); + Reference< com::sun::star::beans::XPropertySetInfo > xInfo = xPageStyle->getPropertySetInfo(); + if (xInfo->hasPropertyByName("WritingMode")) + { + if( xPageStyle.is() ) + xPageStyle->getPropertyValue( "WritingMode" ) >>= nWritingMode; + } + } + } + } + } + } + if( nWritingMode != -1 && nWritingMode != text::WritingMode2::PAGE ) + { + if( pDrawModelWrapper ) + pDrawModelWrapper->GetItemPool().SetPoolDefaultItem(SvxFrameDirectionItem(static_cast(nWritingMode), EE_PARA_WRITINGDIR) ); + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +sal_Int16 lcl_getDefaultWritingModeFromPool( const std::shared_ptr& pDrawModelWrapper ) +{ + sal_Int16 nWritingMode = text::WritingMode2::LR_TB; + if(!pDrawModelWrapper) + return nWritingMode; + + const SfxPoolItem& rItem = pDrawModelWrapper->GetItemPool().GetDefaultItem(EE_PARA_WRITINGDIR); + nWritingMode + = static_cast(static_cast(rItem).GetValue()); + return nWritingMode; +} + +} //end anonymous namespace + +awt::Rectangle ChartView::impl_createDiagramAndContent( const CreateShapeParam2D& rParam, const awt::Size& rPageSize ) +{ + //return the used rectangle + awt::Rectangle aUsedOuterRect(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y, 0, 0); + + rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); + if( !xDiagram.is()) + return aUsedOuterRect; + + sal_Int32 nDimensionCount = DiagramHelper::getDimension( xDiagram ); + if(!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + basegfx::B2IRectangle aAvailableOuterRect = BaseGFXHelper::makeRectangle(rParam.maRemainingSpace); + + const std::vector< std::unique_ptr >& rVCooSysList( rParam.mpSeriesPlotterContainer->getCooSysList() ); + auto& rSeriesPlotterList = rParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + + //create VAxis, so they can give necessary information for automatic scaling + uno::Reference const xNumberFormatsSupplier( + mrChartModel.getNumberFormatsSupplier()); + + for (auto& rpVCooSys : rVCooSysList) + { + if (nDimensionCount == 3) + { + CuboidPlanePosition eLeftWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( xDiagram ) ); + CuboidPlanePosition eBackWallPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( xDiagram ) ); + CuboidPlanePosition eBottomPos( ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( xDiagram ) ); + rpVCooSys->set3DWallPositions( eLeftWallPos, eBackWallPos, eBottomPos ); + } + + rpVCooSys->createVAxisList(&mrChartModel, rPageSize, rParam.maRemainingSpace, rParam.mbUseFixedInnerSize); + } + + // - prepare list of all axis and how they are used + Date aNullDate = NumberFormatterWrapper( xNumberFormatsSupplier ).getNullDate(); + rParam.mpSeriesPlotterContainer->initAxisUsageList(aNullDate); + rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); + rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); + rParam.mpSeriesPlotterContainer->setNumberFormatsFromAxes(); + + //create shapes + + //aspect ratio + drawing::Direction3D aPreferredAspectRatio = + rParam.mpSeriesPlotterContainer->getPreferredAspectRatio(); + + rtl::Reference xSeriesTargetInFrontOfAxis; + rtl::Reference xSeriesTargetBehindAxis; + VDiagram aVDiagram(xDiagram, aPreferredAspectRatio, nDimensionCount); + {//create diagram + aVDiagram.init(rParam.mxDiagramWithAxesShapes); + aVDiagram.createShapes( + awt::Point(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y), + awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height)); + + xSeriesTargetInFrontOfAxis = aVDiagram.getCoordinateRegion(); + // It is preferable to use full size than minimum for pie charts + if (!rParam.mbUseFixedInnerSize) + aVDiagram.reduceToMinimumSize(); + } + + rtl::Reference xTextTargetShapes = + ShapeFactory::createGroup2D(rParam.mxDiagramWithAxesShapes); + + // - create axis and grids for all coordinate systems + + //init all coordinate systems + for (auto& rpVCooSys : rVCooSysList) + { + rpVCooSys->initPlottingTargets(xSeriesTargetInFrontOfAxis, xTextTargetShapes, xSeriesTargetBehindAxis); + + rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + rpVCooSys->initVAxisInList(); + } + + //calculate resulting size respecting axis label layout and fontscaling + + rtl::Reference xBoundingShape(rParam.mxDiagramWithAxesShapes); + ::basegfx::B2IRectangle aConsumedOuterRect; + + //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 + bool bIsPieOrDonut = lcl_IsPieOrDonut(xDiagram); + if( !bIsPieOrDonut && (!rVCooSysList.empty()) ) + { + VCoordinateSystem* pVCooSys = rVCooSysList[0].get(); + pVCooSys->createMaximumAxesLabels(); + + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); + if (!rParam.mbUseFixedInnerSize) + aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); + + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aNewInnerRect ) )); + + //redo autoscaling to get size and text dependent automatic main increment count + rParam.mpSeriesPlotterContainer->doAutoScaling( mrChartModel ); + rParam.mpSeriesPlotterContainer->updateScalesAndIncrementsOnAxes(); + rParam.mpSeriesPlotterContainer->setScalesFromCooSysToPlotter(); + + pVCooSys->createAxesLabels(); + + bool bLessSpaceConsumedThanExpected = false; + { + 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 && !rParam.mbUseFixedInnerSize) + { + aVDiagram.adjustInnerSize( aConsumedOuterRect ); + pVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + // Need to re-adjust again if the labels have changed height because of + // text can break. Ideally this shouldn't be needed, but the chart height + // isn't readjusted otherwise. + pVCooSys->createAxesLabels(); + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); + aVDiagram.adjustInnerSize(aConsumedOuterRect); + pVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen(aVDiagram.getCurrentRectangle()))); + + } + pVCooSys->updatePositions();//todo: logically this belongs to the condition above, but it seems also to be necessary to give the axes group shapes the right bounding rects for hit test - probably caused by bug i106183 -> check again if fixed + } + + //create axes and grids for the final size + for (auto& rpVCooSys : rVCooSysList) + { + rpVCooSys->setTransformationSceneToScreen( B3DHomMatrixToHomogenMatrix( + createTransformationSceneToScreen( aVDiagram.getCurrentRectangle() ) )); + + rpVCooSys->createAxesShapes(); + rpVCooSys->createGridShapes(); + } + + // - create data series for all charttypes + m_bPointsWereSkipped = false; + for( const std::unique_ptr& aPlotter : rSeriesPlotterList ) + { + VSeriesPlotter* pSeriesPlotter = aPlotter.get(); + rtl::Reference xSeriesTarget; + if( pSeriesPlotter->WantToPlotInFrontOfAxisLine() ) + xSeriesTarget = xSeriesTargetInFrontOfAxis; + else + { + xSeriesTarget = xSeriesTargetBehindAxis; + OSL_ENSURE( !bIsPieOrDonut, "not implemented yet! - during a complete recreation this shape is destroyed so no series can be created anymore" ); + } + pSeriesPlotter->initPlotter( xSeriesTarget,xTextTargetShapes,OUString() ); + pSeriesPlotter->setPageReferenceSize( rPageSize ); + VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, pSeriesPlotter ); + if(nDimensionCount==2) + pSeriesPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + //better performance for big data + { + //calculate resolution for coordinate system + Sequence aCoordinateSystemResolution = pVCooSys->getCoordinateSystemResolution( rPageSize, m_aPageResolution ); + pSeriesPlotter->setCoordinateSystemResolution( aCoordinateSystemResolution ); + } + // Do not allow to move data labels in case of pie or donut chart, yet! + pSeriesPlotter->setPieLabelsAllowToMove(!bIsPieOrDonut); + // use the pagesize as remaining space if we have a fixed inner size + if( rParam.mbUseFixedInnerSize ) + aAvailableOuterRect = BaseGFXHelper::makeRectangle(awt::Rectangle(0, 0, rPageSize.Width, rPageSize.Height)); + // set the available space for data labels to avoid moving out from chart area + pSeriesPlotter->setAvailableOuterRect(aAvailableOuterRect); + pSeriesPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || pSeriesPlotter->PointsWereSkipped(); + } + + //recreate all with corrected sizes if requested + if( bIsPieOrDonut ) + { + m_bPointsWereSkipped = false; + + aConsumedOuterRect = ShapeFactory::getRectangleOfShape(*xBoundingShape); + ::basegfx::B2IRectangle aNewInnerRect( aVDiagram.getCurrentRectangle() ); + if (!rParam.mbUseFixedInnerSize) + aNewInnerRect = aVDiagram.adjustInnerSize( aConsumedOuterRect ); + + for( std::unique_ptr& aPlotter : rSeriesPlotterList ) + { + aPlotter->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 (auto& rpVCooSys : rVCooSysList) + { + auto aMatrix = createTransformationSceneToScreen(aNewInnerRect); + rpVCooSys->setTransformationSceneToScreen(B3DHomMatrixToHomogenMatrix(aMatrix)); + } + + // - create data series for all charttypes + for( std::unique_ptr& aPlotter : rSeriesPlotterList ) + { + VCoordinateSystem* pVCooSys = SeriesPlotterContainer::getCooSysForPlotter( rVCooSysList, aPlotter.get() ); + if(nDimensionCount==2) + aPlotter->setTransformationSceneToScreen( pVCooSys->getTransformationSceneToScreen() ); + // Now we can move data labels in case of pie or donut chart! + aPlotter->setPieLabelsAllowToMove(bIsPieOrDonut); + aPlotter->createShapes(); + m_bPointsWereSkipped = m_bPointsWereSkipped || aPlotter->PointsWereSkipped(); + } + + for( std::unique_ptr& aPlotter : rSeriesPlotterList ) + aPlotter->rearrangeLabelToAvoidOverlapIfRequested(rPageSize); + } + + if (rParam.mbUseFixedInnerSize) + { + aUsedOuterRect = awt::Rectangle( aConsumedOuterRect.getMinX(), aConsumedOuterRect.getMinY(), aConsumedOuterRect.getWidth(), aConsumedOuterRect.getHeight() ); + } + else + aUsedOuterRect = rParam.maRemainingSpace; + + bool bSnapRectToUsedArea = false; + for( std::unique_ptr& aPlotter : rSeriesPlotterList ) + { + bSnapRectToUsedArea = aPlotter->shouldSnapRectToUsedArea(); + if(bSnapRectToUsedArea) + break; + } + if(bSnapRectToUsedArea) + { + if (rParam.mbUseFixedInnerSize) + m_aResultingDiagramRectangleExcludingAxes = getRectangleOfObject( "PlotAreaExcludingAxes" ); + else + { + ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); + m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); + } + } + else + { + if (rParam.mbUseFixedInnerSize) + m_aResultingDiagramRectangleExcludingAxes = rParam.maRemainingSpace; + else + { + ::basegfx::B2IRectangle aConsumedInnerRect = aVDiagram.getCurrentRectangle(); + m_aResultingDiagramRectangleExcludingAxes = BaseGFXHelper::toAwtRectangle(aConsumedInnerRect); + } + } + + if (rParam.mxMarkHandles.is()) + { + awt::Point aPos(rParam.maRemainingSpace.X, rParam.maRemainingSpace.Y); + awt::Size aSize(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height); + + bool bPosSizeExcludeAxesProperty = true; + xDiagram->getPropertyValue("PosSizeExcludeAxes") >>= bPosSizeExcludeAxesProperty; + if (rParam.mbUseFixedInnerSize || bPosSizeExcludeAxesProperty) + { + aPos = awt::Point( m_aResultingDiagramRectangleExcludingAxes.X, m_aResultingDiagramRectangleExcludingAxes.Y ); + aSize = awt::Size( m_aResultingDiagramRectangleExcludingAxes.Width, m_aResultingDiagramRectangleExcludingAxes.Height ); + } + rParam.mxMarkHandles->setPosition(aPos); + rParam.mxMarkHandles->setSize(aSize); + } + + return aUsedOuterRect; +} + +bool ChartView::getExplicitValuesForAxis( + uno::Reference< XAxis > xAxis + , ExplicitScaleData& rExplicitScale + , ExplicitIncrementData& rExplicitIncrement ) +{ + SolarMutexGuard aSolarGuard; + + impl_updateView(); + + if(!xAxis.is()) + return false; + + rtl::Reference< BaseCoordinateSystem > xCooSys = AxisHelper::getCoordinateSystemOfAxis(xAxis, mrChartModel.getFirstChartDiagram() ); + const VCoordinateSystem* pVCooSys = SeriesPlotterContainer::findInCooSysList(m_aVCooSysList, xCooSys); + if(!pVCooSys) + return false; + + sal_Int32 nDimensionIndex=-1; + sal_Int32 nAxisIndex=-1; + if( !AxisHelper::getIndicesForAxis( xAxis, xCooSys, nDimensionIndex, nAxisIndex ) ) + return false; + + rExplicitScale = pVCooSys->getExplicitScale(nDimensionIndex,nAxisIndex); + rExplicitIncrement = pVCooSys->getExplicitIncrement(nDimensionIndex,nAxisIndex); + if( !rExplicitScale.m_bShiftedCategoryPosition ) + return true; + + //remove 'one' from max + if( rExplicitScale.AxisType == css::chart2::AxisType::DATE ) + { + Date aMaxDate(rExplicitScale.NullDate); aMaxDate.AddDays(::rtl::math::approxFloor(rExplicitScale.Maximum)); + //for explicit scales with shifted categories we need one interval more + switch( rExplicitScale.TimeResolution ) + { + case css::chart::TimeUnit::DAY: + --aMaxDate; + break; + case css::chart::TimeUnit::MONTH: + aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1); + break; + case css::chart::TimeUnit::YEAR: + aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1); + break; + } + rExplicitScale.Maximum = aMaxDate - rExplicitScale.NullDate; + } + else if( rExplicitScale.AxisType == css::chart2::AxisType::CATEGORY ) + rExplicitScale.Maximum -= 1.0; + else if( rExplicitScale.AxisType == css::chart2::AxisType::SERIES ) + rExplicitScale.Maximum -= 1.0; + return true; +} + +SdrPage* ChartView::getSdrPage() +{ + if(m_xDrawPage) + return m_xDrawPage->GetSdrPage(); + + return nullptr; +} + +rtl::Reference< SvxShape > ChartView::getShapeForCID( const OUString& rObjectCID ) +{ + SolarMutexGuard aSolarGuard; + SdrObject* pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, this->getSdrPage() ); + if( !pObj ) + return nullptr; + + uno::Reference< drawing::XShape > xShape = pObj->getUnoShape(); + rtl::Reference xShape2 = dynamic_cast(xShape.get()); + assert(xShape2 || !xShape); + return xShape2; +} + +awt::Rectangle ChartView::getDiagramRectangleExcludingAxes() +{ + impl_updateView(); + return m_aResultingDiagramRectangleExcludingAxes; +} + +awt::Rectangle ChartView::getRectangleOfObject( const OUString& rObjectCID, bool bSnapRect ) +{ + impl_updateView(); + + awt::Rectangle aRet; + rtl::Reference< SvxShape > 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 ) + { + SolarMutexGuard aSolarGuard; + SdrObject* pRootSdrObject = xShape->GetSdrObject(); + if( pRootSdrObject ) + { + SdrObjList* pRootList = pRootSdrObject->GetSubList(); + if( pRootList ) + { + OUString aShapeName = "MarkHandles"; + if( eObjectType == OBJECTTYPE_DIAGRAM ) + aShapeName = "PlotAreaIncludingAxes"; + SdrObject* pShape = DrawModelWrapper::getNamedSdrObject( aShapeName, pRootList ); + if( pShape ) + { + xShape = dynamic_cast(pShape->getUnoShape().get()); + assert(xShape); + } + } + } + } + + 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 + SdrObject* pSdrObject = xShape->GetSdrObject(); + if( pSdrObject ) + { + tools::Rectangle aSnapRect( pSdrObject->GetSnapRect() ); + aRet = awt::Rectangle(aSnapRect.Left(),aSnapRect.Top(),aSnapRect.GetWidth(),aSnapRect.GetHeight()); + } + } + } + return aRet; +} + +std::shared_ptr< DrawModelWrapper > ChartView::getDrawModelWrapper() +{ + return m_pDrawModelWrapper; +} + +namespace +{ + +constexpr double constPageLayoutDistancePercentage = 0.02; + +bool getAvailablePosAndSizeForDiagram( + CreateShapeParam2D& rParam, const awt::Size & rPageSize, const uno::Reference< beans::XPropertySet >& xProp) +{ + rParam.mbUseFixedInnerSize = false; + + //@todo: we need a size dependent on the axis labels + sal_Int32 nYDistance = static_cast(rPageSize.Height * constPageLayoutDistancePercentage); + sal_Int32 nXDistance = static_cast(rPageSize.Width * constPageLayoutDistancePercentage); + rParam.maRemainingSpace.X += nXDistance; + rParam.maRemainingSpace.Width -= 2*nXDistance; + rParam.maRemainingSpace.Y += nYDistance; + rParam.maRemainingSpace.Height -= 2*nYDistance; + + bool bPosSizeExcludeAxes = false; + if( xProp.is() ) + xProp->getPropertyValue( "PosSizeExcludeAxes" ) >>= bPosSizeExcludeAxes; + + //size: + css::chart2::RelativeSize aRelativeSize; + if( xProp.is() && (xProp->getPropertyValue( "RelativeSize" )>>=aRelativeSize) ) + { + rParam.maRemainingSpace.Height = static_cast(aRelativeSize.Secondary*rPageSize.Height); + rParam.maRemainingSpace.Width = static_cast(aRelativeSize.Primary*rPageSize.Width); + rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; + } + + if (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0) + return false; + + //position: + chart2::RelativePosition aRelativePosition; + if( xProp.is() && (xProp->getPropertyValue( "RelativePosition" )>>=aRelativePosition) ) + { + //@todo decide whether x is primary or secondary + + //the coordinates re relative to the page + double fX = aRelativePosition.Primary*rPageSize.Width; + double fY = aRelativePosition.Secondary*rPageSize.Height; + + awt::Point aPos = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + awt::Point(static_cast(fX),static_cast(fY)), + awt::Size(rParam.maRemainingSpace.Width, rParam.maRemainingSpace.Height), + aRelativePosition.Anchor); + + rParam.maRemainingSpace.X = aPos.X; + rParam.maRemainingSpace.Y = aPos.Y; + + rParam.mbUseFixedInnerSize = bPosSizeExcludeAxes; + } + + //ensure that the diagram does not lap out right side or out of bottom + if (rParam.maRemainingSpace.Y + rParam.maRemainingSpace.Height > rPageSize.Height) + rParam.maRemainingSpace.Height = rPageSize.Height - rParam.maRemainingSpace.Y; + + if (rParam.maRemainingSpace.X + rParam.maRemainingSpace.Width > rPageSize.Width) + rParam.maRemainingSpace.Width = rPageSize.Width - rParam.maRemainingSpace.X; + + return true; +} + +enum class TitleAlignment { ALIGN_LEFT, ALIGN_TOP, ALIGN_RIGHT, ALIGN_BOTTOM, ALIGN_Z }; + +void changePositionOfAxisTitle( VTitle* pVTitle, TitleAlignment eAlignment + , awt::Rectangle const & rDiagramPlusAxesRect, const awt::Size & rPageSize ) +{ + if(!pVTitle) + return; + + awt::Point aNewPosition(0,0); + awt::Size aTitleSize = pVTitle->getFinalSize(); + sal_Int32 nYDistance = static_cast(rPageSize.Height * constPageLayoutDistancePercentage); + sal_Int32 nXDistance = static_cast(rPageSize.Width * constPageLayoutDistancePercentage); + switch (eAlignment) + { + case TitleAlignment::ALIGN_TOP: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y - aTitleSize.Height/2 - nYDistance ); + break; + case TitleAlignment::ALIGN_BOTTOM: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width/2 + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height + aTitleSize.Height/2 + nYDistance ); + break; + case TitleAlignment::ALIGN_LEFT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X - aTitleSize.Width/2 - nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case TitleAlignment::ALIGN_RIGHT: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height/2 ); + break; + case TitleAlignment::ALIGN_Z: + aNewPosition = awt::Point( rDiagramPlusAxesRect.X + rDiagramPlusAxesRect.Width + aTitleSize.Width/2 + nXDistance + , rDiagramPlusAxesRect.Y + rDiagramPlusAxesRect.Height - aTitleSize.Height/2 ); + break; + } + + sal_Int32 nMaxY = rPageSize.Height - aTitleSize.Height/2; + sal_Int32 nMaxX = rPageSize.Width - aTitleSize.Width/2; + sal_Int32 nMinX = aTitleSize.Width/2; + sal_Int32 nMinY = aTitleSize.Height/2; + if( aNewPosition.Y > nMaxY ) + aNewPosition.Y = nMaxY; + if( aNewPosition.X > nMaxX ) + aNewPosition.X = nMaxX; + if( aNewPosition.Y < nMinY ) + aNewPosition.Y = nMinY; + if( aNewPosition.X < nMinX ) + aNewPosition.X = nMinX; + + pVTitle->changePosition( aNewPosition ); +} + +std::shared_ptr lcl_createTitle( TitleHelper::eTitleType eType + , const rtl::Reference& xPageShapes + , ChartModel& rModel + , awt::Rectangle& rRemainingSpace + , const awt::Size & rPageSize + , TitleAlignment eAlignment + , bool& rbAutoPosition ) +{ + std::shared_ptr apVTitle; + + // #i109336# Improve auto positioning in chart + double fPercentage = constPageLayoutDistancePercentage; + 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 ) + { + nYDistance += 135; // 1/100 mm + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION ) + { + nYDistance = 420; // 1/100 mm + } + else if ( eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION ) + { + nXDistance = 450; // 1/100 mm + } + + uno::Reference< XTitle > xTitle( TitleHelper::getTitle( eType, rModel ) ); + OUString aCompleteString = TitleHelper::getCompleteString(xTitle); + if (aCompleteString.isEmpty() || !VTitle::isVisible(xTitle)) + return apVTitle; + + //create title + awt::Size aTextMaxWidth(rPageSize.Width, rPageSize.Height); + bool bYAxisTitle = false; + if (eType == TitleHelper::MAIN_TITLE || eType == TitleHelper::SUB_TITLE) + { + aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.8); + aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.5); + } + else if (eType == TitleHelper::X_AXIS_TITLE || eType == TitleHelper::SECONDARY_X_AXIS_TITLE + || eType == TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION) + { + aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.8); + aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.2); + } + else if (eType == TitleHelper::Y_AXIS_TITLE || eType == TitleHelper::SECONDARY_Y_AXIS_TITLE + || eType == TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION) + { + aTextMaxWidth.Width = static_cast(rPageSize.Width * 0.2); + aTextMaxWidth.Height = static_cast(rPageSize.Height * 0.8); + bYAxisTitle = true; + } + apVTitle = std::make_shared(xTitle); + OUString aCID = ObjectIdentifier::createClassifiedIdentifierForObject(xTitle, &rModel); + apVTitle->init(xPageShapes, aCID); + apVTitle->createShapes(awt::Point(0, 0), rPageSize, aTextMaxWidth, bYAxisTitle); + awt::Size aTitleUnrotatedSize = apVTitle->getUnrotatedSize(); + awt::Size aTitleSize = apVTitle->getFinalSize(); + + //position + rbAutoPosition = true; + awt::Point aNewPosition(0,0); + chart2::RelativePosition aRelativePosition; + uno::Reference xProp(xTitle, uno::UNO_QUERY); + if (xProp.is() && (xProp->getPropertyValue("RelativePosition") >>= aRelativePosition)) + { + rbAutoPosition = false; + + //@todo decide whether 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(fX),static_cast(fY)) + , aTitleUnrotatedSize, aRelativePosition.Anchor, fAnglePi ); + } + else //auto position + { + switch( eAlignment ) + { + case TitleAlignment::ALIGN_TOP: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + aTitleSize.Height/2 + nYDistance ); + break; + case TitleAlignment::ALIGN_BOTTOM: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width/2 + , rRemainingSpace.Y + rRemainingSpace.Height - aTitleSize.Height/2 - nYDistance ); + break; + case TitleAlignment::ALIGN_LEFT: + aNewPosition = awt::Point( rRemainingSpace.X + aTitleSize.Width/2 + nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + case TitleAlignment::ALIGN_RIGHT: + aNewPosition = awt::Point( rRemainingSpace.X + rRemainingSpace.Width - aTitleSize.Width/2 - nXDistance + , rRemainingSpace.Y + rRemainingSpace.Height/2 ); + break; + case TitleAlignment::ALIGN_Z: + break; + + } + } + apVTitle->changePosition( aNewPosition ); + + //remaining space + switch( eAlignment ) + { + case TitleAlignment::ALIGN_TOP: + // Push the remaining space down from top. + rRemainingSpace.Y += ( aTitleSize.Height + nYDistance ); + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case TitleAlignment::ALIGN_BOTTOM: + // Push the remaining space up from bottom. + rRemainingSpace.Height -= ( aTitleSize.Height + nYDistance ); + break; + case TitleAlignment::ALIGN_LEFT: + // Push the remaining space to the right from left edge. + rRemainingSpace.X += ( aTitleSize.Width + nXDistance ); + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + case TitleAlignment::ALIGN_RIGHT: + // Push the remaining space to the left from right edge. + rRemainingSpace.Width -= ( aTitleSize.Width + nXDistance ); + break; + case TitleAlignment::ALIGN_Z: + break; + } + + return apVTitle; +} + +bool lcl_createLegend( const rtl::Reference< Legend > & xLegend + , const rtl::Reference& xPageShapes + , const uno::Reference< uno::XComponentContext > & xContext + , awt::Rectangle & rRemainingSpace + , const awt::Size & rPageSize + , ChartModel& rModel + , std::vector< LegendEntryProvider* >&& rLegendEntryProviderList + , sal_Int16 nDefaultWritingMode ) +{ + if (!VLegend::isVisible(xLegend)) + return false; + + awt::Size rDefaultLegendSize; + VLegend aVLegend( xLegend, xContext, std::move(rLegendEntryProviderList), + xPageShapes, rModel); + aVLegend.setDefaultWritingMode( nDefaultWritingMode ); + aVLegend.createShapes( awt::Size( rRemainingSpace.Width, rRemainingSpace.Height ), + rPageSize, rDefaultLegendSize ); + aVLegend.changePosition( rRemainingSpace, rPageSize, rDefaultLegendSize ); + return true; +} + +void lcl_createButtons(const rtl::Reference& xPageShapes, + ChartModel& rModel, + awt::Rectangle& rRemainingSpace) +{ + uno::Reference xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY); + if (!xPivotTableDataProvider.is()) + return; + + uno::Reference xModelPage(rModel.getPageBackground()); + + awt::Size aSize(4000, 700); // size of the button + + tools::Long x = 0; + + if (xPivotTableDataProvider->getPageFields().hasElements()) + { + x = 0; + + const css::uno::Sequence aPivotFieldEntries = xPivotTableDataProvider->getPageFields(); + for (css::chart2::data::PivotTableFieldEntry const & rPageFieldEntry : aPivotFieldEntries) + { + VButton aButton; + aButton.init(xPageShapes); + awt::Point aNewPosition(rRemainingSpace.X + x + 100, rRemainingSpace.Y + 100); + sal_Int32 nDimensionIndex = rPageFieldEntry.DimensionIndex; + OUString aFieldOutputDescription = xPivotTableDataProvider->getFieldOutputDescription(nDimensionIndex); + aButton.setLabel(rPageFieldEntry.Name + " | " + aFieldOutputDescription); + aButton.setCID("FieldButton.Page." + OUString::number(nDimensionIndex)); + aButton.setPosition(aNewPosition); + aButton.setSize(aSize); + if (rPageFieldEntry.HasHiddenMembers) + aButton.setArrowColor(Color(0x0000FF)); + + aButton.createShapes(xModelPage); + x += aSize.Width + 100; + } + rRemainingSpace.Y += (aSize.Height + 100 + 100); + rRemainingSpace.Height -= (aSize.Height + 100 + 100); + } + + aSize = awt::Size(3000, 700); // size of the button + + if (!xPivotTableDataProvider->getRowFields().hasElements()) + return; + + x = 200; + const css::uno::Sequence aPivotFieldEntries = xPivotTableDataProvider->getRowFields(); + for (css::chart2::data::PivotTableFieldEntry const & rRowFieldEntry : aPivotFieldEntries) + { + VButton aButton; + aButton.init(xPageShapes); + awt::Point aNewPosition(rRemainingSpace.X + x + 100, + rRemainingSpace.Y + rRemainingSpace.Height - aSize.Height - 100); + aButton.setLabel(rRowFieldEntry.Name); + aButton.setCID("FieldButton.Row." + OUString::number(rRowFieldEntry.DimensionIndex)); + aButton.setPosition(aNewPosition); + aButton.setSize(aSize); + if ( rRowFieldEntry.Name == "Data" ) + { + aButton.setBGColor( Color(0x00F6F6F6) ); + aButton.showArrow( false ); + } + else if (rRowFieldEntry.HasHiddenMembers) + aButton.setArrowColor(Color(0x0000FF)); + aButton.createShapes(xModelPage); + x += aSize.Width + 100; + } + rRemainingSpace.Height -= (aSize.Height + 100 + 100); +} + +void formatPage( + ChartModel& rChartModel + , const awt::Size& rPageSize + , const rtl::Reference& xTarget + ) +{ + try + { + uno::Reference< beans::XPropertySet > xModelPage( rChartModel.getPageBackground()); + if( ! xModelPage.is()) + return; + + //format page + tPropertyNameValueMap aNameValueMap; + PropertyMapper::getValueMap( aNameValueMap, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xModelPage ); + + OUString aCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) ); + aNameValueMap.emplace( "Name", uno::Any( aCID ) ); //CID OUString + + tNameSequence aNames; + tAnySequence aValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aNames, aValues, aNameValueMap ); + + ShapeFactory::createRectangle( + xTarget, rPageSize, awt::Point(0, 0), aNames, aValues); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +void lcl_removeEmptyGroupShapes( const SdrObject& rParent ) +{ + SdrObjList* pObjList = rParent.getChildrenOfSdrObject(); + if (!pObjList || pObjList->GetObjCount() == 0) + return; + + //iterate from back! + for(auto nIdx = static_cast(pObjList->GetObjCount() - 1); nIdx >= 0; --nIdx) + { + SdrObject* pChildSdrObject = pObjList->GetObj(nIdx); + SdrObjList* pChildObjList = pChildSdrObject->getChildrenOfSdrObject(); + if (!pChildObjList) + continue; + if (pChildObjList->GetObjCount() == 0) + { + //remove empty group shape + SdrObject* pRemoved = pObjList->NbcRemoveObject(nIdx); + SdrObject::Free( pRemoved ); + } + else + lcl_removeEmptyGroupShapes(*pChildSdrObject); + } +} + +} + +void ChartView::impl_refreshAddIn() +{ + if( !m_bRefreshAddIn ) + return; + + uno::Reference< beans::XPropertySet > xProp( static_cast< ::cppu::OWeakObject* >( &mrChartModel ), uno::UNO_QUERY ); + if( !xProp.is()) + return; + + try + { + uno::Reference< util::XRefreshable > xAddIn; + xProp->getPropertyValue( "AddIn" ) >>= xAddIn; + if( xAddIn.is() ) + { + bool bRefreshAddInAllowed = true; + xProp->getPropertyValue( "RefreshAddInAllowed" ) >>= bRefreshAddInAllowed; + if( bRefreshAddInAllowed ) + xAddIn->refresh(); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void ChartView::createShapes() +{ + SolarMutexGuard aSolarGuard; + + osl::MutexGuard aTimedGuard(maTimeMutex); + if(mrChartModel.isTimeBased()) + { + maTimeBased.bTimeBased = true; + } + + //make sure add-in is refreshed after creating the shapes + const ::comphelper::ScopeGuard aGuard( [this]() { this->impl_refreshAddIn(); } ); + + m_aResultingDiagramRectangleExcludingAxes = awt::Rectangle(0,0,0,0); + impl_deleteCoordinateSystems(); + if( m_pDrawModelWrapper ) + { + // #i12587# support for shapes in chart + m_pDrawModelWrapper->getSdrModel().EnableUndo( false ); + m_pDrawModelWrapper->clearMainDrawPage(); + } + + lcl_setDefaultWritingMode( m_pDrawModelWrapper, mrChartModel ); + + awt::Size aPageSize = mrChartModel.getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + + if(!mxRootShape.is()) + mxRootShape = ShapeFactory::getOrCreateChartRootShape( m_xDrawPage ); + + SdrPage* pPage = ChartView::getSdrPage(); + if(pPage) //it is necessary to use the implementation here as the uno page does not provide a propertyset + pPage->SetSize(Size(aPageSize.Width,aPageSize.Height)); + else + { + OSL_FAIL("could not set page size correctly"); + } + ShapeFactory::setPageSize(mxRootShape, aPageSize); + + createShapes2D(aPageSize); + + // #i12587# support for shapes in chart + if ( m_pDrawModelWrapper ) + { + m_pDrawModelWrapper->getSdrModel().EnableUndo( true ); + } + + if(maTimeBased.bTimeBased) + { + maTimeBased.nFrame++; + } +} + +// util::XEventListener (base of XCloseListener) +void SAL_CALL ChartView::disposing( const lang::EventObject& /* rSource */ ) +{ +} + +void ChartView::impl_updateView( bool bCheckLockedCtrler ) +{ + if( !m_pDrawModelWrapper ) + return; + + // #i12587# support for shapes in chart + if ( m_bSdrViewIsInEditMode ) + { + return; + } + + if (bCheckLockedCtrler && mrChartModel.hasControllersLocked()) + return; + + if( !m_bViewDirty || m_bInViewUpdate ) + return; + + m_bInViewUpdate = true; + //bool bOldRefreshAddIn = m_bRefreshAddIn; + //m_bRefreshAddIn = false; + try + { + impl_notifyModeChangeListener("invalid"); + + //prepare draw model + { + SolarMutexGuard aSolarGuard; + m_pDrawModelWrapper->lockControllers(); + } + + //create chart view + { + 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( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + m_bViewDirty = m_bViewUpdatePending; + m_bViewUpdatePending = false; + m_bInViewUpdate = false; + } + + { + SolarMutexGuard aSolarGuard; + m_pDrawModelWrapper->unlockControllers(); + } + + impl_notifyModeChangeListener("valid"); + + //m_bRefreshAddIn = bOldRefreshAddIn; +} + +// ____ XModifyListener ____ +void SAL_CALL ChartView::modified( const lang::EventObject& /* aEvent */ ) +{ + m_bViewDirty = true; + if( m_bInViewUpdate ) + m_bViewUpdatePending = true; + + impl_notifyModeChangeListener("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 ) + { + uno::Reference< view::XSelectionSupplier > xSelectionSupplier( mrChartModel.getCurrentController(), uno::UNO_QUERY ); + if ( xSelectionSupplier.is() ) + { + OUString aSelObjCID; + uno::Any aSelObj( xSelectionSupplier->getSelection() ); + aSelObj >>= aSelObjCID; + if ( !aSelObjCID.isEmpty() ) + { + return; + } + } + } + + if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint) + return; + const SdrHint* pSdrHint = static_cast< const SdrHint* >(&rHint); + + bool bShapeChanged = false; + switch( pSdrHint->GetKind() ) + { + case SdrHintKind::ObjectChange: + bShapeChanged = true; + break; + case SdrHintKind::ObjectInserted: + bShapeChanged = true; + break; + case SdrHintKind::ObjectRemoved: + bShapeChanged = true; + break; + case SdrHintKind::ModelCleared: + bShapeChanged = true; + break; + case SdrHintKind::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; + + mrChartModel.setModified(true); +} + +void ChartView::impl_notifyModeChangeListener( const OUString& rNewMode ) +{ + try + { + comphelper::OInterfaceContainerHelper2* pIC = m_aListenerContainer + .getContainer( cppu::UnoType::get()); + if( pIC ) + { + util::ModeChangeEvent aEvent( static_cast< uno::XWeak* >( this ), rNewMode ); + comphelper::OInterfaceIteratorHelper2 aIt( *pIC ); + while( aIt.hasMoreElements() ) + { + static_cast< util::XModeChangeListener* >( aIt.next() )->modeChanged( aEvent ); + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } +} + +// ____ XModeChangeBroadcaster ____ + +void SAL_CALL ChartView::addModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) +{ + m_aListenerContainer.addInterface( + cppu::UnoType::get(), xListener ); +} +void SAL_CALL ChartView::removeModeChangeListener( const uno::Reference< util::XModeChangeListener >& xListener ) +{ + m_aListenerContainer.removeInterface( + cppu::UnoType::get(), xListener ); +} +void SAL_CALL ChartView::addModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) +{ + +} +void SAL_CALL ChartView::removeModeChangeApproveListener( const uno::Reference< util::XModeChangeApproveListener >& /* _rxListener */ ) +{ + +} + +// ____ XUpdatable ____ +void SAL_CALL ChartView::update() +{ + impl_updateView(); + + //#i100778# migrate all imported or old documents to a plot area sizing exclusive axes (in case the save settings allow for this): + //Although in general it is a bad idea to change the model from within the view this is exceptionally the best place to do this special conversion. + //When a view update is requested (what happens for creating the metafile or displaying + //the chart in edit mode or printing) it is most likely that all necessary information is available - like the underlying spreadsheet data for example. + //Those data are important for the correct axis label sizes which are needed during conversion. + if( DiagramHelper::switchDiagramPositioningToExcludingPositioning( mrChartModel, true, false ) ) + impl_updateView(); +} + +void SAL_CALL ChartView::updateSoft() +{ + update(); +} + +void SAL_CALL ChartView::updateHard() +{ + impl_updateView(false); +} + +// ____ XPropertySet ____ +Reference< beans::XPropertySetInfo > SAL_CALL ChartView::getPropertySetInfo() +{ + OSL_FAIL("not implemented"); + return nullptr; +} + +void SAL_CALL ChartView::setPropertyValue( const OUString& rPropertyName + , const Any& rValue ) +{ + if( rPropertyName == "Resolution" ) + { + awt::Size aNewResolution; + if( ! (rValue >>= aNewResolution) ) + throw lang::IllegalArgumentException( "Property 'Resolution' requires value of type awt::Size", nullptr, 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.Widthmodified( lang::EventObject( static_cast< uno::XWeak* >( this ) ) ); + } + } + else if( rPropertyName == "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( "Property 'ZoomFactors' requires value of type Sequence< PropertyValue >", nullptr, 0 ); + + sal_Int32 nFilterArgs = aZoomFactors.getLength(); + const beans::PropertyValue* pDataValues = aZoomFactors.getConstArray(); + while( nFilterArgs-- ) + { + if ( pDataValues->Name == "ScaleXNumerator" ) + pDataValues->Value >>= m_nScaleXNumerator; + else if ( pDataValues->Name == "ScaleXDenominator" ) + pDataValues->Value >>= m_nScaleXDenominator; + else if ( pDataValues->Name == "ScaleYNumerator" ) + pDataValues->Value >>= m_nScaleYNumerator; + else if ( pDataValues->Name == "ScaleYDenominator" ) + pDataValues->Value >>= m_nScaleYDenominator; + + pDataValues++; + } + } + else if( rPropertyName == "SdrViewIsInEditMode" ) + { + //#i77362 change notification for changes on additional shapes are missing + if( ! (rValue >>= m_bSdrViewIsInEditMode) ) + throw lang::IllegalArgumentException( "Property 'SdrViewIsInEditMode' requires value of type sal_Bool", nullptr, 0 ); + } + else + throw beans::UnknownPropertyException( "unknown property was tried to set to chart wizard " + rPropertyName, nullptr ); +} + +Any SAL_CALL ChartView::getPropertyValue( const OUString& rPropertyName ) +{ + if( rPropertyName != "Resolution" ) + throw beans::UnknownPropertyException( "unknown property was tried to get from chart wizard " + rPropertyName, nullptr ); + + return Any(m_aPageResolution); +} + +void SAL_CALL ChartView::addPropertyChangeListener( + const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* xListener */ ) +{ + OSL_FAIL("not implemented"); +} +void SAL_CALL ChartView::removePropertyChangeListener( + const OUString& /* aPropertyName */, const Reference< beans::XPropertyChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL ChartView::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +void SAL_CALL ChartView::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< beans::XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL("not implemented"); +} + +// ____ XMultiServiceFactory ____ + +Reference< uno::XInterface > ChartView::createInstance( const OUString& aServiceSpecifier ) +{ + SolarMutexGuard aSolarGuard; + + SdrModel* pModel = ( m_pDrawModelWrapper ? &m_pDrawModelWrapper->getSdrModel() : nullptr ); + if ( pModel ) + { + if ( aServiceSpecifier == "com.sun.star.drawing.DashTable" ) + { + if ( !m_xDashTable.is() ) + { + m_xDashTable = SvxUnoDashTable_createInstance( pModel ); + } + return m_xDashTable; + } + else if ( aServiceSpecifier == "com.sun.star.drawing.GradientTable" ) + { + if ( !m_xGradientTable.is() ) + { + m_xGradientTable = SvxUnoGradientTable_createInstance( pModel ); + } + return m_xGradientTable; + } + else if ( aServiceSpecifier == "com.sun.star.drawing.HatchTable" ) + { + if ( !m_xHatchTable.is() ) + { + m_xHatchTable = SvxUnoHatchTable_createInstance( pModel ); + } + return m_xHatchTable; + } + else if ( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" ) + { + if ( !m_xBitmapTable.is() ) + { + m_xBitmapTable = SvxUnoBitmapTable_createInstance( pModel ); + } + return m_xBitmapTable; + } + else if ( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" ) + { + if ( !m_xTransGradientTable.is() ) + { + m_xTransGradientTable = SvxUnoTransGradientTable_createInstance( pModel ); + } + return m_xTransGradientTable; + } + else if ( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" ) + { + if ( !m_xMarkerTable.is() ) + { + m_xMarkerTable = SvxUnoMarkerTable_createInstance( pModel ); + } + return m_xMarkerTable; + } + } + + return nullptr; +} + +Reference< uno::XInterface > ChartView::createInstanceWithArguments( const OUString& ServiceSpecifier, const uno::Sequence< uno::Any >& Arguments ) +{ + OSL_ENSURE( Arguments.hasElements(), "ChartView::createInstanceWithArguments: arguments are ignored" ); + return createInstance( ServiceSpecifier ); +} + +uno::Sequence< OUString > ChartView::getAvailableServiceNames() +{ + uno::Sequence< OUString > aServiceNames{ "com.sun.star.drawing.DashTable", + "com.sun.star.drawing.GradientTable", + "com.sun.star.drawing.HatchTable", + "com.sun.star.drawing.BitmapTable", + "com.sun.star.drawing.TransparencyGradientTable", + "com.sun.star.drawing.MarkerTable" }; + + return aServiceNames; +} + +OUString ChartView::dump() +{ +#if HAVE_FEATURE_DESKTOP + // Used for unit tests and in chartcontroller only, no need to drag in this when cross-compiling + // for non-desktop + impl_updateView(); + sal_Int32 n = m_xDrawPage->getCount(); + OUStringBuffer aBuffer; + for(sal_Int32 i = 0; i < n; ++i) + { + uno::Reference< drawing::XShapes > xShape(m_xDrawPage->getByIndex(i), uno::UNO_QUERY); + if(xShape.is()) + { + OUString aString = XShapeDumper::dump(uno::Reference(mxRootShape)); + aBuffer.append(aString); + } + else + { + uno::Reference< drawing::XShape > xSingleShape(m_xDrawPage->getByIndex(i), uno::UNO_QUERY); + if(!xSingleShape.is()) + continue; + OUString aString = XShapeDumper::dump(xSingleShape); + aBuffer.append(aString); + } + aBuffer.append("\n\n"); + } + + return aBuffer.makeStringAndClear(); +#else + return OUString(); +#endif +} + +void ChartView::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ChartView")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + if (m_pDrawModelWrapper) + { + m_pDrawModelWrapper->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + +void ChartView::setViewDirty() +{ + osl::MutexGuard aGuard(maTimeMutex); + m_bViewDirty = true; +} + +IMPL_LINK_NOARG(ChartView, UpdateTimeBased, Timer *, void) +{ + setViewDirty(); + update(); +} + +void ChartView::createShapes2D( const awt::Size& rPageSize ) +{ + // todo: it would be nicer to just pass the page m_xDrawPage and format it, + // but the draw page does not support XPropertySet + formatPage( mrChartModel, rPageSize, mxRootShape ); + + CreateShapeParam2D aParam; + aParam.maRemainingSpace.X = 0; + aParam.maRemainingSpace.Y = 0; + aParam.maRemainingSpace.Width = rPageSize.Width; + aParam.maRemainingSpace.Height = rPageSize.Height; + + //create the group shape for diagram and axes first to have title and legends on top of it + rtl::Reference< Diagram > xDiagram( mrChartModel.getFirstChartDiagram() ); + bool bHasRelativeSize = false; + if( xDiagram.is() && xDiagram->getPropertyValue("RelativeSize").hasValue() ) + bHasRelativeSize = true; + + OUString aDiagramCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) ) );//todo: other index if more than one diagram is possible + rtl::Reference xDiagramPlusAxesPlusMarkHandlesGroup_Shapes = + ShapeFactory::createGroup2D(mxRootShape,aDiagramCID); + + aParam.mxMarkHandles = ShapeFactory::createInvisibleRectangle( + xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0,0)); + ShapeFactory::setShapeName(aParam.mxMarkHandles, "MarkHandles"); + + aParam.mxPlotAreaWithAxes = ShapeFactory::createInvisibleRectangle( + xDiagramPlusAxesPlusMarkHandlesGroup_Shapes, awt::Size(0, 0)); + ShapeFactory::setShapeName(aParam.mxPlotAreaWithAxes, "PlotAreaIncludingAxes"); + + aParam.mxDiagramWithAxesShapes = ShapeFactory::createGroup2D(xDiagramPlusAxesPlusMarkHandlesGroup_Shapes); + + bool bAutoPositionDummy = true; + + // create buttons + lcl_createButtons(mxRootShape, mrChartModel, aParam.maRemainingSpace); + + lcl_createTitle( + TitleHelper::MAIN_TITLE, mxRootShape, mrChartModel, + aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy); + if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) + return; + + lcl_createTitle( + TitleHelper::SUB_TITLE, mxRootShape, mrChartModel, + aParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_TOP, bAutoPositionDummy ); + if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) + return; + + aParam.mpSeriesPlotterContainer = std::make_shared(m_aVCooSysList); + aParam.mpSeriesPlotterContainer->initializeCooSysAndSeriesPlotter( mrChartModel ); + if(maTimeBased.bTimeBased && maTimeBased.nFrame != 0) + { + auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + size_t n = rSeriesPlotter.size(); + for(size_t i = 0; i < n; ++i) + { + std::vector aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); + std::vector< VDataSeries* >& rAllOldDataSeries = + maTimeBased.m_aDataSeriesList[i]; + size_t m = std::min(aAllNewDataSeries.size(), rAllOldDataSeries.size()); + for(size_t j = 0; j < m; ++j) + { + aAllNewDataSeries[j]->setOldTimeBased( + rAllOldDataSeries[j], (maTimeBased.nFrame % 60)/60.0); + } + } + } + + lcl_createLegend( + LegendHelper::getLegend( mrChartModel ), mxRootShape, m_xCC, + aParam.maRemainingSpace, rPageSize, mrChartModel, aParam.mpSeriesPlotterContainer->getLegendEntryProviderList(), + lcl_getDefaultWritingModeFromPool( m_pDrawModelWrapper ) ); + + if (!bHasRelativeSize && (aParam.maRemainingSpace.Width <= 0 || aParam.maRemainingSpace.Height <= 0)) + return; + + if (!createAxisTitleShapes2D(aParam, rPageSize, bHasRelativeSize)) + return; + + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical(xDiagram, bDummy, bDummy); + + if (getAvailablePosAndSizeForDiagram(aParam, rPageSize, xDiagram)) + { + awt::Rectangle aUsedOuterRect = impl_createDiagramAndContent(aParam, rPageSize); + + if (aParam.mxPlotAreaWithAxes.is()) + { + aParam.mxPlotAreaWithAxes->setPosition(awt::Point(aUsedOuterRect.X, aUsedOuterRect.Y)); + aParam.mxPlotAreaWithAxes->setSize(awt::Size(aUsedOuterRect.Width, aUsedOuterRect.Height)); + } + + //correct axis title position + awt::Rectangle aDiagramPlusAxesRect( aUsedOuterRect ); + if (aParam.mbAutoPosTitleX) + changePositionOfAxisTitle(aParam.mpVTitleX.get(), TitleAlignment::ALIGN_BOTTOM, aDiagramPlusAxesRect, rPageSize); + if (aParam.mbAutoPosTitleY) + changePositionOfAxisTitle(aParam.mpVTitleY.get(), TitleAlignment::ALIGN_LEFT, aDiagramPlusAxesRect, rPageSize); + if (aParam.mbAutoPosTitleZ) + changePositionOfAxisTitle(aParam.mpVTitleZ.get(), TitleAlignment::ALIGN_Z, aDiagramPlusAxesRect, rPageSize); + if (aParam.mbAutoPosSecondTitleX) + changePositionOfAxisTitle(aParam.mpVTitleSecondX.get(), bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, aDiagramPlusAxesRect, rPageSize); + if (aParam.mbAutoPosSecondTitleY) + changePositionOfAxisTitle(aParam.mpVTitleSecondY.get(), bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, aDiagramPlusAxesRect, rPageSize); + } + + //cleanup: remove all empty group shapes to avoid grey border lines: + lcl_removeEmptyGroupShapes( *mxRootShape->GetSdrObject() ); + + if(maTimeBased.bTimeBased && maTimeBased.nFrame % 60 == 0) + { + // create copy of the data for next frame + auto& rSeriesPlotter = aParam.mpSeriesPlotterContainer->getSeriesPlotterList(); + size_t n = rSeriesPlotter.size(); + maTimeBased.m_aDataSeriesList.clear(); + maTimeBased.m_aDataSeriesList.resize(n); + for(size_t i = 0; i < n; ++i) + { + std::vector aAllNewDataSeries = rSeriesPlotter[i]->getAllSeries(); + std::vector& rAllOldDataSeries = maTimeBased.m_aDataSeriesList[i]; + size_t m = aAllNewDataSeries.size(); + for(size_t j = 0; j < m; ++j) + { + rAllOldDataSeries.push_back( aAllNewDataSeries[j]-> + createCopyForTimeBased() ); + } + } + + maTimeBased.maTimer.Stop(); + } + + if(maTimeBased.bTimeBased && !maTimeBased.maTimer.IsActive()) + { + maTimeBased.maTimer.SetTimeout(15); + maTimeBased.maTimer.SetInvokeHandler(LINK(this, ChartView, UpdateTimeBased)); + maTimeBased.maTimer.Start(); + } +} + +bool ChartView::createAxisTitleShapes2D( CreateShapeParam2D& rParam, const css::awt::Size& rPageSize, bool bHasRelativeSize ) +{ + rtl::Reference xDiagram = mrChartModel.getFirstChartDiagram(); + + rtl::Reference< ChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); + sal_Int32 nDimension = DiagramHelper::getDimension( xDiagram ); + + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 0 ) ) + rParam.mpVTitleX = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, mxRootShape, mrChartModel + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_BOTTOM, rParam.mbAutoPosTitleX ); + if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) + return false; + + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 1 ) ) + rParam.mpVTitleY = lcl_createTitle( TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, mxRootShape, mrChartModel + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_LEFT, rParam.mbAutoPosTitleY ); + if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) + return false; + + if( ChartTypeHelper::isSupportingMainAxis( xChartType, nDimension, 2 ) ) + rParam.mpVTitleZ = lcl_createTitle( TitleHelper::Z_AXIS_TITLE, mxRootShape, mrChartModel + , rParam.maRemainingSpace, rPageSize, TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosTitleZ ); + if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) + return false; + + bool bDummy = false; + bool bIsVertical = DiagramHelper::getVertical( xDiagram, bDummy, bDummy ); + + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) + rParam.mpVTitleSecondX = lcl_createTitle( TitleHelper::SECONDARY_X_AXIS_TITLE, mxRootShape, mrChartModel + , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_RIGHT : TitleAlignment::ALIGN_TOP, rParam.mbAutoPosSecondTitleX ); + if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) + return false; + + if( ChartTypeHelper::isSupportingSecondaryAxis( xChartType, nDimension ) ) + rParam.mpVTitleSecondY = lcl_createTitle( TitleHelper::SECONDARY_Y_AXIS_TITLE, mxRootShape, mrChartModel + , rParam.maRemainingSpace, rPageSize, bIsVertical? TitleAlignment::ALIGN_TOP : TitleAlignment::ALIGN_RIGHT, rParam.mbAutoPosSecondTitleY ); + if (!bHasRelativeSize && (rParam.maRemainingSpace.Width <= 0 || rParam.maRemainingSpace.Height <= 0)) + return false; + + return true; +} + +} //namespace chart + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart2_ChartView_get_implementation(css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + rtl::Reference<::chart::ChartModel> pChartModel = new ::chart::ChartModel(context); + return cppu::acquire(new ::chart::ChartView(context, *pChartModel)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/Clipping.cxx b/chart2/source/view/main/Clipping.cxx new file mode 100644 index 000000000..713e88c26 --- /dev/null +++ b/chart2/source/view/main/Clipping.cxx @@ -0,0 +1,425 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +#include +#include + +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 its two endpoints rP0 and rP1 is clipped at the rectangle + rRectangle. If there is at least a part of it visible then sal_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 sal_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 whether 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; +} + +unsigned int round_up_nearest_pow2(unsigned int v) +{ + // compute the next highest power of 2 of 32-bit v + --v; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + ++v; + return v; +} + +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_FAIL( "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 > SAL_MAX_INT16 ? round_up_nearest_pow2(nNewResultPointCount) * 2 : nReservePointCount; + if( nNewResultPointCount > nReallocLength ) + { + nReallocLength = nNewResultPointCount; + OSL_FAIL("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; +} + +void lcl_addPointToPoly( std::vector>& rPoly + , const drawing::Position3D& rPos + , sal_Int32 nPolygonIndex + , std::vector< sal_Int32 >& rResultPointCount + , sal_Int32 nReservePointCount ) +{ + if(nPolygonIndex<0) + { + OSL_FAIL( "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(o3tl::make_unsigned(nPolygonIndex) >= rPoly.size() ) + { + rPoly.resize(nPolygonIndex+1); + rResultPointCount.resize(nPolygonIndex+1,0); + } + + std::vector* pOuterSequence = &rPoly[nPolygonIndex]; + + sal_Int32 nNewResultPointCount = rResultPointCount[nPolygonIndex]+1; + sal_Int32 nSeqLength = pOuterSequence->size(); + + if( nSeqLength <= nNewResultPointCount ) + { + sal_Int32 nReallocLength = nReservePointCount > SAL_MAX_INT16 ? round_up_nearest_pow2(nNewResultPointCount) * 2 : nReservePointCount; + if( nNewResultPointCount > nReallocLength ) + { + nReallocLength = nNewResultPointCount; + OSL_FAIL("this should not be the case to avoid performance problems"); + } + pOuterSequence->resize(nReallocLength); + } + + css::drawing::Position3D* pInnerSequence = pOuterSequence->data(); + + pInnerSequence[nNewResultPointCount-1] = rPos; + 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.hasElements()) + 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; nOldPolyIndex0 ) + 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); + } +} + +void Clipping::clipPolygonAtRectangle( const std::vector>& rPolygon + , const B2DRectangle& rRectangle + , std::vector>& aResult + , bool bSplitPiecesToDifferentPolygons ) +{ + aResult.clear(); + + if(rPolygon.empty()) + 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.size(); + for(sal_Int32 nOldPolyIndex=0; nOldPolyIndex(aResult.size()) + && 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--; ) + { + std::vector* pOuterSequence = &aResult[nPolygonIndex]; + + sal_Int32 nUsedPointCount = aResultPointCount[nPolygonIndex]; + pOuterSequence->resize(nUsedPointCount); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/DataPointSymbolSupplier.cxx b/chart2/source/view/main/DataPointSymbolSupplier.cxx new file mode 100644 index 000000000..ff7f8370a --- /dev/null +++ b/chart2/source/view/main/DataPointSymbolSupplier.cxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +rtl::Reference< SvxShapeGroup > DataPointSymbolSupplier::create2DSymbolList( + const rtl::Reference& xTarget + , const drawing::Direction3D& rSize ) +{ + rtl::Reference< SvxShapeGroup > xGroupShapes = ShapeFactory::createGroup2D( xTarget ); + + drawing::Position3D aPos(0,0,0); + for(sal_Int32 nS=0;nS +#include +#include "ChartItemPool.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::linguistic2 { class XHyphenator; } +namespace com::sun::star::linguistic2 { class XSpellChecker1; } + +using namespace ::com::sun::star; + + +namespace chart +{ + +DrawModelWrapper::DrawModelWrapper() +: SdrModel() +{ + m_xChartItemPool = ChartItemPool::CreateChartItemPool(); + + SetScaleUnit(MapUnit::Map100thMM); + SetScaleFraction(Fraction(1, 1)); + SetDefaultFontHeight(423); // 12pt + + SfxItemPool* pMasterPool = &GetItemPool(); + pMasterPool->SetDefaultMetric(MapUnit::Map100thMM); + pMasterPool->SetPoolDefaultItem(SfxBoolItem(EE_PARA_HYPHENATE, true) ); + pMasterPool->SetPoolDefaultItem(makeSvx3DPercentDiagonalItem (5)); + + // append chart pool to end of pool chain + pMasterPool->GetLastPoolInChain()->SetSecondaryPool(m_xChartItemPool.get()); + pMasterPool->FreezeIdRanges(); + SetTextDefaults(); + + //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; + } + + //Hyphenation 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(...) + { + OSL_FAIL("Can't get Hyphenator or SpellChecker for chart"); + } + + //ref device for font rendering + OutputDevice* pDefaultDevice = rOutliner.GetRefDevice(); + if( !pDefaultDevice ) + pDefaultDevice = Application::GetDefaultDevice(); + m_pRefDevice.disposeAndClear(); + m_pRefDevice = VclPtr::Create(*pDefaultDevice); + MapMode aMapMode = m_pRefDevice->GetMapMode(); + aMapMode.SetMapUnit(MapUnit::Map100thMM); + m_pRefDevice->SetMapMode(aMapMode); + SetRefDevice(m_pRefDevice.get()); + rOutliner.SetRefDevice(m_pRefDevice.get()); +} + +DrawModelWrapper::~DrawModelWrapper() +{ + //remove m_pChartItemPool from pool chain + if(m_xChartItemPool) + { + SfxItemPool* pPool = &GetItemPool(); + for (;;) + { + SfxItemPool* pSecondary = pPool->GetSecondaryPool(); + if(pSecondary == m_xChartItemPool.get()) + { + pPool->SetSecondaryPool (nullptr); + break; + } + pPool = pSecondary; + } + m_xChartItemPool.clear(); + } + m_pRefDevice.disposeAndClear(); +} + +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 = SdrModel::getUnoModel(); + return uno::Reference::query( xI ); +} + +SdrModel& DrawModelWrapper::getSdrModel() +{ + return *this; +} + +uno::Reference< lang::XMultiServiceFactory > DrawModelWrapper::getShapeFactory() +{ + uno::Reference< lang::XMultiServiceFactory > xShapeFactory( getUnoModel(), uno::UNO_QUERY ); + return xShapeFactory; +} + +const rtl::Reference & DrawModelWrapper::getMainDrawPage() +{ + if (m_xMainDrawPage.is()) + return m_xMainDrawPage; + + // Create draw page. + uno::Reference xDrawPagesSuplier(getUnoModel(), uno::UNO_QUERY); + if (!xDrawPagesSuplier.is()) + return m_xMainDrawPage; + + uno::Reference xDrawPages = xDrawPagesSuplier->getDrawPages(); + if (xDrawPages->getCount() > 1) + { + // Take the first page in case of multiple pages. + uno::Any aPage = xDrawPages->getByIndex(0); + uno::Reference xTmp; + aPage >>= xTmp; + m_xMainDrawPage = dynamic_cast(xTmp.get()); + assert(m_xMainDrawPage); + } + + if (!m_xMainDrawPage.is()) + { + m_xMainDrawPage = dynamic_cast(xDrawPages->insertNewByIndex(0).get()); + assert(m_xMainDrawPage); + } + + //ensure that additional shapes are in front of the chart objects so create the chart root before + // let us disable this call for now + // TODO:moggi + // ShapeFactory::getOrCreateShapeFactory(getShapeFactory())->getOrCreateChartRootShape( m_xMainDrawPage ); + return m_xMainDrawPage; +} + +const rtl::Reference & DrawModelWrapper::getHiddenDrawPage() +{ + if( !m_xHiddenDrawPage.is() ) + { + uno::Reference< drawing::XDrawPagesSupplier > xDrawPagesSuplier( getUnoModel(), uno::UNO_QUERY ); + if( xDrawPagesSuplier.is() ) + { + uno::Reference< drawing::XDrawPages > xDrawPages( xDrawPagesSuplier->getDrawPages () ); + if( xDrawPages->getCount()>1 ) + { + uno::Any aPage = xDrawPages->getByIndex( 1 ) ; + uno::Reference xTmp; + aPage >>= xTmp; + m_xHiddenDrawPage = dynamic_cast(xTmp.get()); + assert(m_xHiddenDrawPage); + } + + if(!m_xHiddenDrawPage.is()) + { + if( xDrawPages->getCount()==0 ) + { + m_xMainDrawPage = dynamic_cast(xDrawPages->insertNewByIndex( 0 ).get()); + assert(m_xMainDrawPage); + } + m_xHiddenDrawPage = dynamic_cast(xDrawPages->insertNewByIndex( 1 ).get()); + assert(m_xHiddenDrawPage); + } + } + } + return m_xHiddenDrawPage; +} +void DrawModelWrapper::clearMainDrawPage() +{ + //uno::Reference xChartRoot( m_xMainDrawPage, uno::UNO_QUERY ); + rtl::Reference 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 ); + } + } +} + +rtl::Reference DrawModelWrapper::getChartRootShape( const rtl::Reference& xDrawPage ) +{ + return ShapeFactory::getChartRootShape( xDrawPage ); +} + +void DrawModelWrapper::lockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->lockControllers(); +} +void DrawModelWrapper::unlockControllers() +{ + uno::Reference< frame::XModel > xDrawModel( getUnoModel() ); + if( xDrawModel.is()) + xDrawModel->unlockControllers(); +} + +OutputDevice* DrawModelWrapper::getReferenceDevice() const +{ + return SdrModel::GetRefDevice(); +} + +SfxItemPool& DrawModelWrapper::GetItemPool() +{ + return SdrModel::GetItemPool(); +} +XColorListRef DrawModelWrapper::GetColorList() const +{ + return SdrModel::GetColorList(); +} +XDashListRef DrawModelWrapper::GetDashList() const +{ + return SdrModel::GetDashList(); +} +XLineEndListRef DrawModelWrapper::GetLineEndList() const +{ + return SdrModel::GetLineEndList(); +} +XGradientListRef DrawModelWrapper::GetGradientList() const +{ + return SdrModel::GetGradientList(); +} +XHatchListRef DrawModelWrapper::GetHatchList() const +{ + return SdrModel::GetHatchList(); +} +XBitmapListRef DrawModelWrapper::GetBitmapList() const +{ + return SdrModel::GetBitmapList(); +} + +XPatternListRef DrawModelWrapper::GetPatternList() const +{ + return SdrModel::GetPatternList(); +} + +SdrObject* DrawModelWrapper::getNamedSdrObject( const OUString& rName ) +{ + if( rName.isEmpty() ) + return nullptr; + return getNamedSdrObject( rName, GetPage(0) ); +} + +SdrObject* DrawModelWrapper::getNamedSdrObject( const OUString& rObjectCID, SdrObjList const * pSearchList ) +{ + if(!pSearchList || rObjectCID.isEmpty()) + return nullptr; + const size_t nCount = pSearchList->GetObjCount(); + for( size_t nN=0; nNGetObj(nN); + if(!pObj) + continue; + if( ObjectIdentifier::areIdenticalObjects( rObjectCID, pObj->GetName() ) ) + return pObj; + pObj = DrawModelWrapper::getNamedSdrObject( rObjectCID, pObj->GetSubList() ); + if(pObj) + return pObj; + } + return nullptr; +} + +bool DrawModelWrapper::removeShape( const rtl::Reference& xShape ) +{ + uno::Reference xShapes( xShape->getParent(), uno::UNO_QUERY ); + if( xShapes.is() ) + { + xShapes->remove(xShape); + return true; + } + return false; +} + +void DrawModelWrapper::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("DrawModelWrapper")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + SdrModel::dumpAsXml(pWriter); + + (void)xmlTextWriterEndElement(pWriter); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ExplicitValueProvider.cxx b/chart2/source/view/main/ExplicitValueProvider.cxx new file mode 100644 index 000000000..cf5a99974 --- /dev/null +++ b/chart2/source/view/main/ExplicitValueProvider.cxx @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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; + +namespace +{ +constexpr sal_Int32 constDiagramTitleSpace = 200; //=0,2 cm spacing + +bool lcl_getPropertySwapXAndYAxis(const rtl::Reference& xDiagram) +{ + bool bSwapXAndY = false; + + if (xDiagram.is()) + { + const std::vector>& aCooSysList( + xDiagram->getBaseCoordinateSystems()); + if (!aCooSysList.empty()) + { + try + { + aCooSysList[0]->getPropertyValue("SwapXAndYAxis") >>= bSwapXAndY; + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + } + return bSwapXAndY; +} + +} // end anonymous namespace + +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForAxis( + const Reference& xAxis, + const rtl::Reference<::chart::BaseCoordinateSystem>& xCorrespondingCoordinateSystem, + const rtl::Reference<::chart::ChartModel>& xChartDoc) +{ + return AxisHelper::getExplicitNumberFormatKeyForAxis( + xAxis, xCorrespondingCoordinateSystem, xChartDoc, + true /*bSearchForParallelAxisIfNothingIsFound*/); +} + +const uno::Sequence& ExplicitValueProvider::getUnoTunnelId() +{ + static const comphelper::UnoIdInit theExplicitValueProviderUnoTunnelId; + return theExplicitValueProviderUnoTunnelId.getSeq(); +} + +sal_Int32 ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel( + const uno::Reference& xSeriesOrPointProp) +{ + sal_Int32 nFormat = 0; + if (!xSeriesOrPointProp.is()) + return nFormat; + + try + { + xSeriesOrPointProp->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nFormat; + } + catch (const beans::UnknownPropertyException&) + { + } + + if (nFormat < 0) + nFormat = 0; + return nFormat; +} + +sal_Int32 ExplicitValueProvider::getExplicitPercentageNumberFormatKeyForDataLabel( + const uno::Reference& xSeriesOrPointProp, + const uno::Reference& xNumberFormatsSupplier) +{ + sal_Int32 nFormat = 0; + if (!xSeriesOrPointProp.is()) + return nFormat; + if (!(xSeriesOrPointProp->getPropertyValue("PercentageNumberFormat") >>= nFormat)) + { + nFormat = DiagramHelper::getPercentNumberFormat(xNumberFormatsSupplier); + } + if (nFormat < 0) + nFormat = 0; + return nFormat; +} + +awt::Rectangle ExplicitValueProvider::AddSubtractAxisTitleSizes( + ChartModel& rModel, ExplicitValueProvider* pChartView, const awt::Rectangle& rPositionAndSize, + bool bSubtract) +{ + awt::Rectangle aRet(rPositionAndSize); + + //add axis title sizes to the diagram size + uno::Reference xTitle_Height( + TitleHelper::getTitle(TitleHelper::TITLE_AT_STANDARD_X_AXIS_POSITION, rModel)); + uno::Reference xTitle_Width( + TitleHelper::getTitle(TitleHelper::TITLE_AT_STANDARD_Y_AXIS_POSITION, rModel)); + uno::Reference xSecondTitle_Height( + TitleHelper::getTitle(TitleHelper::SECONDARY_X_AXIS_TITLE, rModel)); + uno::Reference xSecondTitle_Width( + TitleHelper::getTitle(TitleHelper::SECONDARY_Y_AXIS_TITLE, rModel)); + if (xTitle_Height.is() || xTitle_Width.is() || xSecondTitle_Height.is() + || xSecondTitle_Width.is()) + { + ExplicitValueProvider* pExplicitValueProvider = pChartView; + if (pExplicitValueProvider) + { + //detect whether x axis points into x direction or not + if (lcl_getPropertySwapXAndYAxis(rModel.getFirstChartDiagram())) + { + 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()) + { + OUString aCID_X( + ObjectIdentifier::createClassifiedIdentifierForObject(xTitle_Height, &rModel)); + nTitleSpaceHeight + = pExplicitValueProvider->getRectangleOfObject(aCID_X, true).Height; + if (nTitleSpaceHeight) + nTitleSpaceHeight += constDiagramTitleSpace; + } + if (xTitle_Width.is()) + { + OUString aCID_Y( + ObjectIdentifier::createClassifiedIdentifierForObject(xTitle_Width, &rModel)); + nTitleSpaceWidth = pExplicitValueProvider->getRectangleOfObject(aCID_Y, true).Width; + if (nTitleSpaceWidth) + nTitleSpaceWidth += constDiagramTitleSpace; + } + if (xSecondTitle_Height.is()) + { + OUString aCID_X(ObjectIdentifier::createClassifiedIdentifierForObject( + xSecondTitle_Height, &rModel)); + nSecondTitleSpaceHeight + = pExplicitValueProvider->getRectangleOfObject(aCID_X, true).Height; + if (nSecondTitleSpaceHeight) + nSecondTitleSpaceHeight += constDiagramTitleSpace; + } + if (xSecondTitle_Width.is()) + { + OUString aCID_Y(ObjectIdentifier::createClassifiedIdentifierForObject( + xSecondTitle_Width, &rModel)); + nSecondTitleSpaceWidth + += pExplicitValueProvider->getRectangleOfObject(aCID_Y, true).Width; + if (nSecondTitleSpaceWidth) + nSecondTitleSpaceWidth += constDiagramTitleSpace; + } + if (bSubtract) + { + aRet.X += nTitleSpaceWidth; + aRet.Y += nSecondTitleSpaceHeight; + aRet.Width -= (nTitleSpaceWidth + nSecondTitleSpaceWidth); + aRet.Height -= (nTitleSpaceHeight + nSecondTitleSpaceHeight); + } + else + { + aRet.X -= nTitleSpaceWidth; + aRet.Y -= nSecondTitleSpaceHeight; + aRet.Width += nTitleSpaceWidth + nSecondTitleSpaceWidth; + aRet.Height += nTitleSpaceHeight + nSecondTitleSpaceHeight; + } + } + } + return aRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/LabelPositionHelper.cxx b/chart2/source/view/main/LabelPositionHelper.cxx new file mode 100644 index 000000000..e39bc0495 --- /dev/null +++ b/chart2/source/view/main/LabelPositionHelper.cxx @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +LabelPositionHelper::LabelPositionHelper( + sal_Int32 nDimensionCount + , const rtl::Reference& xLogicTarget) + : m_nDimensionCount(nDimensionCount) + , m_xLogicTarget(xLogicTarget) +{ +} + +LabelPositionHelper::~LabelPositionHelper() +{ +} + +awt::Point LabelPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D ) const +{ + return PlottingPositionHelper::transformSceneToScreenPosition( + rScenePosition3D, m_xLogicTarget, m_nDimensionCount ); +} + +void LabelPositionHelper::changeTextAdjustment( tAnySequence& rPropValues, const tNameSequence& rPropNames, LabelAlignment eAlignment) +{ + //HorizontalAdjustment + { + drawing::TextHorizontalAdjust eHorizontalAdjust = drawing::TextHorizontalAdjust_CENTER; + if( eAlignment==LABEL_ALIGN_RIGHT || eAlignment==LABEL_ALIGN_RIGHT_TOP || eAlignment==LABEL_ALIGN_RIGHT_BOTTOM ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_LEFT; + else if( eAlignment==LABEL_ALIGN_LEFT || eAlignment==LABEL_ALIGN_LEFT_TOP || eAlignment==LABEL_ALIGN_LEFT_BOTTOM ) + eHorizontalAdjust = drawing::TextHorizontalAdjust_RIGHT; + uno::Any* pHorizontalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,u"TextHorizontalAdjust"); + if(pHorizontalAdjustAny) + *pHorizontalAdjustAny <<= eHorizontalAdjust; + } + + //VerticalAdjustment + { + drawing::TextVerticalAdjust eVerticalAdjust = drawing::TextVerticalAdjust_CENTER; + if( eAlignment==LABEL_ALIGN_TOP || eAlignment==LABEL_ALIGN_RIGHT_TOP || eAlignment==LABEL_ALIGN_LEFT_TOP ) + eVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM; + else if( eAlignment==LABEL_ALIGN_BOTTOM || eAlignment==LABEL_ALIGN_RIGHT_BOTTOM || eAlignment==LABEL_ALIGN_LEFT_BOTTOM ) + eVerticalAdjust = drawing::TextVerticalAdjust_TOP; + uno::Any* pVerticalAdjustAny = PropertyMapper::getValuePointer(rPropValues,rPropNames,u"TextVerticalAdjust"); + if(pVerticalAdjustAny) + *pVerticalAdjustAny <<= eVerticalAdjust; + } +} + +static void lcl_doDynamicFontResize( uno::Any* pAOldAndNewFontHeightAny + , const awt::Size& rOldReferenceSize + , const awt::Size& rNewReferenceSize ) +{ + double fOldFontHeight = 0; + if( pAOldAndNewFontHeightAny && ( *pAOldAndNewFontHeightAny >>= fOldFontHeight ) ) + { + double fNewFontHeight = RelativeSizeHelper::calculate( fOldFontHeight, rOldReferenceSize, rNewReferenceSize ); + *pAOldAndNewFontHeightAny <<= fNewFontHeight; + } +} + +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( "ReferencePageSize") >>= aOldReferenceSize ) + { + uno::Any* pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, u"CharHeight" ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, u"CharHeightAsian" ); + lcl_doDynamicFontResize( pAOldAndNewFontHeightAny, aOldReferenceSize, rNewReferenceSize ); + pAOldAndNewFontHeightAny = PropertyMapper::getValuePointer( rPropValues, rPropNames, u"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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*std::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*std::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = -aSize.Width *std::sin( beta ) + -aSize.Height *std::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *std::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *std::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - M_PI; + rfXCorrection = -aSize.Width *std::cos( beta ) + -aSize.Height*std::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *std::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *std::sin( beta ); + } + else + { + double beta = 2*M_PI - fAnglePi; + rfXCorrection = -aSize.Height*std::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*std::sin( fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width*std::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = M_PI - fAnglePi; + rfXCorrection = aSize.Width *std::cos( beta ) + + aSize.Height*std::sin( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = aSize.Width *std::sin( beta )/2.0; + else + rfYCorrection = aSize.Width *std::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = aSize.Width *std::sin( beta ) + +aSize.Height*std::cos( beta )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width *std::cos( beta )/2.0; + else + rfYCorrection = -aSize.Width *std::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*std::sin( 2*M_PI - fAnglePi )/2.0; + if( bRotateAroundCenter ) + rfYCorrection = -aSize.Width*std::sin( 2*M_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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree== 0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*std::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*std::cos( fAnglePi )/2.0; + rfYCorrection = -aSize.Width*std::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi - M_PI_2; + rfXCorrection = aSize.Height*std::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*std::sin( beta )/2.0; + rfYCorrection = -aSize.Width*std::cos( beta )/2.0 + - aSize.Height*std::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = fAnglePi - M_PI; + rfXCorrection = -aSize.Height *std::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *std::cos( beta )/2.0; + rfYCorrection = -aSize.Width *std::sin( beta )/2.0 + -aSize.Height *std::cos( beta ); + } + else + { + rfXCorrection = aSize.Height*std::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width*std::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*std::sin( fAnglePi )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *std::cos( fAnglePi )/2.0; + rfYCorrection = aSize.Width*std::sin( fAnglePi )/2.0; + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = -aSize.Height*std::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width *std::sin( beta )/2.0; + rfYCorrection = aSize.Width *std::cos( beta )/2.0 + +aSize.Height*std::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = aSize.Height*std::cos( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection -= aSize.Width *std::sin( beta )/2.0; + rfYCorrection = aSize.Height*std::sin( beta ) + +aSize.Width*std::cos( beta )/2.0; + } + else + { + double beta = 2*M_PI - fAnglePi; + rfXCorrection = aSize.Height*std::sin( beta )/2.0; + if( !bRotateAroundCenter ) + rfXCorrection += aSize.Width*std::cos( beta )/2.0; + rfYCorrection = aSize.Width*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = -aSize.Width*std::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = -aSize.Width*std::sin( beta ); + rfYCorrection = -aSize.Height*std::sin( beta ) + -aSize.Width*std::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = -aSize.Height*std::cos( beta ) + -aSize.Width*std::sin( beta ); + rfYCorrection = -aSize.Height*std::sin( beta ); + } + else + { + rfXCorrection = aSize.Height*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = -aSize.Height*std::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = -aSize.Width*std::sin( beta ) + -aSize.Height*std::cos( beta ); + rfYCorrection = aSize.Height*std::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = -aSize.Width*std::sin( beta ); + rfYCorrection = aSize.Width*std::cos( beta ) + +aSize.Height*std::sin( beta ); + } + else + { + rfYCorrection = -aSize.Width*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfXCorrection = aSize.Height*std::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = aSize.Width*std::sin( beta ) + +aSize.Height*std::cos( beta ); + rfYCorrection = -aSize.Height*std::sin( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = aSize.Width*std::sin( beta ); + rfYCorrection = -aSize.Width*std::cos( beta ) + -aSize.Height*std::sin( beta ); + } + else + { + rfYCorrection = aSize.Width*std::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 = basegfx::deg2rad(fAnglePositiveDegree); + if( fAnglePositiveDegree==0.0 ) + { + } + else if( fAnglePositiveDegree<= 90.0 ) + { + rfYCorrection = aSize.Width*std::sin( fAnglePi ); + } + else if( fAnglePositiveDegree<= 180.0 ) + { + double beta = fAnglePi-M_PI_2; + rfXCorrection = aSize.Width*std::sin( beta ); + rfYCorrection = aSize.Height*std::sin( beta ) + +aSize.Width*std::cos( beta ); + } + else if( fAnglePositiveDegree<= 270.0 ) + { + double beta = 3*M_PI_2 - fAnglePi; + rfXCorrection = aSize.Height*std::cos( beta ) + +aSize.Width*std::sin( beta ); + rfYCorrection = aSize.Height*std::sin( beta ); + } + else + { + rfXCorrection = -aSize.Height*std::sin( fAnglePi ); + } +} + +}//end anonymous namespace + +void LabelPositionHelper::correctPositionForRotation( const rtl::Reference& 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(aOldPos.X + fXCorrection ) + , static_cast(aOldPos.Y + fYCorrection ) ) ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/Linear3DTransformation.cxx b/chart2/source/view/main/Linear3DTransformation.cxx new file mode 100644 index 000000000..0d723ef34 --- /dev/null +++ b/chart2/source/view/main/Linear3DTransformation.cxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + + Linear3DTransformation::Linear3DTransformation( const drawing::HomogenMatrix& rHomMatrix, bool bSwapXAndY ) + : m_Matrix(rHomMatrix) + , m_bSwapXAndY(bSwapXAndY) +{} + +Linear3DTransformation::~Linear3DTransformation() +{} + +// ____ XTransformation2 ____ +css::drawing::Position3D Linear3DTransformation::transform( + const Sequence< double >& rSourceValues ) const +{ + double fX = rSourceValues[0]; + double fY = rSourceValues[1]; + double fZ = rSourceValues[2]; + if(m_bSwapXAndY) + std::swap(fX,fY); + css::drawing::Position3D aNewVec; + double fZwi; + + fZwi = m_Matrix.Line1.Column1 * fX + + m_Matrix.Line1.Column2 * fY + + m_Matrix.Line1.Column3 * fZ + + m_Matrix.Line1.Column4; + aNewVec.PositionX = fZwi; + + fZwi = m_Matrix.Line2.Column1 * fX + + m_Matrix.Line2.Column2 * fY + + m_Matrix.Line2.Column3 * fZ + + m_Matrix.Line2.Column4; + aNewVec.PositionY = fZwi; + + fZwi = m_Matrix.Line3.Column1 * fX + + m_Matrix.Line3.Column2 * fY + + m_Matrix.Line3.Column3 * fZ + + m_Matrix.Line3.Column4; + aNewVec.PositionZ = 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.PositionX /= fZwi; + aNewVec.PositionY /= fZwi; + aNewVec.PositionZ /= fZwi; + } + return aNewVec; +} + +css::drawing::Position3D Linear3DTransformation::transform( + const css::drawing::Position3D& rSourceValues ) const +{ + double fX = rSourceValues.PositionX; + double fY = rSourceValues.PositionY; + double fZ = rSourceValues.PositionZ; + if(m_bSwapXAndY) + std::swap(fX,fY); + css::drawing::Position3D aNewVec; + double fZwi; + + fZwi = m_Matrix.Line1.Column1 * fX + + m_Matrix.Line1.Column2 * fY + + m_Matrix.Line1.Column3 * fZ + + m_Matrix.Line1.Column4; + aNewVec.PositionX = fZwi; + + fZwi = m_Matrix.Line2.Column1 * fX + + m_Matrix.Line2.Column2 * fY + + m_Matrix.Line2.Column3 * fZ + + m_Matrix.Line2.Column4; + aNewVec.PositionY = fZwi; + + fZwi = m_Matrix.Line3.Column1 * fX + + m_Matrix.Line3.Column2 * fY + + m_Matrix.Line3.Column3 * fZ + + m_Matrix.Line3.Column4; + aNewVec.PositionZ = 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.PositionX /= fZwi; + aNewVec.PositionY /= fZwi; + aNewVec.PositionZ /= fZwi; + } + return aNewVec; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/PlotterBase.cxx b/chart2/source/view/main/PlotterBase.cxx new file mode 100644 index 000000000..a706f1600 --- /dev/null +++ b/chart2/source/view/main/PlotterBase.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PlotterBase::PlotterBase( sal_Int32 nDimensionCount ) + : m_nDimension(nDimensionCount) + , m_pPosHelper(nullptr) +{ +} + +void PlotterBase::initPlotter( const rtl::Reference& xLogicTarget + , const rtl::Reference& xFinalTarget + , const OUString& rCID ) +{ + OSL_PRECOND(xLogicTarget.is()&&xFinalTarget.is(),"no proper initialization parameters"); + //is only allowed to be called once + m_xLogicTarget = xLogicTarget; + m_xFinalTarget = xFinalTarget; + m_aCID = rCID; +} + +PlotterBase::~PlotterBase() +{ +} + +void PlotterBase::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) +{ + if (!m_pPosHelper) + return; + + OSL_PRECOND(m_nDimension<=static_cast(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence"); + m_pPosHelper->setScales( std::move(rScales), bSwapXAndYAxis ); +} + +void PlotterBase::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + if (!m_pPosHelper) + return; + + OSL_PRECOND(m_nDimension==2,"Set this transformation only in case of 2D"); + if(m_nDimension!=2) + return; + m_pPosHelper->setTransformationSceneToScreen( rMatrix ); +} + +rtl::Reference PlotterBase::createGroupShape( + const rtl::Reference& xTarget + , const OUString& rName ) +{ + if(m_nDimension==2) + { + //create and add to target + return ShapeFactory::createGroup2D( xTarget, rName ); + } + else + { + //create and added to target + return ShapeFactory::createGroup3D( xTarget, rName ); + } +} + +bool PlotterBase::isValidPosition( const drawing::Position3D& rPos ) +{ + if( std::isnan(rPos.PositionX) ) + return false; + if( std::isnan(rPos.PositionY) ) + return false; + if( std::isnan(rPos.PositionZ) ) + return false; + if( std::isinf(rPos.PositionX) ) + return false; + if( std::isinf(rPos.PositionY) ) + return false; + if( std::isinf(rPos.PositionZ) ) + return false; + return true; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/PlottingPositionHelper.cxx b/chart2/source/view/main/PlottingPositionHelper.cxx new file mode 100644 index 000000000..eab2f69e7 --- /dev/null +++ b/chart2/source/view/main/PlottingPositionHelper.cxx @@ -0,0 +1,708 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +XTransformation2::~XTransformation2() {} + +PlottingPositionHelper::PlottingPositionHelper() + : m_bSwapXAndY( false ) + , m_nXResolution( 1000 ) + , m_nYResolution( 1000 ) + , m_nZResolution( 1000 ) + , m_bMaySkipPointsInRegressionCalculation( true ) + , m_bDateAxis(false) + , m_nTimeResolution( css::chart::TimeUnit::DAY ) + , m_aNullDate(30,12,1899) + , m_fScaledCategoryWidth(1.0) + , m_bAllowShiftXAxisPos(false) + , m_bAllowShiftZAxisPos(false) +{ +} +PlottingPositionHelper::PlottingPositionHelper( const PlottingPositionHelper& rSource ) + : m_aScales( rSource.m_aScales ) + , m_aMatrixScreenToScene( rSource.m_aMatrixScreenToScene ) + // m_xTransformationLogicToScene( nullptr ) //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 ) + , m_bDateAxis( rSource.m_bDateAxis ) + , m_nTimeResolution( rSource.m_nTimeResolution ) + , m_aNullDate( rSource.m_aNullDate ) + , m_fScaledCategoryWidth( rSource.m_fScaledCategoryWidth ) + , m_bAllowShiftXAxisPos( rSource.m_bAllowShiftXAxisPos ) + , m_bAllowShiftZAxisPos( rSource.m_bAllowShiftZAxisPos ) +{ +} + +PlottingPositionHelper::~PlottingPositionHelper() +{ + +} + +std::unique_ptr PlottingPositionHelper::clone() const +{ + return std::make_unique(*this); +} + +std::unique_ptr PlottingPositionHelper::createSecondaryPosHelper( const ExplicitScaleData& rSecondaryScale ) +{ + auto pRet = clone(); + pRet->m_aScales[1]=rSecondaryScale; + return pRet; +} + +void PlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + m_aMatrixScreenToScene = HomogenMatrixToB3DHomMatrix(rMatrix); + m_xTransformationLogicToScene = nullptr; +} + +void PlottingPositionHelper::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) +{ + m_aScales = std::move(rScales); + m_bSwapXAndY = bSwapXAndYAxis; + m_xTransformationLogicToScene = nullptr; +} + +::chart::XTransformation2* PlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + //this is a standard transformation for a cartesian coordinate system + + //transformation from 2) to 4) //@todo 2) and 4) need an 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 a double ) + if(!m_xTransformationLogicToScene) + { + ::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 + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &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 = nXAxisOrientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0; + double fScaleDirectionY = nYAxisOrientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0; + double fScaleDirectionZ = nZAxisOrientation==AxisOrientation_MATHEMATICAL ? -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( nXAxisOrientation==AxisOrientation_MATHEMATICAL ) + aMatrix.translate(-MinX*fScaleX, 0.0, 0.0); + else + aMatrix.translate(-MaxX*fScaleX, 0.0, 0.0); + if( nYAxisOrientation==AxisOrientation_MATHEMATICAL ) + aMatrix.translate(0.0, -MinY*fScaleY, 0.0); + else + aMatrix.translate(0.0, -MaxY*fScaleY, 0.0); + if( nZAxisOrientation==AxisOrientation_MATHEMATICAL ) + 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.reset(new Linear3DTransformation(B3DHomMatrixToHomogenMatrix( aMatrix ), m_bSwapXAndY)); + } + return m_xTransformationLogicToScene.get(); +} + +drawing::Position3D PlottingPositionHelper::transformLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + doLogicScaling( &fX,&fY,&fZ ); + if(bClip) + clipScaledLogicValues( &fX,&fY,&fZ ); + + return transformScaledLogicToScene( fX, fY, fZ, false ); +} + +drawing::Position3D PlottingPositionHelper::transformScaledLogicToScene( + double fX, double fY, double fZ, bool bClip ) const +{ + if( bClip ) + clipScaledLogicValues( &fX,&fY,&fZ ); + + drawing::Position3D aPos( fX, fY, fZ); + + ::chart::XTransformation2* pTransformation = + getTransformationScaledLogicToScene(); + return pTransformation->transform( aPos ); +} + +awt::Point PlottingPositionHelper::transformSceneToScreenPosition( const drawing::Position3D& rScenePosition3D + , const rtl::Reference& xSceneTarget + , sal_Int32 nDimensionCount ) +{ + //@todo would like to have a cheaper method to do this transformation + awt::Point aScreenPoint( static_cast(rScenePosition3D.PositionX), static_cast(rScenePosition3D.PositionY) ); + + //transformation from scene to screen (only necessary for 3D): + if(nDimensionCount==3) + { + //create 3D anchor shape + tPropertyNameMap aDummyPropertyNameMap; + rtl::Reference xShape3DAnchor = ShapeFactory::createCube( xSceneTarget + , rScenePosition3D,drawing::Direction3D(1,1,1) + , 0, nullptr, aDummyPropertyNameMap); + //get 2D position from xShape3DAnchor + aScreenPoint = xShape3DAnchor->getPosition(); + xSceneTarget->remove(xShape3DAnchor); + } + return aScreenPoint; +} + +void PlottingPositionHelper::transformScaledLogicToScene( drawing::PolyPolygonShape3D& rPolygon ) const +{ + drawing::Position3D aScenePosition; + auto SequenceXRange = asNonConstRange(rPolygon.SequenceX); + auto SequenceYRange = asNonConstRange(rPolygon.SequenceY); + auto SequenceZRange = asNonConstRange(rPolygon.SequenceZ); + for( sal_Int32 nS = rPolygon.SequenceX.getLength(); nS--;) + { + auto xValuesRange = asNonConstRange(SequenceXRange[nS]); + auto yValuesRange = asNonConstRange(SequenceYRange[nS]); + auto zValuesRange = asNonConstRange(SequenceZRange[nS]); + for( sal_Int32 nP = SequenceXRange[nS].getLength(); nP--; ) + { + double& fX = xValuesRange[nP]; + double& fY = yValuesRange[nP]; + double& fZ = zValuesRange[nP]; + aScenePosition = transformScaledLogicToScene( fX,fY,fZ,true ); + fX = aScenePosition.PositionX; + fY = aScenePosition.PositionY; + fZ = aScenePosition.PositionZ; + } + } +} + +void PlottingPositionHelper::transformScaledLogicToScene( std::vector>& rPolygon ) const +{ + drawing::Position3D aScenePosition; + for( sal_Int32 nS = static_cast(rPolygon.size()); nS--;) + { + auto valuesRange = rPolygon[nS].data(); + for( sal_Int32 nP = rPolygon[nS].size(); nP--; ) + { + double& fX = valuesRange[nP].PositionX; + double& fY = valuesRange[nP].PositionY; + double& fZ = valuesRange[nP].PositionZ; + aScenePosition = 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 + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &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 + doUnshiftedLogicScaling( &MinX, &MinY, &MinZ ); + doUnshiftedLogicScaling( &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() + : m_fRadiusOffset(0.0) + , m_fAngleDegreeOffset(90.0) +{ + 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 ) +{ +} + +PolarPlottingPositionHelper::~PolarPlottingPositionHelper() +{ +} + +std::unique_ptr PolarPlottingPositionHelper::clone() const +{ + return std::make_unique(*this); +} + +void PolarPlottingPositionHelper::setTransformationSceneToScreen( const drawing::HomogenMatrix& rMatrix) +{ + PlottingPositionHelper::setTransformationSceneToScreen( rMatrix); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} +void PolarPlottingPositionHelper::setScales( std::vector< ExplicitScaleData >&& rScales, bool bSwapXAndYAxis ) +{ + PlottingPositionHelper::setScales( std::move(rScales), bSwapXAndYAxis ); + m_aUnitCartesianToScene =impl_calculateMatrixUnitCartesianToScene( m_aMatrixScreenToScene ); +} + +::basegfx::B3DHomMatrix PolarPlottingPositionHelper::impl_calculateMatrixUnitCartesianToScene( const ::basegfx::B3DHomMatrix& rMatrixScreenToScene ) const +{ + ::basegfx::B3DHomMatrix aRet; + + if( m_aScales.empty() ) + return aRet; + + double fTranslate =1.0; + double fScale =FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0; + + double fTranslateLogicZ; + double fScaleLogicZ; + { + double fScaleDirectionZ = m_aScales[2].Orientation==AxisOrientation_MATHEMATICAL ? 1.0 : -1.0; + double MinZ = getLogicMinZ(); + double MaxZ = getLogicMaxZ(); + doLogicScaling( nullptr, nullptr, &MinZ ); + doLogicScaling( nullptr, nullptr, &MaxZ ); + double fWidthZ = MaxZ - MinZ; + + if( m_aScales[2].Orientation==AxisOrientation_MATHEMATICAL ) + fTranslateLogicZ=MinZ; + else + fTranslateLogicZ=MaxZ; + fScaleLogicZ = fScaleDirectionZ*FIXED_SIZE_FOR_3D_CHART_VOLUME/fWidthZ; + } + + double fTranslateX = fTranslate; + double fTranslateY = fTranslate; + double fTranslateZ = fTranslateLogicZ; + + double fScaleX = fScale; + double fScaleY = fScale; + double fScaleZ = fScaleLogicZ; + + aRet.translate(fTranslateX, fTranslateY, fTranslateZ);//x first + aRet.scale(fScaleX, fScaleY, fScaleZ);//x first + + aRet = rMatrixScreenToScene * aRet; + return aRet; +} + +::chart::XTransformation2* PolarPlottingPositionHelper::getTransformationScaledLogicToScene() const +{ + if( !m_xTransformationLogicToScene ) + m_xTransformationLogicToScene.reset(new VPolarTransformation(*this)); + return m_xTransformationLogicToScene.get(); +} + +double PolarPlottingPositionHelper::getWidthAngleDegree( double& fStartLogicValueOnAngleAxis, double& fEndLogicValueOnAngleAxis ) const +{ + const ExplicitScaleData& rAngleScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0]; + if( rAngleScale.Orientation != AxisOrientation_MATHEMATICAL ) + { + double fHelp = fEndLogicValueOnAngleAxis; + fEndLogicValueOnAngleAxis = fStartLogicValueOnAngleAxis; + fStartLogicValueOnAngleAxis = fHelp; + } + + double fStartAngleDegree = transformToAngleDegree( fStartLogicValueOnAngleAxis ); + double fEndAngleDegree = transformToAngleDegree( fEndLogicValueOnAngleAxis ); + double fWidthAngleDegree = fEndAngleDegree - fStartAngleDegree; + + if( ::rtl::math::approxEqual( fStartAngleDegree, fEndAngleDegree ) + && !::rtl::math::approxEqual( fStartLogicValueOnAngleAxis, fEndLogicValueOnAngleAxis ) ) + fWidthAngleDegree = 360.0; + + // tdf#123504: both 0 and 360 are valid and different values here! + while (fWidthAngleDegree < 0.0) + fWidthAngleDegree += 360.0; + while (fWidthAngleDegree > 360.0) + fWidthAngleDegree -= 360.0; + + return fWidthAngleDegree; +} + +//This method does a lot of computation for understanding which scale to +//utilize and if reverse orientation should be used. Indeed, for a pie or donut, +//the final result is as simple as multiplying by 360 and adding +//`m_fAngleDegreeOffset`. +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(rScale.Orientation != AxisOrientation_MATHEMATICAL) + 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); + // tdf#123504: both 0 and 360 are valid and different values here! + while (fRet > 360.0) + fRet -= 360.0; + while (fRet < 0) + fRet += 360.0; + return fRet; +} + +/** + * Given a value in the radius axis scale range, it returns, in the simplest + * case (that is when `m_fRadiusOffset` is zero), the normalized value; when + * `m_fRadiusOffset` is not zero (e.g. as in the case of a donut), the interval + * used for normalization is extended by `m_fRadiusOffset`: if the axis + * orientation is not reversed the new interval becomes + * [scale.Minimum - m_fRadiusOffset, scale.Maximum] else it becomes + * [scale.Minimum, scale.Maximum + m_fRadiusOffset]. + * Pay attention here! For the latter case, since the axis orientation is + * reversed, the normalization is reversed too. Indeed, we have + * `transformToRadius(scale.Maximum + m_fRadiusOffset) = 0` and + * `transformToRadius(scale.Minimum) = 1`. + * + * For a pie chart the radius axis scale range is initialized by the + * `getMinimum` and `getMaximum` methods of the `PieChart` object (see notes + * for `VCoordinateSystem::prepareAutomaticAxisScaling`). + * So we have scale.Minimum = 0.5 (always constant!) and + * scale.Maximum = 0.5 + number_of_rings + max_offset + * (see notes for `PieChart::getMaxOffset`). + * Hence we get the following general formulas for computing normalized inner + * and outer radius: + * + * 1- transformToRadius(inner_radius) = + * (number_of_rings - (ring_index + 1) + m_fRadiusOffset) + * / (number_of_rings + max_offset + m_fRadiusOffset) + * + * 2- transformToRadius(outer_radius) = + * (1 + number_of_rings - (ring_index + 1) + m_fRadiusOffset) + * / (number_of_rings + max_offset + m_fRadiusOffset). + * + * Here you have to take into account that values for inner and outer radius + * are swapped since the radius axis is reversed (See notes for + * `PiePositionHelper::getInnerAndOuterRadius`). So indeed inner_radius is + * the outer and outer_radius is the inner. Anyway still because of the reverse + * orientation, the normalization performed by `transformToRadius` is reversed + * too, as we have seen above. Hence `transformToRadius(inner_radius)` is + * really the normalized inner radius and `transformToRadius(outer_radius)` is + * really the normalized outer radius. + * + * Some basic examples where we apply the above formulas: + * 1- For a non-exploded pie chart we have: + * `transformToRadius(inner_radius) = 0`, + * `transformToRadius(outer_radius) = 1`. + * 2- For a non-exploded donut with a single ring we have: + * `transformToRadius(inner_radius) = + * m_fRadiusOffset/(1 + m_fRadiusOffset)`, + * `transformToRadius(outer_radius) = + * (1 + m_fRadiusOffset)/(1 + m_fRadiusOffset) = 1`. + * 3- For an exploded pie chart we have: + * `transformToRadius(inner_radius) = 0/(1 + max_offset) = 0`, + * `transformToRadius(outer_radius) = 1/(1 + max_offset)`. + * + * The third example needs some remark. Both the logical inner and outer + * radius passed to `transformToRadius` are offset by `max_offset`. + * However the returned normalized values do not contain any (normalized) + * offset term at all, otherwise the returned values would be + * `max_offset/(1 + max_offset)` and `1`. Hence, for exploded pie/donut, + * `transformToRadius` returns the normalized value of radii without any + * offset term. These values are smaller than in the non-exploded case by an + * amount equals to the value of the normalized maximum offset + * (`max_offset/(1 + max_offset)` in the example above). That is due to the + * fact that the normalization keeps into account the space needed for the + * offset. This is the correct behavior, in fact the offset for the current + * slice could be different from the maximum offset. + * These remarks should clarify why the `PieChart::createDataPoint` and + * `PieChart::createTextLabelShape` methods add the normalized offset (for the + * current slice) to the normalized radii in order to achieve the correct + * placement of slice and text shapes. + */ +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, nullptr ); + + fScaledLogicRadiusValue = m_bSwapXAndY ? fX : fY; + + bool bMinIsInnerRadius = true; + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if(rScale.Orientation != AxisOrientation_MATHEMATICAL) + bMinIsInnerRadius = false; + + double fInnerScaledLogicRadius=0.0; + double fOuterScaledLogicRadius=0.0; + { + double MinX = getLogicMinX(); + double MinY = getLogicMinY(); + doLogicScaling( &MinX, &MinY, nullptr ); + double MaxX = getLogicMaxX(); + double MaxY = getLogicMaxY(); + doLogicScaling( &MaxX, &MaxY, nullptr ); + + 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) + clipLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ ); +} + +drawing::Position3D PolarPlottingPositionHelper::transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const +{ + if(bClip) + clipScaledLogicValues( &fX,&fY,&fZ ); + double fLogicValueOnAngleAxis = m_bSwapXAndY ? fY : fX; + double fLogicValueOnRadiusAxis = m_bSwapXAndY ? fX : fY; + return transformAngleRadiusToScene( fLogicValueOnAngleAxis, fLogicValueOnRadiusAxis, fZ, false ); +} +drawing::Position3D PolarPlottingPositionHelper::transformUnitCircleToScene( double fUnitAngleDegree, double fUnitRadius + , double fLogicZ ) const +{ + double fAnglePi = basegfx::deg2rad(fUnitAngleDegree); + + double fX=fUnitRadius*std::cos(fAnglePi); + double fY=fUnitRadius*std::sin(fAnglePi); + double fZ=fLogicZ; + + //!! 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 = transformToAngleDegree(fLogicValueOnAngleAxis,bDoScaling); + double fUnitRadius = transformToRadius(fLogicValueOnRadiusAxis,bDoScaling); + + return transformUnitCircleToScene( fUnitAngleDegree, fUnitRadius, fLogicZ ); +} + +double PolarPlottingPositionHelper::getOuterLogicRadius() const +{ + const ExplicitScaleData& rScale = m_bSwapXAndY ? m_aScales[0] : m_aScales[1]; + if( rScale.Orientation==AxisOrientation_MATHEMATICAL ) + 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; +} + +void PlottingPositionHelper::setTimeResolution( tools::Long nTimeResolution, const Date& rNullDate ) +{ + m_nTimeResolution = nTimeResolution; + m_aNullDate = rNullDate; + + //adapt category width + double fCategoryWidth = 1.0; + if( !m_aScales.empty() ) + { + if( m_aScales[0].AxisType == css::chart2::AxisType::DATE ) + { + m_bDateAxis = true; + if( nTimeResolution == css::chart::TimeUnit::YEAR ) + { + const double fMonthCount = 12.0;//todo: this depends on the DateScaling and must be adjusted in case we use more generic calendars in future + fCategoryWidth = fMonthCount; + } + } + } + setScaledCategoryWidth(fCategoryWidth); +} + +void PlottingPositionHelper::setScaledCategoryWidth( double fScaledCategoryWidth ) +{ + m_fScaledCategoryWidth = fScaledCategoryWidth; +} +void PlottingPositionHelper::AllowShiftXAxisPos( bool bAllowShift ) +{ + m_bAllowShiftXAxisPos = bAllowShift; +} +void PlottingPositionHelper::AllowShiftZAxisPos( bool bAllowShift ) +{ + m_bAllowShiftZAxisPos = bAllowShift; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/PolarLabelPositionHelper.cxx b/chart2/source/view/main/PolarLabelPositionHelper.cxx new file mode 100644 index 000000000..d5c819954 --- /dev/null +++ b/chart2/source/view/main/PolarLabelPositionHelper.cxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +PolarLabelPositionHelper::PolarLabelPositionHelper( + PolarPlottingPositionHelper* pPosHelper + , sal_Int32 nDimensionCount + , const rtl::Reference& xLogicTarget ) + : LabelPositionHelper( nDimensionCount, xLogicTarget ) + , 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, css::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 != css::chart::DataLabelPlacement::OUTSIDE) + && (nLabelPlacement != css::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 polar coordinate system + fRadius = fUnitCircleOuterRadius; + else + fRadius = fUnitCircleInnerRadius + (fUnitCircleOuterRadius-fUnitCircleInnerRadius)/2.0 ; + + awt::Point aRet( transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( fAngleDegree, fRadius, fLogicZ+0.5 ) ) ); + + if(m_nDimensionCount==3 && nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE) + { + //check whether the upper or the downer edge is more distant from the center + //take the farthest point to put the label to + + awt::Point aP0( transformSceneToScreenPosition( + m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ ) ) ); + awt::Point aP1(aRet); + awt::Point aP2( 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 + + fAngleDegree = basegfx::rad2deg(atan2(fDY,fDX)); + } + //set LabelAlignment + if( !bCenter ) + { + // tdf#123504: both 0 and 360 are valid and different values here! + while (fAngleDegree > 360.0) + fAngleDegree -= 360.0; + while (fAngleDegree < 0.0) + fAngleDegree += 360.0; + + bool bOutside = nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE; + + if (fAngleDegree <= 5 || fAngleDegree >= 355) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT : LABEL_ALIGN_LEFT; + else if (fAngleDegree < 85) + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_TOP : LABEL_ALIGN_LEFT_BOTTOM; + else if (fAngleDegree <= 95) + rAlignment = bOutside ? LABEL_ALIGN_TOP : LABEL_ALIGN_BOTTOM; + else if (fAngleDegree < 175) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_TOP : LABEL_ALIGN_RIGHT_BOTTOM; + else if (fAngleDegree <= 185) + rAlignment = bOutside ? LABEL_ALIGN_LEFT : LABEL_ALIGN_RIGHT; + else if (fAngleDegree < 265) + rAlignment = bOutside ? LABEL_ALIGN_LEFT_BOTTOM : LABEL_ALIGN_RIGHT_TOP; + else if (fAngleDegree <= 275) + rAlignment = bOutside ? LABEL_ALIGN_BOTTOM : LABEL_ALIGN_TOP; + else + rAlignment = bOutside ? LABEL_ALIGN_RIGHT_BOTTOM : LABEL_ALIGN_LEFT_TOP; + } + else + { + rAlignment = LABEL_ALIGN_CENTER; + } + + //add a scaling independent Offset if requested + if( nScreenValueOffsetInRadiusDirection != 0) + { + awt::Point aOrigin( 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/PropertyMapper.cxx b/chart2/source/view/main/PropertyMapper.cxx new file mode 100644 index 000000000..0ee929bc7 --- /dev/null +++ b/chart2/source/view/main/PropertyMapper.cxx @@ -0,0 +1,561 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +void PropertyMapper::setMappedProperties( + SvxShape& xTarget + , const uno::Reference< beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap ) +{ + if( !xSource.is() ) + return; + + sal_Int32 nPropertyCount = rMap.size(); + tNameSequence aNames(nPropertyCount); + tAnySequence aValues(nPropertyCount); + auto pNames = aNames.getArray(); + auto pValues = aValues.getArray(); + sal_Int32 nN=0; + + for (auto const& elem : rMap) + { + const OUString & rTarget = elem.first; + const OUString & rSource = elem.second; + try + { + uno::Any aAny( xSource->getPropertyValue(rSource) ); + if( aAny.hasValue() ) + { + //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer) + pNames[nN] = rTarget; + pValues[nN] = std::move(aAny); + ++nN; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + if (nN == 0) + return; + //reduce to real property count + aNames.realloc(nN); + aValues.realloc(nN); + + uno::Reference< beans::XMultiPropertySet > xShapeMultiProp( xTarget, uno::UNO_QUERY_THROW ); + try + { + xShapeMultiProp->setPropertyValues( aNames, aValues ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); //if this occurs more often think of removing the XMultiPropertySet completely for better performance + } +} + +void PropertyMapper::setMappedProperties( + const uno::Reference< beans::XPropertySet >& xTarget + , const uno::Reference< beans::XPropertySet >& xSource + , const tPropertyNameMap& rMap ) +{ + if( !xTarget.is() || !xSource.is() ) + return; + + tNameSequence aNames; + tAnySequence aValues; + sal_Int32 nN=0; + sal_Int32 nPropertyCount = rMap.size(); + aNames.realloc(nPropertyCount); + auto pNames = aNames.getArray(); + aValues.realloc(nPropertyCount); + auto pValues = aValues.getArray(); + + for (auto const& elem : rMap) + { + const OUString & rTarget = elem.first; + const OUString & rSource = elem.second; + try + { + uno::Any aAny( xSource->getPropertyValue(rSource) ); + if( aAny.hasValue() ) + { + //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer) + pNames[nN] = rTarget; + pValues[nN] = aAny; + ++nN; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + if (nN == 0) + return; + + uno::Reference< beans::XMultiPropertySet > xShapeMultiProp( xTarget, uno::UNO_QUERY ); + if (xShapeMultiProp) + try + { + //reduce to real property count + aNames.realloc(nN); + aValues.realloc(nN); + xShapeMultiProp->setPropertyValues( aNames, aValues ); + return; // successful + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); //if this occurs more often think of removing the XMultiPropertySet completely for better performance + } + + // fall back to one at a time + try + { + for( sal_Int32 i = 0; i < nN; i++ ) + { + try + { + xTarget->setPropertyValue( aNames[i], aValues[i] ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +void PropertyMapper::getValueMap( + tPropertyNameValueMap& rValueMap + , const tPropertyNameMap& rNameMap + , const uno::Reference< beans::XPropertySet >& xSourceProp + ) +{ + uno::Reference< beans::XMultiPropertySet > xMultiPropSet(xSourceProp, uno::UNO_QUERY); + if((false) && xMultiPropSet.is()) + { + uno::Sequence< OUString > aPropSourceNames(rNameMap.size()); + auto aPropSourceNamesRange = asNonConstRange(aPropSourceNames); + uno::Sequence< OUString > aPropTargetNames(rNameMap.size()); + auto aPropTargetNamesRange = asNonConstRange(aPropTargetNames); + sal_Int32 i = 0; + for (auto const& elem : rNameMap) + { + aPropTargetNamesRange[i] = elem.first; + aPropSourceNamesRange[i] = elem.second; + ++i; + } + + uno::Sequence< uno::Any > xValues = xMultiPropSet->getPropertyValues(aPropSourceNames); + sal_Int32 n = rNameMap.size(); + for(i = 0;i < n; ++i) + { + if( xValues[i].hasValue() ) + rValueMap.emplace( aPropTargetNames[i], xValues[i] ); + } + } + else + { + for (auto const& elem : rNameMap) + { + const OUString & rTarget = elem.first; + const OUString & rSource = elem.second; + try + { + uno::Any aAny( xSourceProp->getPropertyValue(rSource) ); + if( aAny.hasValue() ) + rValueMap.emplace( rTarget, aAny ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } +} + +void PropertyMapper::getMultiPropertyListsFromValueMap( + tNameSequence& rNames + , tAnySequence& rValues + , const tPropertyNameValueMap& rValueMap + ) +{ + sal_Int32 nPropertyCount = rValueMap.size(); + rNames.realloc(nPropertyCount); + auto pNames = rNames.getArray(); + rValues.realloc(nPropertyCount); + auto pValues = rValues.getArray(); + + //fill sequences + sal_Int32 nN=0; + for (auto const& elem : rValueMap) + { + const uno::Any& rAny = elem.second; + if( rAny.hasValue() ) + { + //do not set empty anys because of performance (otherwise SdrAttrObj::ItemChange will take much longer) + pNames[nN] = elem.first; + pValues[nN] = rAny; + ++nN; + } + } + //reduce to real property count + rNames.realloc(nN); + rValues.realloc(nN); +} + +uno::Any* PropertyMapper::getValuePointer( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , std::u16string_view rPropName ) +{ + sal_Int32 nCount = rPropNames.getLength(); + for( sal_Int32 nN = 0; nN < nCount; nN++ ) + { + if(rPropNames[nN] == rPropName) + return &rPropValues.getArray()[nN]; + } + return nullptr; +} + +uno::Any* PropertyMapper::getValuePointerForLimitedSpace( tAnySequence& rPropValues + , const tNameSequence& rPropNames + , bool bLimitedHeight) +{ + return PropertyMapper::getValuePointer( rPropValues, rPropNames + , bLimitedHeight ? OUString("TextMaximumFrameHeight") : OUString("TextMaximumFrameWidth") ); +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForCharacterProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForCharacterProperties{ + {"CharColor", "CharColor"}, + {"CharContoured", "CharContoured"}, + {"CharEmphasis", "CharEmphasis"},//the service style::CharacterProperties describes a property called 'CharEmphasize' which is nowhere implemented + + {"CharFontFamily", "CharFontFamily"}, + {"CharFontFamilyAsian", "CharFontFamilyAsian"}, + {"CharFontFamilyComplex", "CharFontFamilyComplex"}, + {"CharFontCharSet", "CharFontCharSet"}, + {"CharFontCharSetAsian", "CharFontCharSetAsian"}, + {"CharFontCharSetComplex", "CharFontCharSetComplex"}, + {"CharFontName", "CharFontName"}, + {"CharFontNameAsian", "CharFontNameAsian"}, + {"CharFontNameComplex", "CharFontNameComplex"}, + {"CharFontPitch", "CharFontPitch"}, + {"CharFontPitchAsian", "CharFontPitchAsian"}, + {"CharFontPitchComplex", "CharFontPitchComplex"}, + {"CharFontStyleName", "CharFontStyleName"}, + {"CharFontStyleNameAsian", "CharFontStyleNameAsian"}, + {"CharFontStyleNameComplex", "CharFontStyleNameComplex"}, + + {"CharHeight", "CharHeight"}, + {"CharHeightAsian", "CharHeightAsian"}, + {"CharHeightComplex", "CharHeightComplex"}, + {"CharKerning", "CharKerning"}, + {"CharLocale", "CharLocale"}, + {"CharLocaleAsian", "CharLocaleAsian"}, + {"CharLocaleComplex", "CharLocaleComplex"}, + {"CharPosture", "CharPosture"}, + {"CharPostureAsian", "CharPostureAsian"}, + {"CharPostureComplex", "CharPostureComplex"}, + {"CharRelief", "CharRelief"}, + {"CharShadowed", "CharShadowed"}, + {"CharStrikeout", "CharStrikeout"}, + {"CharUnderline", "CharUnderline"}, + {"CharUnderlineColor", "CharUnderlineColor"}, + {"CharUnderlineHasColor", "CharUnderlineHasColor"}, + {"CharOverline", "CharOverline"}, + {"CharOverlineColor", "CharOverlineColor"}, + {"CharOverlineHasColor", "CharOverlineHasColor"}, + {"CharWeight", "CharWeight"}, + {"CharWeightAsian", "CharWeightAsian"}, + {"CharWeightComplex", "CharWeightComplex"}, + {"CharWordMode", "CharWordMode"}, + + {"WritingMode", "WritingMode"}, + + {"ParaIsCharacterDistance", "ParaIsCharacterDistance"}}; + + return s_aShapePropertyMapForCharacterProperties; +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForParagraphProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForParagraphProperties{ + {"ParaAdjust", "ParaAdjust"}, + {"ParaBottomMargin", "ParaBottomMargin"}, + {"ParaIsHyphenation", "ParaIsHyphenation"}, + {"ParaLastLineAdjust", "ParaLastLineAdjust"}, + {"ParaLeftMargin", "ParaLeftMargin"}, + {"ParaRightMargin", "ParaRightMargin"}, + {"ParaTopMargin", "ParaTopMargin"}}; + return s_aShapePropertyMapForParagraphProperties; +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForFillProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForFillProperties{ + {"FillBackground", "FillBackground"}, + {"FillBitmapName", "FillBitmapName"}, + {"FillColor", "FillColor"}, + {"FillGradientName", "FillGradientName"}, + {"FillGradientStepCount", "FillGradientStepCount"}, + {"FillHatchName", "FillHatchName"}, + {"FillStyle", "FillStyle"}, + {"FillTransparence", "FillTransparence"}, + {"FillTransparenceGradientName", "FillTransparenceGradientName"}, + //bitmap properties + {"FillBitmapMode", "FillBitmapMode"}, + {"FillBitmapSizeX", "FillBitmapSizeX"}, + {"FillBitmapSizeY", "FillBitmapSizeY"}, + {"FillBitmapLogicalSize", "FillBitmapLogicalSize"}, + {"FillBitmapOffsetX", "FillBitmapOffsetX"}, + {"FillBitmapOffsetY", "FillBitmapOffsetY"}, + {"FillBitmapRectanglePoint", "FillBitmapRectanglePoint"}, + {"FillBitmapPositionOffsetX", "FillBitmapPositionOffsetX"}, + {"FillBitmapPositionOffsetY", "FillBitmapPositionOffsetY"}}; + return s_aShapePropertyMapForFillProperties; +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForLineProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForLineProperties{ + {"LineColor", "LineColor"}, + {"LineDashName", "LineDashName"}, + {"LineJoint", "LineJoint"}, + {"LineStyle", "LineStyle"}, + {"LineTransparence", "LineTransparence"}, + {"LineWidth", "LineWidth"}, + {"LineCap", "LineCap"}}; + return s_aShapePropertyMapForLineProperties; +} + +namespace { + tPropertyNameMap getPropertyNameMapForFillAndLineProperties_() { + auto map = PropertyMapper::getPropertyNameMapForFillProperties(); + auto const & add + = PropertyMapper::getPropertyNameMapForLineProperties(); + map.insert(add.begin(), add.end()); + return map; + } +} +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForFillAndLineProperties() +{ + static tPropertyNameMap s_aShapePropertyMapForFillAndLineProperties + = getPropertyNameMapForFillAndLineProperties_(); + return s_aShapePropertyMapForFillAndLineProperties; +} + +namespace { + tPropertyNameMap getPropertyNameMapForTextShapeProperties_() { + auto map = PropertyMapper::getPropertyNameMapForCharacterProperties(); + auto const & add1 + = PropertyMapper::getPropertyNameMapForFillProperties(); + map.insert(add1.begin(), add1.end()); + auto const & add2 + = PropertyMapper::getPropertyNameMapForLineProperties(); + map.insert(add2.begin(), add2.end()); + return map; + } +} +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForTextShapeProperties() +{ + static tPropertyNameMap s_aShapePropertyMapForTextShapeProperties + = getPropertyNameMapForTextShapeProperties_(); + return s_aShapePropertyMapForTextShapeProperties; +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForLineSeriesProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForLineSeriesProperties{ + {"LineColor", "Color"}, + {"LineDashName", "LineDashName"}, + {"LineStyle", "LineStyle"}, + {"LineTransparence", "Transparency"}, + {"LineWidth", "LineWidth"}, + {"LineCap", "LineCap"}}; + return s_aShapePropertyMapForLineSeriesProperties; +} + +namespace { + tPropertyNameMap getPropertyNameMapForTextLabelProperties_() { + auto map = PropertyMapper::getPropertyNameMapForCharacterProperties(); + map.insert({ + {"LineStyle", CHART_UNONAME_LABEL_BORDER_STYLE}, + {"LineWidth", CHART_UNONAME_LABEL_BORDER_WIDTH}, + {"LineColor", CHART_UNONAME_LABEL_BORDER_COLOR}, + {"LineTransparence", CHART_UNONAME_LABEL_BORDER_TRANS}, + {"FillStyle", CHART_UNONAME_LABEL_FILL_STYLE}, + {"FillColor", CHART_UNONAME_LABEL_FILL_COLOR}, + {"FillBackground", CHART_UNONAME_LABEL_FILL_BACKGROUND}, + {"FillHatchName", CHART_UNONAME_LABEL_FILL_HATCH_NAME} + }); + // fix the spelling! + return map; + } +} +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForTextLabelProperties() +{ + // target name (drawing layer) : source name (chart model) + static tPropertyNameMap aMap = getPropertyNameMapForTextLabelProperties_(); + return aMap; +} + +const tPropertyNameMap& PropertyMapper::getPropertyNameMapForFilledSeriesProperties() +{ + //shape property -- chart model object property + static tPropertyNameMap s_aShapePropertyMapForFilledSeriesProperties{ + {"FillBackground", "FillBackground"}, + {"FillBitmapName", "FillBitmapName"}, + {"FillColor", "Color"}, + {"FillGradientName", "GradientName"}, + {"FillGradientStepCount", "GradientStepCount"}, + {"FillHatchName", "HatchName"}, + {"FillStyle", "FillStyle"}, + {"FillTransparence", "Transparency"}, + {"FillTransparenceGradientName", "TransparencyGradientName"}, + //bitmap properties + {"FillBitmapMode", "FillBitmapMode"}, + {"FillBitmapSizeX", "FillBitmapSizeX"}, + {"FillBitmapSizeY", "FillBitmapSizeY"}, + {"FillBitmapLogicalSize", "FillBitmapLogicalSize"}, + {"FillBitmapOffsetX", "FillBitmapOffsetX"}, + {"FillBitmapOffsetY", "FillBitmapOffsetY"}, + {"FillBitmapRectanglePoint", "FillBitmapRectanglePoint"}, + {"FillBitmapPositionOffsetX", "FillBitmapPositionOffsetX"}, + {"FillBitmapPositionOffsetY", "FillBitmapPositionOffsetY"}, + //line properties + {"LineColor", "BorderColor"}, + {"LineDashName", "BorderDashName"}, + {"LineStyle", "BorderStyle"}, + {"LineTransparence", "BorderTransparency"}, + {"LineWidth", "BorderWidth"}, + {"LineCap", "LineCap"}}; + return s_aShapePropertyMapForFilledSeriesProperties; +} + +void PropertyMapper::setMultiProperties( + const tNameSequence& rNames + , const tAnySequence& rValues + , SvxShape& xTarget ) +{ + try + { + xTarget.setPropertyValues( rNames, rValues ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); //if this occurs more often think of removing the XMultiPropertySet completely for better performance + } +} + +void PropertyMapper::getTextLabelMultiPropertyLists( + const uno::Reference< beans::XPropertySet >& xSourceProp + , tNameSequence& rPropNames, tAnySequence& rPropValues + , bool bName + , sal_Int32 nLimitedSpace + , bool bLimitedHeight + , bool bSupportsLabelBorder) +{ + //fill character properties into the ValueMap + tPropertyNameValueMap aValueMap; + tPropertyNameMap const & aNameMap = bSupportsLabelBorder ? PropertyMapper::getPropertyNameMapForTextLabelProperties() : getPropertyNameMapForCharacterProperties(); + + PropertyMapper::getValueMap(aValueMap, aNameMap, xSourceProp); + + //some more shape properties apart from character properties, position-matrix and label string + aValueMap.emplace( "TextHorizontalAdjust", uno::Any(drawing::TextHorizontalAdjust_CENTER) ); // drawing::TextHorizontalAdjust - needs to be overwritten + aValueMap.emplace( "TextVerticalAdjust", uno::Any(drawing::TextVerticalAdjust_CENTER) ); //drawing::TextVerticalAdjust - needs to be overwritten + aValueMap.emplace( "TextAutoGrowHeight", uno::Any(true) ); // sal_Bool + aValueMap.emplace( "TextAutoGrowWidth", uno::Any(true) ); // sal_Bool + aValueMap.emplace( "ParaAdjust", uno::Any(style::ParagraphAdjust_CENTER) ); // style::ParagraphAdjust_CENTER - needs to be overwritten + if( bName ) + aValueMap.emplace( "Name", uno::Any( OUString() ) ); //CID OUString - needs to be overwritten for each point + + if( nLimitedSpace > 0 ) + { + if(bLimitedHeight) + aValueMap.emplace( "TextMaximumFrameHeight", uno::Any(nLimitedSpace) ); //sal_Int32 + else + aValueMap.emplace( "TextMaximumFrameWidth", uno::Any(nLimitedSpace) ); //sal_Int32 + aValueMap.emplace( "ParaIsHyphenation", uno::Any(true) ); + } + + 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.emplace( "TextHorizontalAdjust", uno::Any( drawing::TextHorizontalAdjust_CENTER )); + aValueMap.emplace( "TextVerticalAdjust", uno::Any( drawing::TextVerticalAdjust_CENTER )); + aValueMap.emplace( "TextAutoGrowHeight", uno::Any( true )); + aValueMap.emplace( "TextAutoGrowWidth", uno::Any( true )); + + // set some distance to the border, in case it is shown + const sal_Int32 nWidthDist = 250; + const sal_Int32 nHeightDist = 125; + aValueMap.emplace( "TextLeftDistance", uno::Any( nWidthDist )); + aValueMap.emplace( "TextRightDistance", uno::Any( nWidthDist )); + aValueMap.emplace( "TextUpperDistance", uno::Any( nHeightDist )); + aValueMap.emplace( "TextLowerDistance", uno::Any( nHeightDist )); + + // use a line-joint showing the border of thick lines like two rectangles + // filled in between. + aValueMap["LineJoint"] <<= drawing::LineJoint_ROUND; + + PropertyMapper::getMultiPropertyListsFromValueMap( rPropNames, rPropValues, aValueMap ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/SeriesPlotterContainer.cxx b/chart2/source/view/main/SeriesPlotterContainer.cxx new file mode 100644 index 000000000..1eb6a64a4 --- /dev/null +++ b/chart2/source/view/main/SeriesPlotterContainer.cxx @@ -0,0 +1,739 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "SeriesPlotterContainer.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace chart +{ +using namespace ::css; +using namespace ::css::chart2; + +using ::css::uno::Reference; +using ::css::uno::Sequence; +using ::css::uno::Any; + +SeriesPlotterContainer::SeriesPlotterContainer( + std::vector>& rVCooSysList) + : m_rVCooSysList(rVCooSysList) + , m_nMaxAxisIndex(0) + , m_bChartTypeUsesShiftedCategoryPositionPerDefault(false) + , m_nDefaultDateNumberFormat(0) +{ +} + +SeriesPlotterContainer::~SeriesPlotterContainer() +{ + // - remove plotter from coordinatesystems + for (auto& nC : m_rVCooSysList) + nC->clearMinimumAndMaximumSupplierList(); +} + +std::vector SeriesPlotterContainer::getLegendEntryProviderList() +{ + std::vector aRet(m_aSeriesPlotterList.size()); + sal_Int32 nN = 0; + for (const std::unique_ptr& aPlotter : m_aSeriesPlotterList) + aRet[nN++] = aPlotter.get(); + return aRet; +} + +VCoordinateSystem* SeriesPlotterContainer::findInCooSysList( + const std::vector>& rVCooSysList, + const rtl::Reference& xCooSys) +{ + for (auto& pVCooSys : rVCooSysList) + { + if (pVCooSys->getModel() == xCooSys) + return pVCooSys.get(); + } + return nullptr; +} + +VCoordinateSystem* SeriesPlotterContainer::getCooSysForPlotter( + const std::vector>& rVCooSysList, + MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier) +{ + if (!pMinimumAndMaximumSupplier) + return nullptr; + for (auto& pVCooSys : rVCooSysList) + { + if (pVCooSys->hasMinimumAndMaximumSupplier(pMinimumAndMaximumSupplier)) + return pVCooSys.get(); + } + return nullptr; +} + +VCoordinateSystem* SeriesPlotterContainer::addCooSysToList( + std::vector>& rVCooSysList, + const rtl::Reference& xCooSys, ChartModel& rChartModel) +{ + VCoordinateSystem* pExistingVCooSys + = SeriesPlotterContainer::findInCooSysList(rVCooSysList, xCooSys); + if (pExistingVCooSys) + return pExistingVCooSys; + + std::unique_ptr pVCooSys + = VCoordinateSystem::createCoordinateSystem(xCooSys); + if (!pVCooSys) + return nullptr; + + OUString aCooSysParticle( + ObjectIdentifier::createParticleForCoordinateSystem(xCooSys, &rChartModel)); + pVCooSys->setParticle(aCooSysParticle); + + pVCooSys->setExplicitCategoriesProvider(new ExplicitCategoriesProvider(xCooSys, rChartModel)); + rVCooSysList.push_back(std::move(pVCooSys)); + return rVCooSysList.back().get(); +} + +void SeriesPlotterContainer::initializeCooSysAndSeriesPlotter(ChartModel& rChartModel) +{ + rtl::Reference xDiagram = rChartModel.getFirstChartDiagram(); + if (!xDiagram.is()) + return; + + uno::Reference xNumberFormatsSupplier(&rChartModel); + if (rChartModel.hasInternalDataProvider() && DiagramHelper::isSupportingDateAxis(xDiagram)) + m_nDefaultDateNumberFormat = DiagramHelper::getDateNumberFormat(xNumberFormatsSupplier); + + sal_Int32 nDimensionCount = DiagramHelper::getDimension(xDiagram); + if (!nDimensionCount) + { + //@todo handle mixed dimension + nDimensionCount = 2; + } + + bool bSortByXValues = false; + bool bConnectBars = false; + bool bGroupBarsPerAxis = true; + bool bIncludeHiddenCells = true; + bool bSecondaryYaxisVisible = true; + sal_Int32 nStartingAngle = 90; + sal_Int32 n3DRelativeHeight = 100; + try + { + xDiagram->getPropertyValue(CHART_UNONAME_SORT_BY_XVALUES) >>= bSortByXValues; + xDiagram->getPropertyValue("ConnectBars") >>= bConnectBars; + xDiagram->getPropertyValue("GroupBarsPerAxis") >>= bGroupBarsPerAxis; + xDiagram->getPropertyValue("IncludeHiddenCells") >>= bIncludeHiddenCells; + xDiagram->getPropertyValue("StartingAngle") >>= nStartingAngle; + + if (nDimensionCount == 3) + { + xDiagram->getPropertyValue("3DRelativeHeight") >>= n3DRelativeHeight; + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + //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 xColorScheme(xDiagram->getDefaultColorScheme()); + auto& rCooSysList = xDiagram->getBaseCoordinateSystems(); + sal_Int32 nGlobalSeriesIndex = 0; //for automatic symbols + for (std::size_t nCS = 0; nCS < rCooSysList.size(); ++nCS) + { + rtl::Reference xCooSys(rCooSysList[nCS]); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::addCooSysToList(m_rVCooSysList, xCooSys, rChartModel); + // Let's check whether the secondary Y axis is visible + try + { + if (xCooSys->getMaximumAxisIndexByDimension(1) > 0) + { + rtl::Reference xAxisProp = xCooSys->getAxisByDimension2(1, 1); + xAxisProp->getPropertyValue("Show") >>= bSecondaryYaxisVisible; + } + } + catch (const lang::IndexOutOfBoundsException&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + //iterate through all chart types in the current coordinate system + std::vector> aChartTypeList(xCooSys->getChartTypes2()); + for (std::size_t nT = 0; nT < aChartTypeList.size(); ++nT) + { + rtl::Reference xChartType(aChartTypeList[nT]); + if (nDimensionCount == 3 + && xChartType->getChartType().equalsIgnoreAsciiCase( + CHART2_SERVICE_NAME_CHARTTYPE_PIE)) + { + try + { + sal_Int32 n3DRelativeHeightOldValue(100); + uno::Any aAny = xChartType->getPropertyValue("3DRelativeHeight"); + aAny >>= n3DRelativeHeightOldValue; + if (n3DRelativeHeightOldValue != n3DRelativeHeight) + xChartType->setPropertyValue("3DRelativeHeight", + uno::Any(n3DRelativeHeight)); + } + catch (const uno::Exception&) + { + } + } + + if (nT == 0) + m_bChartTypeUsesShiftedCategoryPositionPerDefault + = ChartTypeHelper::shiftCategoryPosAtXAxisPerDefault(xChartType); + + bool bExcludingPositioning = DiagramHelper::getDiagramPositioningMode(xDiagram) + == DiagramPositioningMode_EXCLUDING; + VSeriesPlotter* pPlotter = VSeriesPlotter::createSeriesPlotter( + xChartType, nDimensionCount, bExcludingPositioning); + if (!pPlotter) + continue; + + m_aSeriesPlotterList.push_back(std::unique_ptr(pPlotter)); + pPlotter->setNumberFormatsSupplier(xNumberFormatsSupplier); + pPlotter->setColorScheme(xColorScheme); + if (pVCooSys) + pPlotter->setExplicitCategoriesProvider(pVCooSys->getExplicitCategoriesProvider()); + sal_Int32 nMissingValueTreatment + = DiagramHelper::getCorrectedMissingValueTreatment(xDiagram, xChartType); + + if (pVCooSys) + pVCooSys->addMinimumAndMaximumSupplier(pPlotter); + + sal_Int32 zSlot = -1; + sal_Int32 xSlot = -1; + sal_Int32 ySlot = -1; + const std::vector>& aSeriesList + = xChartType->getDataSeries2(); + for (std::size_t nS = 0; nS < aSeriesList.size(); ++nS) + { + rtl::Reference const& xDataSeries = aSeriesList[nS]; + if (!bIncludeHiddenCells && !DataSeriesHelper::hasUnhiddenData(xDataSeries)) + continue; + + std::unique_ptr pSeries(new VDataSeries(xDataSeries)); + + pSeries->setGlobalSeriesIndex(nGlobalSeriesIndex); + nGlobalSeriesIndex++; + + if (bSortByXValues) + pSeries->doSortByXValues(); + + pSeries->setConnectBars(bConnectBars); + pSeries->setGroupBarsPerAxis(bGroupBarsPerAxis); + pSeries->setStartingAngle(nStartingAngle); + + pSeries->setMissingValueTreatment(nMissingValueTreatment); + + OUString aSeriesParticle(ObjectIdentifier::createParticleForSeries(0, nCS, nT, nS)); + pSeries->setParticle(aSeriesParticle); + + OUString aRole(ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( + xChartType)); + pSeries->setRoleOfSequenceForDataLabelNumberFormatDetection(aRole); + + //ignore secondary axis for charttypes that do not support them + if (pSeries->getAttachedAxisIndex() != MAIN_AXIS_INDEX + && (!ChartTypeHelper::isSupportingSecondaryAxis(xChartType, nDimensionCount) + || !bSecondaryYaxisVisible)) + { + 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(std::move(pSeries), zSlot, xSlot, ySlot); + } + } + } + + //transport seriesnames to the coordinatesystems if needed + if (m_aSeriesPlotterList.empty()) + return; + + uno::Sequence aSeriesNames; + bool bSeriesNamesInitialized = false; + for (auto& pVCooSys : m_rVCooSysList) + { + if (pVCooSys->needSeriesNamesForAxis()) + { + if (!bSeriesNamesInitialized) + { + aSeriesNames = m_aSeriesPlotterList[0]->getSeriesNames(); + bSeriesNamesInitialized = true; + } + pVCooSys->setSeriesNamesForAxis(aSeriesNames); + } + } +} + +bool SeriesPlotterContainer::isCategoryPositionShifted(const chart2::ScaleData& rSourceScale, + bool bHasComplexCategories) +{ + if (rSourceScale.AxisType == AxisType::CATEGORY) + return bHasComplexCategories || rSourceScale.ShiftedCategoryPosition + || m_bChartTypeUsesShiftedCategoryPositionPerDefault; + + if (rSourceScale.AxisType == AxisType::DATE) + return rSourceScale.ShiftedCategoryPosition; + + return rSourceScale.AxisType == AxisType::SERIES; +} + +void SeriesPlotterContainer::initAxisUsageList(const Date& rNullDate) +{ + m_aAxisUsageList.clear(); + + // Loop through coordinate systems in the diagram (though for now + // there should only be one coordinate system per diagram). + for (auto& pVCooSys : m_rVCooSysList) + { + rtl::Reference xCooSys = pVCooSys->getModel(); + sal_Int32 nDimCount = xCooSys->getDimension(); + bool bComplexCategoryAllowed = ChartTypeHelper::isSupportingComplexCategory( + AxisHelper::getChartTypeByIndex(xCooSys, 0)); + + for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) + { + bool bDateAxisAllowed = ChartTypeHelper::isSupportingDateAxis( + AxisHelper::getChartTypeByIndex(xCooSys, 0), nDimIndex); + + // Each dimension may have primary and secondary axes. + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex); + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= nMaxAxisIndex; ++nAxisIndex) + { + rtl::Reference xAxis = xCooSys->getAxisByDimension2(nDimIndex, nAxisIndex); + + if (!xAxis.is()) + continue; + + if (m_aAxisUsageList.find(xAxis) == m_aAxisUsageList.end()) + { + // Create axis usage object for this axis. + + chart2::ScaleData aSourceScale = xAxis->getScaleData(); + ExplicitCategoriesProvider* pCatProvider + = pVCooSys->getExplicitCategoriesProvider(); + if (nDimIndex == 0) + AxisHelper::checkDateAxis(aSourceScale, pCatProvider, bDateAxisAllowed); + + bool bHasComplexCat = pCatProvider && pCatProvider->hasComplexCategories() + && bComplexCategoryAllowed; + aSourceScale.ShiftedCategoryPosition + = isCategoryPositionShifted(aSourceScale, bHasComplexCat); + + m_aAxisUsageList[xAxis].aAutoScaling = ScaleAutomatism(aSourceScale, rNullDate); + } + + AxisUsage& rAxisUsage = m_aAxisUsageList[xAxis]; + rAxisUsage.addCoordinateSystem(pVCooSys.get(), nDimIndex, nAxisIndex); + } + } + } + + // Determine the highest axis index of all dimensions. + m_nMaxAxisIndex = 0; + for (const auto& pVCooSys : m_rVCooSysList) + { + uno::Reference xCooSys = pVCooSys->getModel(); + sal_Int32 nDimCount = xCooSys->getDimension(); + + for (sal_Int32 nDimIndex = 0; nDimIndex < nDimCount; ++nDimIndex) + { + for (auto& axisUsage : m_aAxisUsageList) + { + sal_Int32 nLocalMax = axisUsage.second.getMaxAxisIndexForDimension(nDimIndex); + if (m_nMaxAxisIndex < nLocalMax) + m_nMaxAxisIndex = nLocalMax; + } + } + } +} + +void SeriesPlotterContainer::setScalesFromCooSysToPlotter() +{ + //set scales to plotter to enable them to provide the preferred scene AspectRatio + for (const std::unique_ptr& aPlotter : m_aSeriesPlotterList) + { + VSeriesPlotter* pSeriesPlotter = aPlotter.get(); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::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 numberformats to plotter to enable them to display the data labels in the numberformat of the axis + for (const std::unique_ptr& aPlotter : m_aSeriesPlotterList) + { + VSeriesPlotter* pSeriesPlotter = aPlotter.get(); + VCoordinateSystem* pVCooSys + = SeriesPlotterContainer::getCooSysForPlotter(m_rVCooSysList, pSeriesPlotter); + if (pVCooSys) + { + AxesNumberFormats aAxesNumberFormats; + const rtl::Reference& 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 + { + rtl::Reference xAxisProp + = xCooSys->getAxisByDimension2(nDimensionIndex, nAxisIndex); + if (xAxisProp.is()) + { + sal_Int32 nNumberFormatKey(0); + if (xAxisProp->getPropertyValue(CHART_UNONAME_NUMFMT) + >>= nNumberFormatKey) + { + aAxesNumberFormats.setFormat(nNumberFormatKey, nDimensionIndex, + nAxisIndex); + } + else if (nDimensionIndex == 0) + { + //provide a default date format for date axis with own data + aAxesNumberFormats.setFormat(m_nDefaultDateNumberFormat, + nDimensionIndex, nAxisIndex); + } + } + } + catch (const lang::IndexOutOfBoundsException&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + } + } + } +} + +void SeriesPlotterContainer::updateScalesAndIncrementsOnAxes() +{ + for (auto& nC : m_rVCooSysList) + nC->updateScalesAndIncrementsOnAxes(); +} + +void SeriesPlotterContainer::doAutoScaling(ChartModel& rChartModel) +{ + if (m_aSeriesPlotterList.empty() || m_aAxisUsageList.empty()) + // We need these two containers populated to do auto-scaling. Bail out. + return; + + //iterate over the main scales first than secondary axis + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; ++nAxisIndex) + { + // - first do autoscale for all x and z scales (because they are treated independent) + for (auto & [ rAxis, rAxisUsage ] : m_aAxisUsageList) + { + (void)rAxis; + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 0, nAxisIndex); + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 2, nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement(aExplicitScale, + aExplicitIncrement); + + rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.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 (auto & [ rAxis, rAxisUsage ] : m_aAxisUsageList) + { + (void)rAxis; + rAxisUsage.prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAxisIndex); + + ExplicitScaleData aExplicitScale; + ExplicitIncrementData aExplicitIncrement; + rAxisUsage.aAutoScaling.calculateExplicitScaleAndIncrement(aExplicitScale, + aExplicitIncrement); + + rAxisUsage.setExplicitScaleAndIncrement(0, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScale, + aExplicitIncrement); + rAxisUsage.setExplicitScaleAndIncrement(2, nAxisIndex, aExplicitScale, + aExplicitIncrement); + } + } + AdaptScaleOfYAxisWithoutAttachedSeries(rChartModel); +} + +void SeriesPlotterContainer::AdaptScaleOfYAxisWithoutAttachedSeries(ChartModel& rModel) +{ + //issue #i80518# + for (sal_Int32 nAxisIndex = 0; nAxisIndex <= m_nMaxAxisIndex; nAxisIndex++) + { + for (auto & [ rAxis, rAxisUsage ] : m_aAxisUsageList) + { + (void)rAxis; + std::vector aVCooSysList_Y + = rAxisUsage.getCoordinateSystems(1, nAxisIndex); + if (aVCooSysList_Y.empty()) + continue; + + rtl::Reference xDiagram(rModel.getFirstChartDiagram()); + if (!xDiagram.is()) + continue; + + bool bSeriesAttachedToThisAxis = false; + sal_Int32 nAttachedAxisIndex = -1; + { + std::vector> aSeriesVector + = DiagramHelper::getDataSeriesFromDiagram(xDiagram); + for (auto const& series : aSeriesVector) + { + sal_Int32 nCurrentIndex = DataSeriesHelper::getAttachedAxisIndex(series); + if (nAxisIndex == nCurrentIndex) + { + bSeriesAttachedToThisAxis = true; + break; + } + else if (nAttachedAxisIndex < 0 || nAttachedAxisIndex > nCurrentIndex) + nAttachedAxisIndex = nCurrentIndex; + } + } + + if (bSeriesAttachedToThisAxis || nAttachedAxisIndex < 0) + continue; + + for (VCoordinateSystem* nC : aVCooSysList_Y) + { + nC->prepareAutomaticAxisScaling(rAxisUsage.aAutoScaling, 1, nAttachedAxisIndex); + + ExplicitScaleData aExplicitScaleSource + = nC->getExplicitScale(1, nAttachedAxisIndex); + ExplicitIncrementData aExplicitIncrementSource + = nC->getExplicitIncrement(1, nAttachedAxisIndex); + + ExplicitScaleData aExplicitScaleDest = nC->getExplicitScale(1, nAxisIndex); + ExplicitIncrementData aExplicitIncrementDest + = nC->getExplicitIncrement(1, nAxisIndex); + + aExplicitScaleDest.Orientation = aExplicitScaleSource.Orientation; + aExplicitScaleDest.Scaling = aExplicitScaleSource.Scaling; + aExplicitScaleDest.AxisType = aExplicitScaleSource.AxisType; + + aExplicitIncrementDest.BaseValue = aExplicitIncrementSource.BaseValue; + + ScaleData aScale(rAxisUsage.aAutoScaling.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.hasElements()) + bAutoMinorInterval + = !(aScale.IncrementData.SubIncrements[0].IntervalCount.hasValue()); + if (bAutoMinorInterval) + { + if (!aExplicitIncrementDest.SubIncrements.empty() + && !aExplicitIncrementSource.SubIncrements.empty()) + aExplicitIncrementDest.SubIncrements[0].IntervalCount + = aExplicitIncrementSource.SubIncrements[0].IntervalCount; + } + + nC->setExplicitScaleAndIncrement(1, nAxisIndex, aExplicitScaleDest, + aExplicitIncrementDest); + } + } + } + + if (!AxisHelper::isAxisPositioningEnabled()) + return; + + //correct origin for y main axis (the origin is where the other main axis crosses) + sal_Int32 nAxisIndex = 0; + sal_Int32 nDimensionIndex = 1; + for (auto & [ rAxis, rAxisUsage ] : m_aAxisUsageList) + { + (void)rAxis; + std::vector 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)); + + rtl::Reference xCooSys(aVCooSysList[nC]->getModel()); + rtl::Reference xAxis = xCooSys->getAxisByDimension2(nDimensionIndex, nAxisIndex); + rtl::Reference xCrossingMainAxis + = AxisHelper::getCrossingMainAxis(xAxis, xCooSys); + + if (xCrossingMainAxis.is()) + { + css::chart::ChartAxisPosition eCrossingMainAxisPos( + css::chart::ChartAxisPosition_ZERO); + xCrossingMainAxis->getPropertyValue("CrossoverPosition") >>= eCrossingMainAxisPos; + if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_VALUE) + { + double fValue = 0.0; + xCrossingMainAxis->getPropertyValue("CrossoverValue") >>= fValue; + aExplicitScale.Origin = fValue; + } + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_ZERO) + aExplicitScale.Origin = 0.0; + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_START) + aExplicitScale.Origin = aExplicitScale.Minimum; + else if (eCrossingMainAxisPos == css::chart::ChartAxisPosition_END) + aExplicitScale.Origin = aExplicitScale.Maximum; + } + + aVCooSysList[nC]->setExplicitScaleAndIncrement(nDimensionIndex, nAxisIndex, + aExplicitScale, aExplicitIncrement); + } + } +} + +drawing::Direction3D SeriesPlotterContainer::getPreferredAspectRatio() +{ + drawing::Direction3D aPreferredAspectRatio(1.0, 1.0, 1.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; + for (const std::unique_ptr& aPlotter : m_aSeriesPlotterList) + { + drawing::Direction3D aSingleRatio(aPlotter->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; +} + +} //end chart2 namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/SeriesPlotterContainer.hxx b/chart2/source/view/main/SeriesPlotterContainer.hxx new file mode 100644 index 000000000..e34d07a96 --- /dev/null +++ b/chart2/source/view/main/SeriesPlotterContainer.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "AxisUsage.hxx" + +namespace chart +{ +/** This class is a container of `SeriesPlotter` objects (such as `PieChart` + * instances). It is used for initializing coordinate systems, axes and scales + * of all series plotters which belongs to the container. + */ +class SeriesPlotterContainer +{ +public: + explicit SeriesPlotterContainer(std::vector>& rVCooSysList); + ~SeriesPlotterContainer(); + + /** It is used to set coordinate systems (`m_rVCooSysList`), this method + * is invoked by `ChartView::createShapes2D` before of + * `ChartView::impl_createDiagramAndContent`. + * Coordinate systems are retrieved through the `XCoordinateSystemContainer` + * interface implemented by a diagram object which is provided by the + * `ChartModel` object passed to the method (`rChartModel.getFirstDiagram()`). + * + * It is used for creating series plotters and appending them + * to `m_aSeriesPlotterList`. The created series plotters are initialized + * through data (number formats supplier, color scheme, data series), + * extracted from the chart model or the diagram objects. An exception is + * the explicit category provider that is retrieved through the + * `VCoordinateSystem` object used by the series plotter. + * + * It sets the minimum-maximum supplier for a coordinate system: + * this supplier is the series plotter itself which utilizes the given + * coordinate system. In fact `VSeriesPlotter` has `MinimumMaximumSupplier` + * as one of its base classes. + * Hence, for instance, a `PieChart`, which is a series plotter, is + * a `MinimumMaximumSupplier`, too. + */ + void initializeCooSysAndSeriesPlotter(ChartModel& rModel); + + /** This method is invoked by `ChartView::impl_createDiagramAndContent`. + * It iterates on every axis of every coordinate systems, and if the axis + * is not yet present in `m_aAxisUsageList` it creates a new `AxisUsage` + * object and initialize its `aAutoScaling` member to the `ScaleData` + * object of the current axis. + */ + void initAxisUsageList(const Date& rNullDate); + + /** + * Perform automatic axis scaling and determine the amount and spacing of + * increments. It assumes that the caller has determined the size of the + * largest axis label text object prior to calling this method. + * + * The new axis scaling data will be stored in the VCoordinateSystem + * objects. The label alignment direction for each axis will also get + * determined during this process, and stored in VAxis. + * + * This method is invoked by `ChartView::impl_createDiagramAndContent` + * soon after `initAxisUsageList`. + * It initializes explicit scale and increment objects for all coordinate + * systems in `m_rVCooSysList`. + * This action is achieved by iterating on the `m_aAxisUsageList` container, + * and performing 3 steps: + * 1- call `VCoordinateSystem::prepareAutomaticAxisScaling` for setting + * scaling parameters of the `aAutoScaling` member (a `ScaleAutomatism` + * object) for the current `AxisUsage` instance + * (see `VCoordinateSystem::prepareAutomaticAxisScaling`); + * 2- calculate the explicit scale and increment objects + * (see ScaleAutomatism::calculateExplicitScaleAndIncrement); + * 3- set the explicit scale and increment objects for each coordinate + * system. + */ + void doAutoScaling(ChartModel& rModel); + + /** + * After auto-scaling is performed, call this method to set the explicit + * scaling and increment data to all relevant VAxis objects. + */ + void updateScalesAndIncrementsOnAxes(); + + /** + * After auto-scaling is performed, call this method to set the explicit + * scaling data to all the plotters. + */ + void setScalesFromCooSysToPlotter(); + + void setNumberFormatsFromAxes(); + css::drawing::Direction3D getPreferredAspectRatio(); + + std::vector>& getSeriesPlotterList() + { + return m_aSeriesPlotterList; + } + std::vector>& getCooSysList() { return m_rVCooSysList; } + std::vector getLegendEntryProviderList(); + + void AdaptScaleOfYAxisWithoutAttachedSeries(ChartModel& rModel); + + bool isCategoryPositionShifted(const css::chart2::ScaleData& rSourceScale, + bool bHasComplexCategories); + + static VCoordinateSystem* + getCooSysForPlotter(const std::vector>& rVCooSysList, + MinimumAndMaximumSupplier* pMinimumAndMaximumSupplier); + static VCoordinateSystem* + addCooSysToList(std::vector>& rVCooSysList, + const rtl::Reference& xCooSys, ChartModel& rChartModel); + static VCoordinateSystem* + findInCooSysList(const std::vector>& rVCooSysList, + const rtl::Reference& xCooSys); + +private: + /** A vector of series plotters. + */ + std::vector> m_aSeriesPlotterList; + + /** A vector of coordinate systems. + */ + std::vector>& m_rVCooSysList; + + /** A map whose key is a `XAxis` interface and the related value is + * an object of `AxisUsage` type. + */ + std::map, AxisUsage> m_aAxisUsageList; + + /** + * Max axis index of all dimensions. Currently this can be either 0 or 1 + * since we only support primary and secondary axes per dimension. The + * value of 0 means all dimensions have only primary axis, while 1 means + * at least one dimension has a secondary axis. + */ + sal_Int32 m_nMaxAxisIndex; + + bool m_bChartTypeUsesShiftedCategoryPositionPerDefault; + sal_Int32 m_nDefaultDateNumberFormat; +}; + +} //end chart2 namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx new file mode 100644 index 000000000..7fddc5d01 --- /dev/null +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -0,0 +1,2551 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace chart +{ + +namespace +{ + +void lcl_addProperty(uno::Sequence & rPropertyNames, uno::Sequence & rPropertyValues, + OUString const & rName, uno::Any const & rAny) +{ + rPropertyNames.realloc(rPropertyNames.getLength() + 1); + rPropertyNames.getArray()[rPropertyNames.getLength() - 1] = rName; + + rPropertyValues.realloc(rPropertyValues.getLength() + 1); + rPropertyValues.getArray()[rPropertyValues.getLength() - 1] = rAny; +} + +css::drawing::PolyPolygonShape3D toPolyPolygonShape3D(const std::vector>& rPoints) +{ + css::drawing::PolyPolygonShape3D aUnoPoly; + aUnoPoly.SequenceX.realloc(rPoints.size()); + aUnoPoly.SequenceY.realloc(rPoints.size()); + aUnoPoly.SequenceZ.realloc(rPoints.size()); + for (std::size_t nPolygonIndex=0; nPolygonIndexrealloc(rPoints[nPolygonIndex].size()); + pOuterSequenceY->realloc(rPoints[nPolygonIndex].size()); + pOuterSequenceZ->realloc(rPoints[nPolygonIndex].size()); + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + for (std::size_t nPointIndex=0; nPointIndex ShapeFactory::getOrCreateChartRootShape( + const rtl::Reference& xDrawPage ) +{ + rtl::Reference xRet = ShapeFactory::getChartRootShape(xDrawPage); + if (xRet.is()) + return xRet; + + // Create a new root shape and set it to the bottom of the page. The root + // shape is identified by having the name com.sun.star.chart2.shapes. + rtl::Reference xShapeGroup = new SvxShapeGroup(nullptr, nullptr); + xShapeGroup->setShapeKind(SdrObjKind::Group); + // cast to resolve ambiguity in converting to XShape + xDrawPage->addBottom(static_cast(xShapeGroup.get())); + + setShapeName(xShapeGroup, "com.sun.star.chart2.shapes"); + xShapeGroup->setSize(awt::Size(0,0)); + + return xShapeGroup; +} + +void ShapeFactory::setPageSize(const rtl::Reference&, const awt::Size&) {} + +// diverse tools::PolyPolygon create methods + +static uno::Any createPolyPolygon_Cube( + const drawing::Direction3D& rSize, double fRoundedEdge, bool bRounded ) +{ + OSL_PRECOND(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 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; + + 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, cppu::UnoType::get()); +} + +static uno::Any createPolyPolygon_Cylinder( + double fHeight + , double fRadius + , sal_Int32& nVerticalSegmentCount ) +{ + //fHeight may be negative + OSL_PRECOND(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, cppu::UnoType::get()); +} + +static uno::Any createPolyPolygon_Cone( double fHeight, double fRadius, double fTopHeight + , sal_Int32& nVerticalSegmentCount ) +{ + OSL_PRECOND(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, cppu::UnoType::get()); +} + +// methods for 3D shape creation + +rtl::Reference + ShapeFactory::createCube( + const rtl::Reference& 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 nullptr; + if( bRounded ) + { + try + { + if( xSourceProp.is() ) + { + drawing::LineStyle aLineStyle; + xSourceProp->getPropertyValue( "BorderStyle" ) >>= aLineStyle; + if( aLineStyle == drawing::LineStyle_SOLID ) + bRounded = false; + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + rtl::Reference xShape = impl_createCube( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree, bRounded ); + if( xSourceProp.is()) + PropertyMapper::setMappedProperties( *xShape, xSourceProp, rPropertyNameMap ); + return xShape; +} + +rtl::Reference + ShapeFactory::impl_createCube( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree + , bool bRounded ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + rtl::Reference xShape = new Svx3DExtrudeObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Extrusion); + xTarget->addShape(*xShape); + + //set properties + try + { + //depth + double fDepth = rSize.DirectionZ; + if (fDepth<0) + fDepth*=-1.0; + + //PercentDiagonal + sal_Int16 nPercentDiagonal = bRounded ? 3 : 0; + + //Matrix for position + basegfx::B3DHomMatrix aHomMatrix; + if (nRotateZAngleHundredthDegree != 0) + aHomMatrix.rotate(0.0, 0.0, -basegfx::deg2rad<100>(nRotateZAngleHundredthDegree)); + aHomMatrix.translate(rPosition.PositionX, rPosition.PositionY, + rPosition.PositionZ - (fDepth / 2.0)); + + uno::Sequence aPropertyNames { + UNO_NAME_3D_EXTRUDE_DEPTH, + UNO_NAME_3D_PERCENT_DIAGONAL, + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_TRANSFORM_MATRIX, + }; + + uno::Sequence aPropertyValues { + uno::Any(sal_Int32(fDepth)), // Depth + uno::Any(nPercentDiagonal), // PercentDiagonal + createPolyPolygon_Cube(rSize, double(nPercentDiagonal) / 200.0, bRounded), + uno::Any(B3DHomMatrixToHomogenMatrix(aHomMatrix)) + }; + + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createCylinder( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( + xTarget, rPosition, rSize, 0.0, nRotateZAngleHundredthDegree, true ); +} + +rtl::Reference + ShapeFactory::createPyramid( + const rtl::Reference& 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 nullptr; + + rtl::Reference xGroup( ShapeFactory::createGroup3D( xTarget ) ); + + 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 xGroup; +} + +rtl::Reference + ShapeFactory::createCone( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree ) +{ + return impl_createConeOrCylinder( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree, false ); +} + +rtl::Reference + ShapeFactory::impl_createConeOrCylinder( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize + , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree + , bool bCylinder ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + rtl::Reference xShape = new Svx3DLatheObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Lathe); + xTarget->addShape(*xShape); + + double fWidth = rSize.DirectionX/2.0; //The depth will be corrected 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 + try + { + //Polygon + sal_Int32 nVerticalSegmentCount = 0; + uno::Any aPPolygon = bCylinder + ? createPolyPolygon_Cylinder(fHeight, fRadius, nVerticalSegmentCount) + : createPolyPolygon_Cone(fHeight, fRadius, fTopHeight, nVerticalSegmentCount); + + //Matrix for position + basegfx::B3DHomMatrix aHomMatrix; + if (nRotateZAngleHundredthDegree != 0) + aHomMatrix.rotate(0.0,0.0,-basegfx::deg2rad<100>(nRotateZAngleHundredthDegree)); + //stretch the symmetric objects to given depth + aHomMatrix.scale(1.0,1.0,rSize.DirectionZ/rSize.DirectionX); + aHomMatrix.translate(rPosition.PositionX, rPosition.PositionY, rPosition.PositionZ); + + uno::Sequence aPropertyNames{ + UNO_NAME_3D_PERCENT_DIAGONAL, + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_TRANSFORM_MATRIX, + UNO_NAME_3D_HORZ_SEGS, + UNO_NAME_3D_VERT_SEGS, + UNO_NAME_3D_REDUCED_LINE_GEOMETRY + }; + + uno::Sequence aPropertyValues { + uno::Any(sal_Int16(5)), // PercentDiagonal + aPPolygon, // Polygon + uno::Any(B3DHomMatrixToHomogenMatrix(aHomMatrix)), // Matrix + uno::Any(CHART_3DOBJECT_SEGMENTCOUNT), // Horizontal Segments + uno::Any(nVerticalSegmentCount), // Vertical Segments + uno::Any(true) // Reduced lines + }; + + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +static void appendAndCloseBezierCoords( drawing::PolyPolygonBezierCoords& rReturn, const drawing::PolyPolygonBezierCoords& rAdd, bool bAppendInverse ) +{ + if(!rAdd.Coordinates.hasElements()) + return; + sal_Int32 nAddCount = rAdd.Coordinates[0].getLength(); + if(!nAddCount) + return; + + sal_Int32 nOldCount = rReturn.Coordinates[0].getLength(); + + auto pCoordinates = rReturn.Coordinates.getArray(); + pCoordinates[0].realloc(nOldCount + nAddCount + 1); + auto pCoordinates0 = pCoordinates[0].getArray(); + auto pFlags = rReturn.Flags.getArray(); + pFlags[0].realloc(nOldCount+nAddCount+1); + auto pFlags0 = pFlags[0].getArray(); + + for(sal_Int32 nN=0;nN( fWidthAngleRadian/fAngleSubdivisionRadian ); + if( fWidthAngleRadian > fAngleSubdivisionRadian*nSegmentCount ) + nSegmentCount++; + + double fFirstSegmentAngle = fAngleSubdivisionRadian; + double fLastSegmentAngle = fAngleSubdivisionRadian; + if(nSegmentCount==1) + { + fFirstSegmentAngle = fWidthAngleRadian; + fLastSegmentAngle = 0.0; + } + else + { + double fFirstAngleOnSubDivision = (static_cast(fStartAngleRadian/fAngleSubdivisionRadian)+1)*fAngleSubdivisionRadian; + if( !::rtl::math::approxEqual( fStartAngleRadian, fFirstAngleOnSubDivision ) ) + fFirstSegmentAngle = fFirstAngleOnSubDivision-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 + + drawing::PointSequence aPoints(nPointCount); + auto pPoints = aPoints.getArray(); + drawing::FlagSequence aFlags(nPointCount); + auto pFlags = aFlags.getArray(); + + //!! 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; + + sal_Int32 nPoint=0; + double fCurrentRotateAngle = fStartAngleRadian; + for(sal_Int32 nSegment=0; nSegment( P0.getX()); + pPoints[nPoint].Y = static_cast< sal_Int32 >( P0.getY()); + pFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + + pPoints[nPoint].X = static_cast< sal_Int32 >( P1.getX()); + pPoints[nPoint].Y = static_cast< sal_Int32 >( P1.getY()); + pFlags[nPoint++] = drawing::PolygonFlags_CONTROL; + + pPoints[nPoint].X = static_cast< sal_Int32 >( P2.getX()); + pPoints[nPoint].Y = static_cast< sal_Int32 >( P2.getY()); + pFlags [nPoint++] = drawing::PolygonFlags_CONTROL; + + if(nSegment==(nSegmentCount-1)) + { + pPoints[nPoint].X = static_cast< sal_Int32 >( P3.getX()); + pPoints[nPoint].Y = static_cast< sal_Int32 >( P3.getY()); + pFlags [nPoint++] = drawing::PolygonFlags_NORMAL; + } + } + + aReturn.Coordinates = { aPoints }; + aReturn.Flags = { aFlags }; + + return aReturn; +} + +static drawing::PolyPolygonBezierCoords getRingBezierCoords( + double fUnitCircleInnerRadius + , double fUnitCircleOuterRadius + , double fStartAngleRadian, double fWidthAngleRadian + , const ::basegfx::B2DHomMatrix& aTransformationFromUnitCircle + , const double fAngleSubdivisionRadian ) +{ + drawing::PolyPolygonBezierCoords aReturn; + + drawing::PolyPolygonBezierCoords aOuterArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleOuterRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + aReturn.Coordinates = { aOuterArc.Coordinates[0] }; + aReturn.Flags = { aOuterArc.Flags[0] }; + + drawing::PolyPolygonBezierCoords aInnerArc = getCircularArcBezierCoords( + fStartAngleRadian, fWidthAngleRadian, fUnitCircleInnerRadius, aTransformationFromUnitCircle, fAngleSubdivisionRadian ); + appendAndCloseBezierCoords( aReturn, aInnerArc, true ); + + return aReturn; +} + +rtl::Reference + ShapeFactory::createPieSegment2D( + const rtl::Reference& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene ) +{ + if( !xTarget.is() ) + return nullptr; + + // tdf#123504: both 0 and 360 are valid and different values here! + while (fUnitCircleWidthAngleDegree > 360) + fUnitCircleWidthAngleDegree -= 360.0; + while (fUnitCircleWidthAngleDegree < 0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::PathFill); // aka ClosedBezierShape + xTarget->addShape(*xShape); //need to add the shape before setting of properties + + //set properties + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = M_PI/10.0; + + drawing::PolyPolygonBezierCoords aCoords + = getRingBezierCoords(fUnitCircleInnerRadius, fUnitCircleOuterRadius, + basegfx::deg2rad(fUnitCircleStartAngleDegree), + basegfx::deg2rad(fUnitCircleWidthAngleDegree), + aTransformationFromUnitCircle, fAngleSubdivisionRadian); + + xShape->SvxShape::setPropertyValue( "PolyPolygonBezier", uno::Any( aCoords ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + return xShape; +} + +rtl::Reference + ShapeFactory::createPieSegment( + const rtl::Reference& xTarget + , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree + , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius + , const drawing::Direction3D& rOffset + , const drawing::HomogenMatrix& rUnitCircleToScene + , double fDepth ) +{ + if( !xTarget.is() ) + return nullptr; + + // tdf#123504: both 0 and 360 are valid and different values here! + while (fUnitCircleWidthAngleDegree > 360) + fUnitCircleWidthAngleDegree -= 360.0; + while (fUnitCircleWidthAngleDegree < 0) + fUnitCircleWidthAngleDegree += 360.0; + + //create shape + rtl::Reference xShape = new Svx3DExtrudeObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Extrusion); + xTarget->addShape(*xShape); //need to add the shape before setting of properties + + //set properties + try + { + ::basegfx::B2DHomMatrix aTransformationFromUnitCircle( IgnoreZ( HomogenMatrixToB3DHomMatrix(rUnitCircleToScene) ) ); + aTransformationFromUnitCircle.translate(rOffset.DirectionX,rOffset.DirectionY); + + const double fAngleSubdivisionRadian = M_PI/32.0; + + drawing::PolyPolygonBezierCoords aCoords + = getRingBezierCoords(fUnitCircleInnerRadius, fUnitCircleOuterRadius, + basegfx::deg2rad(fUnitCircleStartAngleDegree), + basegfx::deg2rad(fUnitCircleWidthAngleDegree), + aTransformationFromUnitCircle, fAngleSubdivisionRadian); + + //depth + xShape->setPropertyValue( UNO_NAME_3D_EXTRUDE_DEPTH + , uno::Any(static_cast(fDepth)) ); + + //PercentDiagonal + xShape->setPropertyValue( UNO_NAME_3D_PERCENT_DIAGONAL + , uno::Any( sal_Int16(0) ) ); + + //Polygon + drawing::PolyPolygonShape3D aPoly( BezierToPoly(aCoords) ); + ShapeFactory::closePolygon( aPoly ); + xShape->setPropertyValue( UNO_NAME_3D_POLYPOLYGON3D + , uno::Any( aPoly ) ); + + //DoubleSided + xShape->setPropertyValue( UNO_NAME_3D_DOUBLE_SIDED + , uno::Any( true ) ); + + //Reduced lines + xShape->setPropertyValue( UNO_NAME_3D_REDUCED_LINE_GEOMETRY + , uno::Any( true ) ); + + //TextureProjectionMode + xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_Y + , uno::Any( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + + //TextureProjectionMode + xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_X + , uno::Any( drawing::TextureProjectionMode_PARALLEL ) ); + xShape->setPropertyValue( UNO_NAME_3D_TEXTURE_PROJ_Y + , uno::Any( drawing::TextureProjectionMode_OBJECTSPECIFIC ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createStripe( const rtl::Reference& xTarget + , const Stripe& rStripe + , const uno::Reference< beans::XPropertySet >& xSourceProp + , const tPropertyNameMap& rPropertyNameMap + , bool bDoubleSided + , short nRotatedTexture + , bool bFlatNormals ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + rtl::Reference xShape = new Svx3DPolygonObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Polygon); + xTarget->addShape(*xShape); + + //set properties + try + { + uno::Sequence aPropertyNames{ + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_TEXTUREPOLYGON3D, + UNO_NAME_3D_NORMALSPOLYGON3D, + UNO_NAME_3D_LINEONLY, + UNO_NAME_3D_DOUBLE_SIDED + }; + + uno::Sequence aPropertyValues { + rStripe.getPolyPolygonShape3D(), // Polygon + Stripe::getTexturePolygon(nRotatedTexture), // TexturePolygon + rStripe.getNormalsPolygon(), // Normals Polygon + uno::Any(false), // LineOnly + uno::Any(bDoubleSided) // DoubleSided + }; + + //NormalsKind + if (bFlatNormals) + lcl_addProperty(aPropertyNames, aPropertyValues, + UNO_NAME_3D_NORMALS_KIND, uno::Any(drawing::NormalsKind_FLAT)); + + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + + if (xSourceProp) + { + PropertyMapper::setMappedProperties(*xShape, xSourceProp, rPropertyNameMap); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createArea3D( const rtl::Reference& xTarget + , const std::vector>& rPolyPolygon + , double fDepth ) +{ + if( !xTarget.is() ) + return nullptr; + + if( rPolyPolygon.empty() ) + return nullptr; + + //create shape + rtl::Reference xShape = new Svx3DExtrudeObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Extrusion); + xTarget->addShape(*xShape); + + css::drawing::PolyPolygonShape3D aUnoPolyPolygon = toPolyPolygonShape3D(rPolyPolygon); + + //set properties + try + { + uno::Sequence aPropertyNames{ + UNO_NAME_3D_EXTRUDE_DEPTH, + UNO_NAME_3D_PERCENT_DIAGONAL, + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_DOUBLE_SIDED, + }; + + uno::Sequence aPropertyValues { + uno::Any(sal_Int32(fDepth)), // depth + uno::Any(sal_Int16(0)), // PercentDiagonal + uno::Any(aUnoPolyPolygon), // Polygon + uno::Any(true) // DoubleSided + }; + + //the z component of the polygon is now ignored by the drawing layer, + //so we need to translate the object via transformation matrix + + //Matrix for position + if (!rPolyPolygon.empty() && !rPolyPolygon[0].empty()) + { + basegfx::B3DHomMatrix aM; + aM.translate(0, 0, rPolyPolygon[0][0].PositionZ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + lcl_addProperty(aPropertyNames, aPropertyValues, UNO_NAME_3D_TRANSFORM_MATRIX, uno::Any(aHM)); + } + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createArea2D( const rtl::Reference& xTarget + , const std::vector>& rPolyPolygon ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + SdrPathObj* pPath = new SdrPathObj(xTarget->GetSdrObject()->getSdrModelFromSdrObject(), SdrObjKind::Polygon); + xTarget->GetSdrObject()->GetSubList()->InsertObject(pPath); + + //set properties + try + { + // Polygon + basegfx::B2DPolyPolygon aNewPolyPolygon( PolyToB2DPolyPolygon(rPolyPolygon) ); + // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm + pPath->ForceMetricToItemPoolMetric(aNewPolyPolygon); + pPath->SetPathPoly(aNewPolyPolygon); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return static_cast(pPath->getUnoShape().get()); +} + +static drawing::PointSequenceSequence createPolyPolygon_Symbol( const drawing::Position3D& rPos + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol ) +{ + if(nStandardSymbol<0) + nStandardSymbol*=-1; + nStandardSymbol = nStandardSymbol%ShapeFactory::getSymbolCount(); + SymbolEnum eSymbolType=static_cast(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 + + const sal_Int32 nQuarterCount = 35; // points inside a quadrant, used in case circle + + 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: + case Symbol_HorizontalBar: + case Symbol_VerticalBar: + nPointCount = 5; + break; + case Symbol_X: + nPointCount = 13; + break; + case Symbol_Plus: + nPointCount = 13; + break; + case Symbol_Star: + nPointCount = 9; + break; + case Symbol_Asterisk: + nPointCount = 19; + break; + case Symbol_Circle: + nPointCount = 5 + 4 * nQuarterCount; + break; + default: + break; + } + + drawing::PointSequenceSequence aPP; + + aPP.realloc(1); + + uno::Sequence* pOuterSequence = aPP.getArray(); + + pOuterSequence->realloc(nPointCount); + + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + auto toPoint = [](double x, double y) -> awt::Point + { + return { static_cast(x), static_cast(y) }; + }; + switch(eSymbolType) + { + case Symbol_Square: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + break; + } + case Symbol_UpArrow: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + break; + } + case Symbol_DownArrow: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + break; + } + case Symbol_RightArrow: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + break; + } + case Symbol_LeftArrow: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY ); + break; + } + case Symbol_Bowtie: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + break; + } + case Symbol_Sandglass: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + break; + } + case Symbol_Diamond: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY ); + break; + } + case Symbol_HorizontalBar: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-0.2*fHeightH ); + break; + } + case Symbol_VerticalBar: + { + *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-fHeightH ); + + break; + } + case Symbol_Circle: + { + double fOmega = 1.5707963267948966192 / (nQuarterCount + 1.0); + // one point in the middle of each edge to get full size bounding rectangle + *pInnerSequence++ = toPoint( fX + fWidthH, fY ); + // 0 to PI/2 + for (sal_Int32 i = 1; i <= nQuarterCount; ++i) + { + *pInnerSequence++ = toPoint( fX + fWidthH * cos( i * fOmega ), fY - fHeightH * sin( i * fOmega ) ); + } + // PI/2 to PI + *pInnerSequence++ = toPoint( fX, fY - fHeightH ); + for (sal_Int32 i = 1; i <= nQuarterCount; ++i) + { + *pInnerSequence++ = toPoint( fX - fWidthH * sin( i * fOmega), fY - fHeightH * cos( i * fOmega) ); + } + // PI to 3/2*PI + *pInnerSequence++ = toPoint( fX - fWidthH, fY ); + for (sal_Int32 i = 1; i <= nQuarterCount; ++i) + { + *pInnerSequence++ = toPoint( fX - fWidthH * cos( i * fOmega), fY + fHeightH * sin( i * fOmega) ); + } + // 3/2*PI to 2*PI + *pInnerSequence++ = toPoint( fX, fY + fHeightH ); + for (sal_Int32 i = 1; i <= nQuarterCount; ++i) + { + *pInnerSequence++ = toPoint( fX + fWidthH * sin(i * fOmega), fY + fHeightH * cos(i * fOmega) ); + } + // close polygon + *pInnerSequence++ = toPoint( fX + fWidthH, fY ); + break; + } + case Symbol_Star: + { + *pInnerSequence++ = toPoint( fX, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY-0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX+0.2*fWidthH, fY+0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY+0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY ); + + *pInnerSequence++ = toPoint( fX-0.2*fWidthH, fY-0.2*fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY-fHeightH ); + break; + } + case Symbol_X: + { + const double fScaleX = fWidthH / 128.0; + const double fScaleY = fHeightH / 128.0; + const double fSmall = sqrt(200.0); + const double fLarge = 128.0 - fSmall; + + *pInnerSequence++ = toPoint( fX, fY - fScaleY * fSmall ); + + *pInnerSequence++ = toPoint( fX - fScaleX * fLarge, fY - fHeightH ); + + *pInnerSequence++ = toPoint( fX - fWidthH, fY - fScaleY * fLarge ); + + *pInnerSequence++ = toPoint( fX - fScaleX * fSmall, fY ); + + *pInnerSequence++ = toPoint( fX - fWidthH, fY + fScaleY * fLarge ); + + *pInnerSequence++ = toPoint( fX - fScaleX * fLarge, fY + fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY + fScaleY * fSmall ); + + *pInnerSequence++ = toPoint( fX + fScaleX * fLarge, fY + fHeightH ); + + *pInnerSequence++ = toPoint( fX + fWidthH, fY + fScaleY * fLarge ); + + *pInnerSequence++ = toPoint( fX + fScaleX * fSmall, fY ); + + *pInnerSequence++ = toPoint( fX + fWidthH, fY - fScaleY * fLarge ); + + *pInnerSequence++ = toPoint( fX + fScaleX * fLarge, fY - fHeightH ); + + *pInnerSequence++ = toPoint( fX, fY - fScaleY * fSmall ); + break; + + } + case Symbol_Plus: + { + const double fScaleX = fWidthH / 128.0; + const double fScaleY = fHeightH / 128.0; + const double fHalf = 10.0; //half line width on 256 size square + const double fdX = fScaleX * fHalf; + const double fdY = fScaleY * fHalf; + + *pInnerSequence++ = toPoint( fX-fdX, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fdX, fY-fdY ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fdY ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fdY ); + + *pInnerSequence++ = toPoint( fX-fdX, fY+fdY ); + + *pInnerSequence++ = toPoint( fX-fdX, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fdX, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fdX, fY+fdY ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fdY ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fdY ); + + *pInnerSequence++ = toPoint( fX+fdX, fY-fdY ); + + *pInnerSequence++ = toPoint( fX+fdY, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fdX, fY-fHeightH ); + break; + + } + case Symbol_Asterisk: + { + const double fHalf = 10.0; // half line width on 256 size square + const double fTwoY = fHalf * sqrt(3.0); + const double fFourY = (128.0 - 2.0 * fHalf ) / sqrt(3.0); + const double fThreeX = 128.0 - fHalf; + const double fThreeY = fHalf * sqrt(3.0) + fFourY; + const double fFiveX = 2.0 * fHalf; + + const double fScaleX = fWidthH / 128.0; + const double fScaleY = fHeightH / 128.0; + + //1 + *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fHeightH ); + //2 + *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fScaleY * fTwoY ); + //3 + *pInnerSequence++ = toPoint( fX-fScaleX * fThreeX, fY-fScaleY * fThreeY ); + //4 + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fScaleY * fFourY ); + //5 + *pInnerSequence++ = toPoint( fX-fScaleX * fFiveX, fY ); + //6 as 4 + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fScaleY * fFourY ); + //7 as 3 + *pInnerSequence++ = toPoint( fX-fScaleX * fThreeX, fY+fScaleY * fThreeY ); + //8 as 2 + *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY+fScaleY * fTwoY ); + //9 as 1 + *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY+fHeightH ); + //10 as 1 + *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY+fHeightH ); + //11 as 2 + *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY+fScaleY * fTwoY ); + //12 as 3 + *pInnerSequence++ = toPoint( fX+fScaleX * fThreeX, fY+fScaleY * fThreeY ); + //13 as 4 + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fScaleY * fFourY ); + //14 as 5 + *pInnerSequence++ = toPoint( fX+fScaleX * fFiveX, fY ); + //15 as 4 + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fScaleY * fFourY ); + //16 as 3 + *pInnerSequence++ = toPoint( fX+fScaleX * fThreeX, fY-fScaleY * fThreeY ); + //17 as 2 + *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY-fScaleY * fTwoY ); + // 18 as 1 + *pInnerSequence++ = toPoint( fX+fScaleX * fHalf, fY-fHeightH ); + // 19 = 1, closing + *pInnerSequence++ = toPoint( fX-fScaleX * fHalf, fY-fHeightH ); + break; + } + default: //case Symbol_Square: + { + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY+fHeightH ); + + *pInnerSequence++ = toPoint( fX+fWidthH, fY-fHeightH ); + + *pInnerSequence++ = toPoint( fX-fWidthH, fY-fHeightH ); + break; + } + } + + return aPP; +} + +rtl::Reference + ShapeFactory::createSymbol2D( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , sal_Int32 nStandardSymbol + , sal_Int32 nBorderColor + , sal_Int32 nFillColor ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::Polygon); + xTarget->addShape(*xShape); + + //set properties + try + { + drawing::PointSequenceSequence aPoints = + createPolyPolygon_Symbol( rPosition, rSize, nStandardSymbol ); + + //Polygon + xShape->SvxShape::setPropertyValue( UNO_NAME_POLYPOLYGON + , uno::Any( aPoints ) ); + + //LineColor + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECOLOR + , uno::Any( nBorderColor ) ); + + //FillColor + xShape->SvxShape::setPropertyValue( UNO_NAME_FILLCOLOR + , uno::Any( nFillColor ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createGraphic2D( + const rtl::Reference& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize + , const uno::Reference< graphic::XGraphic >& xGraphic ) +{ + if( !xTarget.is() || !xGraphic.is() ) + return nullptr; + + // @todo: change this to a rectangle shape with a fill bitmap for + // performance reasons (ask AW, said CL) + + //create shape + rtl::Reference xShape = new SvxGraphicObject(nullptr); + xShape->setShapeKind(SdrObjKind::Graphic); + xTarget->addShape(*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 & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + try + { + xShape->SvxShape::setPropertyValue( "Graphic", uno::Any( xGraphic )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference< SvxShapeGroup > + ShapeFactory::createGroup2D( const rtl::Reference& xTarget + , const OUString& aName ) +{ + if( !xTarget.is() ) + return nullptr; + try + { + //create and add to target + rtl::Reference xShapeGroup = new SvxShapeGroup(nullptr, nullptr); + xShapeGroup->setShapeKind(SdrObjKind::Group); + // cast to resolve ambiguity in converting to XShape + xTarget->addShape(*xShapeGroup); + + //set name + if(!aName.isEmpty()) + setShapeName( xShapeGroup, aName ); + + {//workaround + //need this null size as otherwise empty group shapes where painted with a gray border + xShapeGroup->setSize(awt::Size(0,0)); + } + + return xShapeGroup; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return nullptr; +} + +rtl::Reference< SvxShapeGroup > + ShapeFactory::createGroup2D( const rtl::Reference& xTarget + , const OUString& aName ) +{ + if( !xTarget.is() ) + return nullptr; + try + { + //create and add to target + rtl::Reference xShapeGroup = new SvxShapeGroup(nullptr, nullptr); + xShapeGroup->setShapeKind(SdrObjKind::Group); + // cast to resolve ambiguity in converting to XShape + xTarget->add(static_cast(xShapeGroup.get())); + + //set name + if(!aName.isEmpty()) + setShapeName( xShapeGroup, aName ); + + {//workaround + //need this null size as otherwise empty group shapes where painted with a gray border + xShapeGroup->setSize(awt::Size(0,0)); + } + + return xShapeGroup; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return nullptr; +} + +rtl::Reference + ShapeFactory::createGroup3D( const rtl::Reference& xTarget + , const OUString& aName ) +{ + if( !xTarget.is() ) + return nullptr; + try + { + //create shape + rtl::Reference xShape = new Svx3DSceneObject(nullptr, nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Scene); + xTarget->addShape(*xShape); + + //it is necessary to set the transform matrix to initialize the scene properly + //otherwise all objects which are placed into this Group will not be visible + //the following should be unnecessary after the bug is fixed + //set properties + try + { + ::basegfx::B3DHomMatrix aM; + xShape->SvxShape::setPropertyValue( UNO_NAME_3D_TRANSFORM_MATRIX + , uno::Any(B3DHomMatrixToHomogenMatrix(aM)) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //set name + if(!aName.isEmpty()) + setShapeName( xShape , aName ); + + //return + return xShape; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return nullptr; +} + +rtl::Reference + ShapeFactory::createCircle2D( const rtl::Reference& xTarget + , const drawing::Position3D& rPosition + , const drawing::Direction3D& rSize ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + rtl::Reference xShape = new SvxShapeCircle(nullptr); + xShape->setShapeKind(SdrObjKind::CircleOrEllipse); + xTarget->addShape(*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 & ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //set properties + try + { + xShape->SvxShape::setPropertyValue( UNO_NAME_CIRCKIND, uno::Any( drawing::CircleKind_FULL ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createCircle( const rtl::Reference& xTarget + , const awt::Size& rSize + , const awt::Point& rPosition ) +{ + rtl::Reference xShape = new SvxShapeCircle(nullptr); + xShape->setShapeKind(SdrObjKind::CircleOrEllipse); + xTarget->addShape(*xShape); + xShape->setSize( rSize ); + xShape->setPosition( rPosition ); + + return xShape; +} + +rtl::Reference + ShapeFactory::createLine3D( const rtl::Reference& xTarget + , const std::vector>& rPoints + , const VLineProperties& rLineProperties ) +{ + if( !xTarget.is() ) + return nullptr; + + if(rPoints.empty()) + return nullptr; + + //create shape + rtl::Reference xShape = new Svx3DPolygonObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Polygon); + xTarget->addShape(*xShape); + + css::drawing::PolyPolygonShape3D aUnoPoly = toPolyPolygonShape3D(rPoints); + + //set properties + try + { + uno::Sequence aPropertyNames { + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_LINEONLY + }; + + uno::Sequence aPropertyValues { + uno::Any(aUnoPoly), // Polygon + uno::Any(true) // LineOnly + }; + + //Transparency + if(rLineProperties.Transparence.hasValue()) + { + lcl_addProperty(aPropertyNames, aPropertyValues, + UNO_NAME_LINETRANSPARENCE, + rLineProperties.Transparence); + } + + //LineStyle + if(rLineProperties.LineStyle.hasValue()) + { + lcl_addProperty(aPropertyNames, aPropertyValues, + UNO_NAME_LINESTYLE, + rLineProperties.LineStyle); + } + + //LineWidth + if(rLineProperties.Width.hasValue()) + { + lcl_addProperty(aPropertyNames, aPropertyValues, + UNO_NAME_LINEWIDTH, + rLineProperties.Width); + } + + //LineColor + if(rLineProperties.Color.hasValue()) + { + lcl_addProperty(aPropertyNames, aPropertyValues, + UNO_NAME_LINECOLOR, + rLineProperties.Color); + } + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createLine2D( const rtl::Reference& xTarget + , const drawing::PointSequenceSequence& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return nullptr; + + if(!rPoints.hasElements()) + return nullptr; + + //create shape + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::PolyLine); + xTarget->addShape(*xShape); + + //set properties + try + { + //Polygon + xShape->SvxShape::setPropertyValue( UNO_NAME_POLYPOLYGON + , uno::Any( rPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINETRANSPARENCE + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINESTYLE + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINEWIDTH + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECOLOR + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xShape->SvxShape::setPropertyValue( "LineDashName" + , pLineProperties->DashName ); + + //LineCap + if(pLineProperties->LineCap.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECAP + , pLineProperties->LineCap ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createLine2D( const rtl::Reference& xTarget + , const std::vector>& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return nullptr; + + if(rPoints.empty()) + return nullptr; + + //create shape + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::PolyLine); + xTarget->addShape(*xShape); + + drawing::PointSequenceSequence aAnyPoints = PolyToPointSequence(rPoints); + + //set properties + try + { + //Polygon + xShape->SvxShape::setPropertyValue( UNO_NAME_POLYPOLYGON + , uno::Any( aAnyPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINETRANSPARENCE + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINESTYLE + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINEWIDTH + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECOLOR + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xShape->SvxShape::setPropertyValue( "LineDashName" + , pLineProperties->DashName ); + + //LineCap + if(pLineProperties->LineCap.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECAP + , pLineProperties->LineCap ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createLine ( const rtl::Reference& xTarget, + const awt::Size& rSize, const awt::Point& rPosition ) +{ + //create shape + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::Line); + xTarget->addShape(*xShape); + xShape->setSize( rSize ); + xShape->setPosition( rPosition ); + + return xShape; +} + +rtl::Reference ShapeFactory::createInvisibleRectangle( + const rtl::Reference& xTarget + , const awt::Size& rSize ) +{ + try + { + if(!xTarget.is()) + return nullptr; + + rtl::Reference xShape = new SvxShapeRect(nullptr); + xShape->setShapeKind(SdrObjKind::Rectangle); + xTarget->addShape( *xShape ); + ShapeFactory::makeShapeInvisible( xShape ); + xShape->setSize( rSize ); + return xShape; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return nullptr; +} + +rtl::Reference ShapeFactory::createRectangle( + const rtl::Reference& xTarget, + const awt::Size& rSize, + const awt::Point& rPosition, + const tNameSequence& rPropNames, + const tAnySequence& rPropValues, + StackPosition ePos ) +{ + rtl::Reference xShape = new SvxShapeRect(nullptr); + xShape->setShapeKind(SdrObjKind::Rectangle); + if (ePos == StackPosition::Bottom) + { + uno::Reference xTarget2(static_cast(xTarget.get()), uno::UNO_QUERY); + if (xTarget2.is()) + xTarget2->addBottom(xShape); + } + else + xTarget->addShape(*xShape); + + xShape->setPosition( rPosition ); + xShape->setSize( rSize ); + PropertyMapper::setMultiProperties( rPropNames, rPropValues, *xShape ); + + return xShape; +} + +rtl::Reference + ShapeFactory::createRectangle( + const rtl::Reference& xTarget ) +{ + rtl::Reference xShape = new SvxShapeRect(nullptr); + xShape->setShapeKind(SdrObjKind::Rectangle); + xTarget->addShape( *xShape ); + + return xShape; +} + +rtl::Reference + ShapeFactory::createText( const rtl::Reference& xTarget + , const OUString& rText + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const uno::Any& rATransformation ) +{ + if( !xTarget.is() ) + return nullptr; + + if(rText.isEmpty()) + return nullptr; + + //create shape and add to page + rtl::Reference xShape = new SvxShapeText(nullptr); + xShape->setShapeKind(SdrObjKind::Text); + xTarget->addShape(*xShape); + + //set text + xShape->setString( rText ); + + //set properties + PropertyMapper::setMultiProperties( rPropNames, rPropValues, *xShape ); + + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + try + { + if (rATransformation.hasValue()) + xShape->SvxShape::setPropertyValue( "Transformation", rATransformation ); + else + SAL_INFO("chart2", "No rATransformation value is given to ShapeFactory::createText()"); + + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference + ShapeFactory::createText( const rtl::Reference& xTarget + , const uno::Sequence< uno::Reference< chart2::XFormattedString > >& xFormattedString + , const tNameSequence& rPropNames + , const tAnySequence& rPropValues + , const uno::Any& rATransformation ) +{ + if( !xTarget.is() ) + return nullptr; + + if( !xFormattedString.hasElements() ) + return nullptr; + + sal_Int32 nNumberOfParagraphs = xFormattedString.getLength(); + + bool bNotEmpty = false; + for( sal_Int32 nN = 0; nN < nNumberOfParagraphs; ++nN ) + { + if( !xFormattedString[nN]->getString().isEmpty() ) + { + bNotEmpty = true; + break; + } + } + if( !bNotEmpty ) + return nullptr; + + //create shape and add to page + rtl::Reference xShape = new SvxShapeText(nullptr); + xShape->setShapeKind(SdrObjKind::Text); + xTarget->addShape(*xShape); + + //set paragraph properties + bNotEmpty = false; + // the first cursor is used for appending the next paragraph, + // after a new string has been inserted the cursor is moved at the end + // of the inserted string + // the second cursor is used for selecting the paragraph and apply the + // passed text properties + Reference< text::XTextCursor > xInsertCursor = xShape->createTextCursor(); + Reference< text::XTextCursor > xSelectionCursor = xShape->createTextCursor(); + if( xInsertCursor.is() && xSelectionCursor.is() ) + { + uno::Reference< beans::XPropertySet > xSelectionProp( xSelectionCursor, uno::UNO_QUERY ); + if( xSelectionProp.is() ) + { + for( sal_Int32 nN = 0; nN < nNumberOfParagraphs; ++nN ) + { + if( !xFormattedString[nN]->getString().isEmpty() ) + { + xInsertCursor->gotoEnd( false ); + xSelectionCursor->gotoEnd( false ); + xShape->insertString( xInsertCursor, xFormattedString[nN]->getString(), false ); + bNotEmpty = true; + xSelectionCursor->gotoEnd( true ); // select current paragraph + uno::Reference< beans::XPropertySet > xStringProperties( xFormattedString[nN], uno::UNO_QUERY ); + PropertyMapper::setMappedProperties( xSelectionProp, xStringProperties, + PropertyMapper::getPropertyNameMapForTextShapeProperties() ); + } + } + } + } + + if( !bNotEmpty ) + return nullptr; + + //set whole text shape properties + PropertyMapper::setMultiProperties( rPropNames, rPropValues, *xShape ); + + if( rATransformation.hasValue() ) + { + //set position matrix + //the matrix needs to be set at the end behind autogrow and such position influencing properties + try + { + xShape->SvxShape::setPropertyValue( "Transformation", rATransformation ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + return xShape; +} + +rtl::Reference + ShapeFactory::createText( const rtl::Reference& xTarget, + const awt::Size& rSize, + const awt::Point& rPos, + uno::Sequence< uno::Reference< chart2::XFormattedString > >& xFormattedString, + const uno::Reference< + beans::XPropertySet > & xTextProperties, + double nRotation, const OUString& aName, sal_Int32 nTextMaxWidth ) +{ + //create shape and add to page + rtl::Reference xShape = new SvxShapeText(nullptr); + xShape->setShapeKind(SdrObjKind::Text); + try + { + xTarget->addShape(*xShape); + + //set text and text properties + uno::Reference< text::XTextCursor > xTextCursor( xShape->createTextCursor() ); + if( !xTextCursor.is() ) + return xShape; + + tPropertyNameValueMap aValueMap; + //fill line-, fill- and paragraph-properties into the ValueMap + { + tPropertyNameMap aNameMap = PropertyMapper::getPropertyNameMapForParagraphProperties(); + auto const & add = PropertyMapper::getPropertyNameMapForFillAndLineProperties(); + aNameMap.insert(add.begin(), add.end()); + + PropertyMapper::getValueMap( aValueMap, aNameMap, xTextProperties ); + } + + //fill some more shape properties into the ValueMap + { + aValueMap.insert( { "TextHorizontalAdjust", uno::Any(drawing::TextHorizontalAdjust_CENTER) } ); // drawing::TextHorizontalAdjust + aValueMap.insert( { "TextVerticalAdjust", uno::Any(drawing::TextVerticalAdjust_CENTER) } ); //drawing::TextVerticalAdjust + aValueMap.insert( { "TextAutoGrowHeight", uno::Any(true) } ); // sal_Bool + aValueMap.insert( { "TextAutoGrowWidth", uno::Any(true) } ); // sal_Bool + aValueMap.insert( { "TextMaximumFrameWidth", uno::Any(nTextMaxWidth) } ); // sal_Int32 + + //set name/classified ObjectID (CID) + if( !aName.isEmpty() ) + aValueMap.emplace( "Name", uno::Any( aName ) ); //CID OUString + } + + //set global title properties + { + tNameSequence aPropNames; + tAnySequence aPropValues; + PropertyMapper::getMultiPropertyListsFromValueMap( aPropNames, aPropValues, aValueMap ); + PropertyMapper::setMultiProperties( aPropNames, aPropValues, *xShape ); + } + + bool bStackCharacters(false); + try + { + xTextProperties->getPropertyValue( "StackCharacters" ) >>= bStackCharacters; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + if(bStackCharacters) + { + //if the characters should be stacked we use only the first character properties for code simplicity + if( xFormattedString.hasElements() ) + { + OUString aLabel; + for( const auto & i : std::as_const(xFormattedString) ) + aLabel += i->getString(); + aLabel = ShapeFactory::getStackedString( aLabel, bStackCharacters ); + + xTextCursor->gotoEnd(false); + xShape->insertString( xTextCursor, aLabel, false ); + xTextCursor->gotoEnd(true); + uno::Reference< beans::XPropertySet > xSourceProps( xFormattedString[0], uno::UNO_QUERY ); + + PropertyMapper::setMappedProperties( *xShape, xSourceProps + , PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + awt::Size aOldRefSize; + if( xTextProperties->getPropertyValue( "ReferencePageSize") >>= aOldRefSize ) + { + RelativeSizeHelper::adaptFontSizes( *xShape, aOldRefSize, rSize ); + } + } + } + else + { + for( const uno::Reference< chart2::XFormattedString >& rxFS : std::as_const(xFormattedString) ) + { + xTextCursor->gotoEnd(false); + xShape->insertString( xTextCursor, rxFS->getString(), false ); + xTextCursor->gotoEnd(true); + } + awt::Size aOldRefSize; + bool bHasRefPageSize = + ( xTextProperties->getPropertyValue( "ReferencePageSize") >>= aOldRefSize ); + + if( xFormattedString.hasElements() ) + { + uno::Reference< beans::XPropertySet > xSourceProps( xFormattedString[0], uno::UNO_QUERY ); + PropertyMapper::setMappedProperties( *xShape, xSourceProps, PropertyMapper::getPropertyNameMapForCharacterProperties() ); + + // adapt font size according to page size + if( bHasRefPageSize ) + { + RelativeSizeHelper::adaptFontSizes( *xShape, aOldRefSize, rSize ); + } + } + } + + // #i109336# Improve auto positioning in chart + float fFontHeight = 0.0; + if ( xShape->SvxShape::getPropertyValue( "CharHeight" ) >>= fFontHeight ) + { + fFontHeight = convertPointToMm100(fFontHeight); + sal_Int32 nXDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * 0.18f ) ); + sal_Int32 nYDistance = static_cast< sal_Int32 >( ::rtl::math::round( fFontHeight * 0.30f ) ); + xShape->SvxShape::setPropertyValue( "TextLeftDistance", uno::Any( nXDistance ) ); + xShape->SvxShape::setPropertyValue( "TextRightDistance", uno::Any( nXDistance ) ); + xShape->SvxShape::setPropertyValue( "TextUpperDistance", uno::Any( nYDistance ) ); + xShape->SvxShape::setPropertyValue( "TextLowerDistance", uno::Any( nYDistance ) ); + } + sal_Int32 nXPos = rPos.X; + sal_Int32 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( -basegfx::deg2rad(nRotation) );//#i78696#->#i80521# + aM.translate( nXPos, nYPos ); + xShape->SvxShape::setPropertyValue( "Transformation", uno::Any( B2DHomMatrixToHomogenMatrix3(aM) ) ); + + xShape->SvxShape::setPropertyValue( "ParaAdjust", uno::Any( style::ParagraphAdjust_CENTER ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + +rtl::Reference ShapeFactory::getChartRootShape( + const rtl::Reference& xDrawPage ) +{ + rtl::Reference xRet; + const uno::Reference< drawing::XShapes > xShapes = xDrawPage; + 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 ) == "com.sun.star.chart2.shapes" ) + { + xRet = dynamic_cast(xShape.get()); + assert(xRet); + break; + } + } + } + } + return xRet; +} + +void ShapeFactory::makeShapeInvisible( const rtl::Reference< SvxShape >& xShape ) +{ + try + { + xShape->setPropertyValue( "LineStyle", uno::Any( drawing::LineStyle_NONE )); + xShape->setPropertyValue( "FillStyle", uno::Any( drawing::FillStyle_NONE )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +// set a name/CID at a shape (is used for selection handling) + +void ShapeFactory::setShapeName( const rtl::Reference< SvxShape >& xShape + , const OUString& rName ) +{ + if(!xShape.is()) + return; + try + { + xShape->setPropertyValue( UNO_NAME_MISC_OBJ_NAME + , uno::Any( rName ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +OUString ShapeFactory::getShapeName( const uno::Reference< drawing::XShape >& xShape ) +{ + OUString aRet; + + uno::Reference< beans::XPropertySet > xProp( xShape, uno::UNO_QUERY ); + OSL_ENSURE(xProp.is(), "shape offers no XPropertySet"); + if( xProp.is()) + { + try + { + xProp->getPropertyValue( UNO_NAME_MISC_OBJ_NAME ) >>= aRet; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + + return aRet; +} + +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( B2DHomMatrixToHomogenMatrix3(aM) ); + return aATransformation; +} + +OUString ShapeFactory::getStackedString( const OUString& rString, bool bStacked ) +{ + sal_Int32 nLen = rString.getLength(); + if(!bStacked || !nLen) + return rString; + + OUStringBuffer aStackStr; + + //add a newline after each letter + //as we do not no letters here add a newline after each char + for( sal_Int32 nPosSrc=0; nPosSrc < nLen; nPosSrc++ ) + { + if( nPosSrc ) + aStackStr.append( '\r' ); + aStackStr.append(rString[nPosSrc]); + } + return aStackStr.makeStringAndClear(); +} + +bool ShapeFactory::hasPolygonAnyLines( const std::vector>& rPoly) +{ + // #i67757# check all contained polygons, if at least one polygon contains 2 or more points, return true + for( auto const & i : rPoly ) + if( i.size() > 1 ) + return true; + return false; +} + +bool ShapeFactory::isPolygonEmptyOrSinglePoint( const drawing::PolyPolygonShape3D& rPoly) +{ + // true, if empty polypolygon or one polygon with one point + return !rPoly.SequenceX.hasElements() || + ((rPoly.SequenceX.getLength() == 1) && (rPoly.SequenceX[0].getLength() <= 1)); +} + +bool ShapeFactory::isPolygonEmptyOrSinglePoint( const std::vector>& rPoly) +{ + // true, if empty polypolygon or one polygon with one point + return rPoly.empty() || ((rPoly.size() == 1) && (rPoly[0].size() <= 1)); +} + +void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) +{ + OSL_ENSURE( 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 ); +} + +void ShapeFactory::closePolygon( std::vector>& rPoly) +{ + OSL_ENSURE( rPoly.size() <= 1, "ShapeFactory::closePolygon - single polygon expected" ); + //add a last point == first point + if(isPolygonEmptyOrSinglePoint(rPoly)) + return; + drawing::Position3D aFirst(rPoly[0][0]); + AddPointToPoly( rPoly, aFirst ); +} + +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(fFactor*rSourceSizeWithCorrectAspectRatio.Width); + aNewSize.Height=static_cast(fFactor*rSourceSizeWithCorrectAspectRatio.Height); + + return aNewSize; +} + +awt::Point ShapeFactory::calculateTopLeftPositionToCenterObject( + const awt::Point& rTargetAreaPosition + , const awt::Size& rTargetAreaSize + , const awt::Size& rObjectSize ) +{ + awt::Point aNewPosition(rTargetAreaPosition); + aNewPosition.X += static_cast(double(rTargetAreaSize.Width-rObjectSize.Width)/2.0); + aNewPosition.Y += static_cast(double(rTargetAreaSize.Height-rObjectSize.Height)/2.0); + return aNewPosition; +} + +::basegfx::B2IRectangle ShapeFactory::getRectangleOfShape( SvxShape& rShape ) +{ + ::basegfx::B2IRectangle aRet; + + awt::Point aPos = rShape.getPosition(); + awt::Size aSize = rShape.getSize(); + aRet = BaseGFXHelper::makeRectangle(aPos,aSize); + + return aRet; +} + +awt::Size ShapeFactory::getSizeAfterRotation( + SvxShape& rShape, double fRotationAngleDegree ) +{ + awt::Size aRet(0,0); + const awt::Size aSize( rShape.getSize() ); + + if( fRotationAngleDegree == 0.0 ) + aRet = aSize; + else + { + fRotationAngleDegree = NormAngle360(fRotationAngleDegree); + 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 = basegfx::deg2rad(fRotationAngleDegree); + + aRet.Height = static_cast( + aSize.Width*std::sin( fAnglePi ) + + aSize.Height*std::cos( fAnglePi )); + aRet.Width = static_cast( + aSize.Width*std::cos( fAnglePi ) + + aSize.Height*std::sin( fAnglePi )); + } + return aRet; +} + +void ShapeFactory::removeSubShapes( const rtl::Reference& 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 ); + } + } +} + +rtl::Reference +ShapeFactory::createTable(rtl::Reference const& xTarget) +{ + if( !xTarget.is() ) + return nullptr; + + //create table shape + rtl::Reference xShape = new SvxTableShape(nullptr); + xShape->setShapeKind(SdrObjKind::Table); + xTarget->addShape(*xShape); + + return xShape; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/Stripe.cxx b/chart2/source/view/main/Stripe.cxx new file mode 100644 index 000000000..74c8ad046 --- /dev/null +++ b/chart2/source/view/main/Stripe.cxx @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +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, cppu::UnoType::get()); +} + +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(aPolygon3D.getNormal()); + 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, cppu::UnoType::get()); +} + +uno::Any Stripe::getTexturePolygon( short nRotatedTexture ) +{ + 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, cppu::UnoType::get()); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VButton.cxx b/chart2/source/view/main/VButton.cxx new file mode 100644 index 000000000..25a770fb0 --- /dev/null +++ b/chart2/source/view/main/VButton.cxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "VButton.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace chart +{ +using namespace css; + +VButton::VButton() + : m_bShowArrow(true) + , m_nArrowColor(0x00000000) + , m_nBGColor(0x00E6E6E6) +{ +} + +void VButton::init(const rtl::Reference& xTargetPage) +{ + m_xTarget = xTargetPage; +} + +rtl::Reference VButton::createTriangle(awt::Size aSize) +{ + rtl::Reference xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::Polygon); + + drawing::PolyPolygonShape3D aPolyPolygon; + aPolyPolygon.SequenceX.realloc(1); + aPolyPolygon.SequenceY.realloc(1); + aPolyPolygon.SequenceZ.realloc(1); + + drawing::DoubleSequence* pOuterSequenceX = aPolyPolygon.SequenceX.getArray(); + drawing::DoubleSequence* pOuterSequenceY = aPolyPolygon.SequenceY.getArray(); + drawing::DoubleSequence* pOuterSequenceZ = aPolyPolygon.SequenceZ.getArray(); + + pOuterSequenceX->realloc(3); + pOuterSequenceY->realloc(3); + pOuterSequenceZ->realloc(3); + + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + + pInnerSequenceX[0] = 0.0; + pInnerSequenceY[0] = 0.0; + pInnerSequenceZ[0] = 0.0; + + pInnerSequenceX[1] = aSize.Width / 2.0; + pInnerSequenceY[1] = aSize.Height; + pInnerSequenceZ[1] = 0.0; + + pInnerSequenceX[2] = aSize.Width; + pInnerSequenceY[2] = 0.0; + pInnerSequenceZ[2] = 0.0; + + xShape->SvxShape::setPropertyValue("Name", uno::Any(m_sCID)); + xShape->SvxShape::setPropertyValue(UNO_NAME_POLYPOLYGON, + uno::Any(PolyToPointSequence(aPolyPolygon))); + xShape->SvxShape::setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE)); + xShape->SvxShape::setPropertyValue("FillColor", uno::Any(m_nArrowColor)); + + return xShape; +} + +void VButton::createShapes(const uno::Reference& xTextProp) +{ + tNameSequence aPropNames; + tAnySequence aPropValues; + + PropertyMapper::getTextLabelMultiPropertyLists(xTextProp, aPropNames, aPropValues); + + m_xShape = ShapeFactory::createGroup2D(m_xTarget, m_sCID); + m_xShape->setPosition(m_aPosition); + m_xShape->setSize(m_aSize); + + rtl::Reference xContainer = m_xShape; + + tPropertyNameValueMap aTextValueMap; + aTextValueMap["CharHeight"] <<= 10.0f; + aTextValueMap["CharHeightAsian"] <<= 10.0f; + aTextValueMap["CharHeightComplex"] <<= 10.0f; + aTextValueMap["FillColor"] <<= m_nBGColor; + aTextValueMap["FillStyle"] <<= drawing::FillStyle_SOLID; + aTextValueMap["LineColor"] <<= sal_Int32(0xcccccc); + aTextValueMap["LineStyle"] <<= drawing::LineStyle_SOLID; + aTextValueMap["ParaAdjust"] <<= style::ParagraphAdjust_CENTER; + aTextValueMap["TextHorizontalAdjust"] <<= drawing::TextHorizontalAdjust_LEFT; + aTextValueMap["TextVerticalAdjust"] <<= drawing::TextVerticalAdjust_CENTER; + aTextValueMap["ParaLeftMargin"] <<= sal_Int32(100); + aTextValueMap["ParaRightMargin"] <<= sal_Int32(600); + + aTextValueMap["Name"] <<= m_sCID; //CID OUString + + PropertyMapper::getMultiPropertyListsFromValueMap(aPropNames, aPropValues, aTextValueMap); + + rtl::Reference xEntry + = ShapeFactory::createText(xContainer, m_sLabel, aPropNames, aPropValues, uno::Any()); + + if (xEntry.is()) + { + xEntry->setPosition(m_aPosition); + xEntry->setSize(m_aSize); + } + + if (!m_bShowArrow) + return; + + awt::Size aPolySize{ 280, 180 }; + + rtl::Reference xPoly = createTriangle(aPolySize); + xPoly->setSize(aPolySize); + xPoly->setPosition( + { sal_Int32(m_aPosition.X + m_aSize.Width - aPolySize.Width - 100), + sal_Int32(m_aPosition.Y + (m_aSize.Height / 2.0) - (aPolySize.Height / 2.0)) }); + xContainer->add(xPoly); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VButton.hxx b/chart2/source/view/main/VButton.hxx new file mode 100644 index 000000000..87017f369 --- /dev/null +++ b/chart2/source/view/main/VButton.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace chart +{ + +class VButton final +{ +private: + rtl::Reference m_xTarget; + rtl::Reference m_xShape; + OUString m_sLabel; + OUString m_sCID; + css::awt::Point m_aPosition; + css::awt::Size m_aSize; + bool m_bShowArrow; + Color m_nArrowColor; + Color m_nBGColor; + + rtl::Reference + createTriangle(css::awt::Size aSize); + +public: + VButton(); + + void init(const rtl::Reference& xTargetPage); + + void createShapes(const css::uno::Reference& xTextProp); + + void showArrow(bool bShowArrow) + { + m_bShowArrow = bShowArrow; + } + void setArrowColor(Color nArrowColor) + { + m_nArrowColor = nArrowColor; + } + void setBGColor(Color nBGColor) + { + m_nBGColor = nBGColor; + } + void setLabel(OUString const & rLabel) + { + m_sLabel = rLabel; + } + void setCID(OUString const & rCID) + { + m_sCID = rCID; + } + void setPosition(css::awt::Point const & rPosition) + { + m_aPosition = rPosition; + } + css::awt::Size const & getSize() const + { + return m_aSize; + } + void setSize(css::awt::Size const & rSize) + { + m_aSize = rSize; + } +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx new file mode 100644 index 000000000..3fb12ebca --- /dev/null +++ b/chart2/source/view/main/VDataSeries.cxx @@ -0,0 +1,1118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 ) +{ + m_xModel = xModel; + m_aValues = DataSequenceToDoubleSequence( xModel ); +} + +bool VDataSequence::is() const +{ + return m_xModel.is(); +} +void VDataSequence::clear() +{ + m_xModel = nullptr; + m_aValues.realloc(0); +} + +double VDataSequence::getValue( sal_Int32 index ) const +{ + if( 0<=index && index::quiet_NaN(); +} + +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 && indexgetNumberFormatKeyByIndex( index ); + } + + return nNumberFormatKey; +} + +sal_Int32 VDataSequence::getLength() const +{ + return m_aValues.getLength(); +} + +namespace +{ +struct lcl_LessXOfPoint +{ + bool operator() ( const std::vector< double >& first, + const std::vector< double >& second ) + { + if( !first.empty() && !second.empty() ) + { + return first[0]& xDataSequence ) +{ + //#i71686#, #i101968#, #i102428# + sal_Int32 nCount = rData.m_aValues.getLength(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + if( !std::isnan( rData.m_aValues[i] ) ) + return; + } + //no double value is contained + //is there any text? + uno::Sequence< OUString > aStrings( DataSequenceToStringSequence( xDataSequence ) ); + sal_Int32 nTextCount = aStrings.getLength(); + for( sal_Int32 j = 0; j < nTextCount; ++j ) + { + if( !aStrings[j].isEmpty() ) + { + rData.clear(); + return; + } + } + //no content at all +} + +void lcl_maybeReplaceNanWithZero( double& rfValue, sal_Int32 nMissingValueTreatment ) +{ + if( nMissingValueTreatment == css::chart::MissingValueTreatment::USE_ZERO + && (std::isnan(rfValue) || std::isinf(rfValue)) ) + rfValue = 0.0; +} + +} + +VDataSeries::VDataSeries( const rtl::Reference< DataSeries >& xDataSeries ) + : m_nPolygonIndex(0) + , m_fLogicMinX(0.0) + , m_fLogicMaxX(0.0) + , m_fLogicZPos(0.0) + , m_xDataSeries(xDataSeries) + , m_nPointCount(0) + , m_pValueSequenceForDataLabelNumberFormatDetection(&m_aValues_Y) + , m_fXMeanValue(std::numeric_limits::quiet_NaN()) + , m_fYMeanValue(std::numeric_limits::quiet_NaN()) + , m_eStackingDirection(StackingDirection_NO_STACKING) + , m_nAxisIndex(0) + , m_bConnectBars(false) + , m_bGroupBarsPerAxis(true) + , m_nStartingAngle(90) + , m_nGlobalSeriesIndex(0) + , m_nCurrentAttributedPoint(-1) + , m_nMissingValueTreatment(css::chart::MissingValueTreatment::LEAVE_GAP) + , m_bAllowPercentValueInDataLabel(false) + , mpOldSeries(nullptr) + , mnPercent(0.0) +{ + m_xDataSeriesProps = m_xDataSeries; + + const std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > & aDataSequences = + m_xDataSeries->getDataSequences2(); + + for(sal_Int32 nN = aDataSequences.size();nN--;) + { + uno::Reference xDataSequence( aDataSequences[nN]->getValues()); + uno::Reference xProp(xDataSequence, uno::UNO_QUERY ); + if( xProp.is()) + { + try + { + uno::Any aARole = xProp->getPropertyValue("Role"); + OUString aRole; + aARole >>= aRole; + + if (aRole == "values-x") + { + m_aValues_X.init( xDataSequence ); + lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xDataSequence ); + } + else if (aRole =="values-y") + m_aValues_Y.init( xDataSequence ); + else if (aRole == "values-min") + m_aValues_Y_Min.init( xDataSequence ); + else if (aRole == "values-max") + m_aValues_Y_Max.init( xDataSequence ); + else if (aRole == "values-first") + m_aValues_Y_First.init( xDataSequence ); + else if (aRole == "values-last") + m_aValues_Y_Last.init( xDataSequence ); + else if (aRole == "values-size") + m_aValues_Bubble_Size.init( xDataSequence ); + else + { + VDataSequence aSequence; + aSequence.init(xDataSequence); + m_PropertyMap.insert(std::make_pair(aRole, aSequence)); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + } + } + + //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(); + } + + if( !xDataSeries.is()) + return; + + try + { + //get AttributedDataPoints + xDataSeries->getPropertyValue("AttributedDataPoints") >>= m_aAttributedDataPointIndexList; + + xDataSeries->getPropertyValue("StackingDirection") >>= m_eStackingDirection; + + xDataSeries->getPropertyValue("AttachedAxisIndex") >>= m_nAxisIndex; + if(m_nAxisIndex<0) + m_nAxisIndex=0; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +VDataSeries::~VDataSeries() +{ +} + +void VDataSeries::doSortByXValues() +{ + if( !(m_aValues_X.is() && m_aValues_X.m_aValues.hasElements()) ) + return; + + //prepare a vector for sorting + std::vector< std::vector< double > > aTmp;//outer vector are points, inner vector are the different values of the point + sal_Int32 nPointIndex = 0; + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + aTmp.push_back( + { ((nPointIndex < m_aValues_X.m_aValues.getLength()) ? m_aValues_X.m_aValues[nPointIndex] + : std::numeric_limits::quiet_NaN()), + ((nPointIndex < m_aValues_Y.m_aValues.getLength()) ? m_aValues_Y.m_aValues[nPointIndex] + : std::numeric_limits::quiet_NaN()) + } + ); + } + + //do sort + std::stable_sort( aTmp.begin(), aTmp.end(), lcl_LessXOfPoint() ); + + //fill the sorted points back to the members + m_aValues_X.m_aValues.realloc( m_nPointCount ); + auto pDoublesX = m_aValues_X.m_aValues.getArray(); + m_aValues_Y.m_aValues.realloc( m_nPointCount ); + auto pDoublesY = m_aValues_Y.m_aValues.getArray(); + + for( nPointIndex=0; nPointIndex < m_nPointCount; nPointIndex++ ) + { + pDoublesX[nPointIndex]=aTmp[nPointIndex][0]; + pDoublesY[nPointIndex]=aTmp[nPointIndex][1]; + } +} + +void VDataSeries::releaseShapes() +{ + m_xGroupShape.set(nullptr); + m_xLabelsGroupShape.set(nullptr); + m_xErrorXBarsGroupShape.set(nullptr); + m_xErrorYBarsGroupShape.set(nullptr); + m_xFrontSubGroupShape.set(nullptr); + m_xBackSubGroupShape.set(nullptr); + + m_aPolyPolygonShape3D.clear(); + m_nPolygonIndex = 0; +} + +const rtl::Reference<::chart::DataSeries>& VDataSeries::getModel() const +{ + return m_xDataSeries; +} + +void VDataSeries::setCategoryXAxis() +{ + m_aValues_X.clear(); + m_bAllowPercentValueInDataLabel = true; +} + +void VDataSeries::setXValues( const Reference< chart2::data::XDataSequence >& xValues ) +{ + m_aValues_X.clear(); + m_aValues_X.init( xValues ); + m_bAllowPercentValueInDataLabel = true; +} + +void VDataSeries::setXValuesIfNone( const Reference< chart2::data::XDataSequence >& xValues ) +{ + if( m_aValues_X.is() ) + return; + + m_aValues_X.init( xValues ); + lcl_clearIfNoValuesButTextIsContained( m_aValues_X, xValues ); +} + +void VDataSeries::setGlobalSeriesIndex( sal_Int32 nGlobalSeriesIndex ) +{ + m_nGlobalSeriesIndex = nGlobalSeriesIndex; +} + +void VDataSeries::setParticle( const 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, u"", getLabelsCID() ); +} +OUString VDataSeries::getErrorBarsCID(bool bYError) const +{ + OUString aChildParticle( ObjectIdentifier::getStringForType( + bYError ? OBJECTTYPE_DATA_ERRORS_Y : OBJECTTYPE_DATA_ERRORS_X ) + + "=" ); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +OUString VDataSeries::getLabelsCID() const +{ + OUString aChildParticle( ObjectIdentifier::getStringForType( OBJECTTYPE_DATA_LABELS ) + "=" ); + + return ObjectIdentifier::createClassifiedIdentifierForParticles( + m_aSeriesParticle, aChildParticle ); +} +OUString VDataSeries::getDataCurveCID( sal_Int32 nCurveIndex, bool bAverageLine ) const +{ + return ObjectIdentifier::createDataCurveCID( m_aSeriesParticle, nCurveIndex, bAverageLine ); +} + +OUString VDataSeries::getDataCurveEquationCID( sal_Int32 nCurveIndex ) const +{ + return ObjectIdentifier::createDataCurveEquationCID( m_aSeriesParticle, nCurveIndex ); +} +void VDataSeries::setPageReferenceSize( const awt::Size & rPageRefSize ) +{ + m_aReferenceSize = rPageRefSize; +} + +void VDataSeries::setConnectBars( bool bConnectBars ) +{ + m_bConnectBars = bConnectBars; +} + +bool VDataSeries::getConnectBars() const +{ + return m_bConnectBars; +} + +void VDataSeries::setGroupBarsPerAxis( bool bGroupBarsPerAxis ) +{ + m_bGroupBarsPerAxis = bGroupBarsPerAxis; +} + +bool VDataSeries::getGroupBarsPerAxis() const +{ + return m_bGroupBarsPerAxis; +} + +void VDataSeries::setStartingAngle( sal_Int32 nStartingAngle ) +{ + m_nStartingAngle = nStartingAngle; +} + +sal_Int32 VDataSeries::getStartingAngle() const +{ + return m_nStartingAngle; +} + +chart2::StackingDirection VDataSeries::getStackingDirection() const +{ + return m_eStackingDirection; +} + +sal_Int32 VDataSeries::getAttachedAxisIndex() const +{ + return m_nAxisIndex; +} + +void VDataSeries::setAttachedAxisIndex( sal_Int32 nAttachedAxisIndex ) +{ + if( nAttachedAxisIndex < 0 ) + nAttachedAxisIndex = 0; + m_nAxisIndex = nAttachedAxisIndex; +} + +double VDataSeries::getXValue( sal_Int32 index ) const +{ + double fRet = std::numeric_limits::quiet_NaN(); + if(m_aValues_X.is()) + { + if( 0<=index && indexm_aValues_X.getLength()) + { + double nOldVal = mpOldSeries->m_aValues_X.m_aValues[index]; + fRet = nOldVal + (fRet - nOldVal) * mnPercent; + } + } + } + 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 + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +double VDataSeries::getYValue( sal_Int32 index ) const +{ + double fRet = std::numeric_limits::quiet_NaN(); + if(m_aValues_Y.is()) + { + if( 0<=index && indexm_aValues_Y.getLength()) + { + double nOldVal = mpOldSeries->m_aValues_Y.m_aValues[index]; + fRet = nOldVal + (fRet - nOldVal) * mnPercent; + } + } + } + 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 + } + lcl_maybeReplaceNanWithZero( fRet, getMissingValueTreatment() ); + return fRet; +} + +void VDataSeries::getMinMaxXValue(double& fMin, double& fMax) const +{ + fMax = std::numeric_limits::quiet_NaN(); + fMin = std::numeric_limits::quiet_NaN(); + + uno::Sequence< double > aValuesX = getAllX(); + + if(!aValuesX.hasElements()) + return; + + sal_Int32 i = 0; + while ( i < aValuesX.getLength() && std::isnan(aValuesX[i]) ) + i++; + if ( i < aValuesX.getLength() ) + fMax = fMin = aValuesX[i++]; + + for ( ; i < aValuesX.getLength(); i++) + { + const double aValue = aValuesX[i]; + if ( aValue > fMax) + { + fMax = aValue; + } + else if ( aValue < fMin) + { + fMin = aValue; + } + } +} +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 +{ + double nNewVal = m_aValues_Bubble_Size.getValue( index ); + if(mpOldSeries && index < mpOldSeries->m_aValues_Bubble_Size.getLength()) + { + double nOldVal = mpOldSeries->m_aValues_Bubble_Size.getValue( index ); + nNewVal = nOldVal + (nNewVal - nOldVal) * mnPercent; + } + + return nNewVal; +} + +bool VDataSeries::hasExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT); + bool bHasNumberFormat = false; + bool bLinkToSource = true; + uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( nPointIndex )); + if( xPointProp.is() && (xPointProp->getPropertyValue(CHART_UNONAME_LINK_TO_SRC_NUMFMT) >>= bLinkToSource)) + { + sal_Int32 nNumberFormat = -1; + if( !bLinkToSource && (xPointProp->getPropertyValue(aPropName) >>= nNumberFormat)) + bHasNumberFormat = true; + } + return bHasNumberFormat; +} +sal_Int32 VDataSeries::getExplicitNumberFormat( sal_Int32 nPointIndex, bool bForPercentage ) const +{ + OUString aPropName = bForPercentage ? OUString("PercentageNumberFormat") : OUString(CHART_UNONAME_NUMFMT); + sal_Int32 nNumberFormat = -1; + uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( nPointIndex )); + if( xPointProp.is() ) + xPointProp->getPropertyValue(aPropName) >>= nNumberFormat; + return nNumberFormat; +} +void VDataSeries::setRoleOfSequenceForDataLabelNumberFormatDetection( std::u16string_view rRole ) +{ + if (rRole == u"values-y") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y; + else if (rRole == u"values-size") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Bubble_Size; + else if (rRole == u"values-min") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Min; + else if (rRole == u"values-max") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Max; + else if (rRole == u"values-first") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_First; + else if (rRole == u"values-last") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_Y_Last; + else if (rRole == u"values-x") + m_pValueSequenceForDataLabelNumberFormatDetection = &m_aValues_X; +} +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 rtl::Reference< ChartType >& xChartType, bool bSwapXAndY ) const +{ + sal_Int32 nLabelPlacement=0; + try + { + uno::Reference< beans::XPropertySet > xPointProps( getPropertiesOfPoint( nPointIndex ) ); + if( xPointProps.is() ) + xPointProps->getPropertyValue("LabelPlacement") >>= nLabelPlacement; + + const uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements( + xChartType, bSwapXAndY, m_xDataSeries ) ); + + for( sal_Int32 n : aAvailablePlacements ) + if( n == nLabelPlacement ) + return nLabelPlacement; //ok + + //otherwise use the first supported one + if( aAvailablePlacements.hasElements() ) + { + nLabelPlacement = aAvailablePlacements[0]; + if( xPointProps.is() ) + xPointProps->setPropertyValue("LabelPlacement", uno::Any(nLabelPlacement)); + return nLabelPlacement; + } + + OSL_FAIL("no label placement supported"); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return nLabelPlacement; +} + +awt::Point VDataSeries::getLabelPosition( awt::Point aTextShapePos, sal_Int32 nPointIndex ) const +{ + awt::Point aPos(-1, -1); + try + { + RelativePosition aCustomLabelPosition; + uno::Reference< beans::XPropertySet > xPointProps(getPropertiesOfPoint(nPointIndex)); + if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition)) + { + aPos.X = static_cast(aCustomLabelPosition.Primary * m_aReferenceSize.Width) + aTextShapePos.X; + aPos.Y = static_cast(aCustomLabelPosition.Secondary * m_aReferenceSize.Height) + aTextShapePos.Y; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + return aPos; +} + +bool VDataSeries::isLabelCustomPos(sal_Int32 nPointIndex) const +{ + bool bCustom = false; + try + { + if( isAttributedDataPoint(nPointIndex) ) + { + uno::Reference< beans::XPropertySet > xPointProps(m_xDataSeries->getDataPointByIndex(nPointIndex)); + RelativePosition aCustomLabelPosition; + if( xPointProps.is() && (xPointProps->getPropertyValue("CustomLabelPosition") >>= aCustomLabelPosition) ) + bCustom = true; + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + return bCustom; +} + +double VDataSeries::getMinimumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMin = std::numeric_limits::infinity(); + + 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( std::isinf(fMin) ) + return std::numeric_limits::quiet_NaN(); + + return fMin; +} + +double VDataSeries::getMaximumofAllDifferentYValues( sal_Int32 index ) const +{ + double fMax = -std::numeric_limits::infinity(); + + 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::quiet_NaN(); + + return fMax; +} + +uno::Sequence< double > const & 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.m_aValues.realloc( m_nPointCount ); + auto pDoubles = m_aValues_X.m_aValues.getArray(); + for(sal_Int32 nN=m_aValues_X.getLength();nN--;) + pDoubles[nN] = nN+1; + } + return m_aValues_X.m_aValues; +} + +uno::Sequence< double > const & 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.m_aValues.realloc( m_nPointCount ); + auto pDoubles = m_aValues_Y.m_aValues.getArray(); + for(sal_Int32 nN=m_aValues_Y.getLength();nN--;) + pDoubles[nN] = nN+1; + } + return m_aValues_Y.m_aValues; +} + +double VDataSeries::getXMeanValue() const +{ + if( std::isnan( m_fXMeanValue ) ) + { + uno::Reference< XRegressionCurveCalculator > xCalculator( RegressionCurveHelper::createRegressionCurveCalculatorByServiceName( u"com.sun.star.chart2.MeanValueRegressionCurve" ) ); + uno::Sequence< double > aXValuesDummy; + xCalculator->recalculateRegression( aXValuesDummy, getAllX() ); + m_fXMeanValue = xCalculator->getCurveValue( 1.0 ); + } + return m_fXMeanValue; +} + +double VDataSeries::getYMeanValue() const +{ + if( std::isnan( m_fYMeanValue ) ) + { + uno::Reference< XRegressionCurveCalculator > xCalculator( + RegressionCurveHelper::createRegressionCurveCalculatorByServiceName(u"com.sun.star.chart2.MeanValueRegressionCurve")); + uno::Sequence< double > aXValuesDummy; + xCalculator->recalculateRegression( aXValuesDummy, getAllY() ); + m_fYMeanValue = xCalculator->getCurveValue( 1.0 ); + } + return m_fYMeanValue; +} + +static std::unique_ptr getSymbolPropertiesFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp ) +{ + std::unique_ptr< Symbol > apSymbolProps( new Symbol() ); + try + { + if( xProp->getPropertyValue("Symbol") >>= *apSymbolProps ) + { + //use main color to fill symbols + xProp->getPropertyValue("Color") >>= apSymbolProps->FillColor; + // border of symbols always same as fill color + apSymbolProps->BorderColor = apSymbolProps->FillColor; + } + else + apSymbolProps.reset(); + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return apSymbolProps; +} + +Symbol* VDataSeries::getSymbolProperties( sal_Int32 index ) const +{ + Symbol* pRet=nullptr; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if (!m_apSymbolProperties_AttributedPoint) + m_apSymbolProperties_AttributedPoint + = getSymbolPropertiesFromPropertySet(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) + m_apSymbolProperties_Series + = getSymbolPropertiesFromPropertySet(getPropertiesOfSeries()); + if( m_apSymbolProperties_Series && m_apSymbolProperties_Series->Style != SymbolStyle_NONE ) + { + if (!m_apSymbolProperties_InvisibleSymbolForSelection) + { + m_apSymbolProperties_InvisibleSymbolForSelection.reset(new Symbol); + m_apSymbolProperties_InvisibleSymbolForSelection->Style = SymbolStyle_STANDARD; + m_apSymbolProperties_InvisibleSymbolForSelection->StandardSymbol = 0;//square + m_apSymbolProperties_InvisibleSymbolForSelection->Size = com::sun::star::awt::Size(0, 0);//tdf#126033 + m_apSymbolProperties_InvisibleSymbolForSelection->BorderColor = 0xff000000;//invisible + m_apSymbolProperties_InvisibleSymbolForSelection->FillColor = 0xff000000;//invisible + } + pRet = m_apSymbolProperties_InvisibleSymbolForSelection.get(); + } + } + } + else + { + if (!m_apSymbolProperties_Series) + m_apSymbolProperties_Series + = getSymbolPropertiesFromPropertySet(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::getXErrorBarProperties( sal_Int32 index ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProp; + + uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( index )); + if( xPointProp.is() ) + xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_X) >>= xErrorBarProp; + return xErrorBarProp; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getYErrorBarProperties( sal_Int32 index ) const +{ + uno::Reference< beans::XPropertySet > xErrorBarProp; + + uno::Reference< beans::XPropertySet > xPointProp( getPropertiesOfPoint( index )); + if( xPointProp.is() ) + xPointProp->getPropertyValue(CHART_UNONAME_ERRORBAR_Y) >>= xErrorBarProp; + return xErrorBarProp; +} + +bool VDataSeries::hasPointOwnColor( sal_Int32 index ) const +{ + if( !isAttributedDataPoint(index) ) + return false; + + try + { + uno::Reference< beans::XPropertyState > xPointState( getPropertiesOfPoint(index), uno::UNO_QUERY_THROW ); + return (xPointState->getPropertyState("Color") != beans::PropertyState_DEFAULT_VALUE ); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return false; +} + +bool VDataSeries::isAttributedDataPoint( sal_Int32 index ) const +{ + //returns true if the data point assigned by the given index has set its own properties + if( index>=m_nPointCount || m_nPointCount==0) + return false; + for(sal_Int32 n : m_aAttributedDataPointIndexList) + { + if(index == n) + return true; + } + return false; +} + +bool VDataSeries::isVaryColorsByPoint() const +{ + bool bVaryColorsByPoint = false; + Reference< beans::XPropertySet > xSeriesProp( getPropertiesOfSeries() ); + if( xSeriesProp.is() ) + xSeriesProp->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint; + return bVaryColorsByPoint; +} + +uno::Reference< beans::XPropertySet > VDataSeries::getPropertiesOfPoint( sal_Int32 index ) const +{ + if( isAttributedDataPoint( index ) ) + return m_xDataSeries->getDataPointByIndex(index); + return getPropertiesOfSeries(); +} + +const uno::Reference & VDataSeries::getPropertiesOfSeries() const +{ + return m_xDataSeriesProps; +} + +static std::unique_ptr getDataPointLabelFromPropertySet( const uno::Reference< beans::XPropertySet >& xProp ) +{ + std::unique_ptr< DataPointLabel > apLabel( new DataPointLabel() ); + try + { + if( !(xProp->getPropertyValue(CHART_UNONAME_LABEL) >>= *apLabel) ) + apLabel.reset(); + } + catch(const uno::Exception &) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + 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 = nullptr; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if (!m_apLabel_AttributedPoint) + m_apLabel_AttributedPoint + = getDataPointLabelFromPropertySet(getPropertiesOfPoint(index)); + pRet = m_apLabel_AttributedPoint.get(); + } + else + { + if (!m_apLabel_Series) + m_apLabel_Series + = getDataPointLabelFromPropertySet(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 = getDataPointLabel( index ); + if( !pLabel || (!pLabel->ShowNumber && !pLabel->ShowNumberInPercent + && !pLabel->ShowCategoryName && !pLabel->ShowCustomLabel && !pLabel->ShowSeriesName ) ) + return nullptr; + return pLabel; +} + +bool VDataSeries::getTextLabelMultiPropertyLists( sal_Int32 index + , tNameSequence*& pPropNames + , tAnySequence*& pPropValues ) const +{ + pPropNames = nullptr; pPropValues = nullptr; + uno::Reference< beans::XPropertySet > xTextProp; + bool bDoDynamicFontResize = false; + if( isAttributedDataPoint( index ) ) + { + adaptPointCache( index ); + if (!m_apLabelPropValues_AttributedPoint) + { + // Cache these properties for this point. + m_apLabelPropNames_AttributedPoint.reset(new tNameSequence); + m_apLabelPropValues_AttributedPoint.reset(new tAnySequence); + xTextProp.set( getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( + xTextProp, *m_apLabelPropNames_AttributedPoint, *m_apLabelPropValues_AttributedPoint); + bDoDynamicFontResize = true; + } + pPropNames = m_apLabelPropNames_AttributedPoint.get(); + pPropValues = m_apLabelPropValues_AttributedPoint.get(); + } + else + { + if (!m_apLabelPropValues_Series) + { + // Cache these properties for the whole series. + m_apLabelPropNames_Series.reset(new tNameSequence); + m_apLabelPropValues_Series.reset(new tAnySequence); + xTextProp.set( getPropertiesOfPoint( index )); + PropertyMapper::getTextLabelMultiPropertyLists( + xTextProp, *m_apLabelPropNames_Series, *m_apLabelPropValues_Series); + 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 ); + } + + return (pPropNames && pPropValues); +} + +void VDataSeries::setMissingValueTreatment( sal_Int32 nMissingValueTreatment ) +{ + m_nMissingValueTreatment = nMissingValueTreatment; +} + +sal_Int32 VDataSeries::getMissingValueTreatment() const +{ + return m_nMissingValueTreatment; +} + +VDataSeries::VDataSeries() + : m_nPolygonIndex(0) + , m_fLogicMinX(0) + , m_fLogicMaxX(0) + , m_fLogicZPos(0) + , m_nPointCount(0) + , m_pValueSequenceForDataLabelNumberFormatDetection(nullptr) + , m_fXMeanValue(0) + , m_fYMeanValue(0) + , m_eStackingDirection(chart2::StackingDirection_NO_STACKING) + , m_nAxisIndex(0) + , m_bConnectBars(false) + , m_bGroupBarsPerAxis(false) + , m_nStartingAngle(0) + , m_nGlobalSeriesIndex(0) + , m_nCurrentAttributedPoint(0) + , m_nMissingValueTreatment(0) + , m_bAllowPercentValueInDataLabel(false) + , mpOldSeries(nullptr) + , mnPercent(0) +{ +} + +void VDataSeries::setOldTimeBased( VDataSeries* pOldSeries, double nPercent ) +{ + mnPercent = nPercent; + mpOldSeries = pOldSeries; + mpOldSeries->mpOldSeries = nullptr; +} + +VDataSeries* VDataSeries::createCopyForTimeBased() const +{ + VDataSeries* pNew = new VDataSeries(); + pNew->m_aValues_X = m_aValues_X; + pNew->m_aValues_Y = m_aValues_Y; + pNew->m_aValues_Z = m_aValues_Z; + pNew->m_aValues_Y_Min = m_aValues_Y_Min; + pNew->m_aValues_Y_Max = m_aValues_Y_Max; + pNew->m_aValues_Y_First = m_aValues_Y_First; + pNew->m_aValues_Y_Last = m_aValues_Y_Last; + pNew->m_aValues_Bubble_Size = m_aValues_Bubble_Size; + pNew->m_PropertyMap = m_PropertyMap; + + pNew->m_nPointCount = m_nPointCount; + + return pNew; +} + +double VDataSeries::getValueByProperty( sal_Int32 nIndex, const OUString& rPropName ) const +{ + auto const itr = m_PropertyMap.find(rPropName); + if (itr == m_PropertyMap.end()) + return std::numeric_limits::quiet_NaN(); + + const VDataSequence* pData = &itr->second; + double fValue = pData->getValue(nIndex); + if(mpOldSeries && mpOldSeries->hasPropertyMapping(rPropName)) + { + double fOldValue = mpOldSeries->getValueByProperty( nIndex, rPropName ); + if(rPropName.endsWith("Color")) + { + //optimized interpolation for color values + Color aColor(ColorTransparency, static_cast(fValue)); + Color aOldColor(ColorTransparency, static_cast(fOldValue)); + sal_uInt8 r = aOldColor.GetRed() + (aColor.GetRed() - aOldColor.GetRed()) * mnPercent; + sal_uInt8 g = aOldColor.GetGreen() + (aColor.GetGreen() - aOldColor.GetGreen()) * mnPercent; + sal_uInt8 b = aOldColor.GetBlue() + (aColor.GetBlue() - aOldColor.GetBlue()) * mnPercent; + sal_uInt8 a = aOldColor.GetAlpha() + (aColor.GetAlpha() - aOldColor.GetAlpha()) * mnPercent; + Color aRet(ColorAlpha, a, r, g, b); + return sal_uInt32(aRet); + } + return fOldValue + (fValue - fOldValue) * mnPercent; + } + return fValue; +} + +bool VDataSeries::hasPropertyMapping(const OUString& rPropName ) const +{ + return m_PropertyMap.find(rPropName) != m_PropertyMap.end(); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VLegend.cxx b/chart2/source/view/main/VLegend.cxx new file mode 100644 index 000000000..794d8d41e --- /dev/null +++ b/chart2/source/view/main/VLegend.cxx @@ -0,0 +1,1099 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VLegend.hxx" +#include "VButton.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +namespace +{ + +typedef std::pair< ::chart::tNameSequence, ::chart::tAnySequence > tPropertyValues; + +double lcl_CalcViewFontSize( + const Reference< beans::XPropertySet > & xProp, + const awt::Size & rReferenceSize ) +{ + double fResult = 10.0; + + float fFontHeight( 0.0 ); + if( xProp.is() && ( xProp->getPropertyValue( "CharHeight") >>= fFontHeight )) + { + fResult = fFontHeight; + try + { + awt::Size aPropRefSize; + if( (xProp->getPropertyValue( "ReferencePageSize") >>= aPropRefSize) && + (aPropRefSize.Height > 0)) + { + fResult = ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return convertPointToMm100(fResult); +} + +void lcl_getProperties( + const Reference< beans::XPropertySet > & xLegendProp, + tPropertyValues & rOutLineFillProperties, + tPropertyValues & rOutTextProperties, + const awt::Size & rReferenceSize ) +{ + // Get Line- and FillProperties from model legend + if( !xLegendProp.is()) + return; + + // set rOutLineFillProperties + ::chart::tPropertyNameValueMap aLineFillValueMap; + ::chart::PropertyMapper::getValueMap( aLineFillValueMap, ::chart::PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xLegendProp ); + + aLineFillValueMap[ "LineJoint" ] <<= drawing::LineJoint_ROUND; + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutLineFillProperties.first, rOutLineFillProperties.second, aLineFillValueMap ); + + // set rOutTextProperties + ::chart::tPropertyNameValueMap aTextValueMap; + ::chart::PropertyMapper::getValueMap( aTextValueMap, ::chart::PropertyMapper::getPropertyNameMapForCharacterProperties(), xLegendProp ); + + aTextValueMap[ "TextAutoGrowHeight" ] <<= true; + aTextValueMap[ "TextAutoGrowWidth" ] <<= true; + aTextValueMap[ "TextHorizontalAdjust" ] <<= drawing::TextHorizontalAdjust_LEFT; + aTextValueMap[ "TextMaximumFrameWidth" ] <<= rReferenceSize.Width; //needs to be overwritten by actual available space in the legend + + // recalculate font size + awt::Size aPropRefSize; + float fFontHeight( 0.0 ); + if( (xLegendProp->getPropertyValue( "ReferencePageSize") >>= aPropRefSize) && + (aPropRefSize.Height > 0) && + (aTextValueMap[ "CharHeight" ] >>= fFontHeight) ) + { + aTextValueMap[ "CharHeight" ] <<= + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )); + + if( aTextValueMap[ "CharHeightAsian" ] >>= fFontHeight ) + { + aTextValueMap[ "CharHeightAsian" ] <<= + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )); + } + if( aTextValueMap[ "CharHeightComplex" ] >>= fFontHeight ) + { + aTextValueMap[ "CharHeightComplex" ] <<= + static_cast< float >( + ::chart::RelativeSizeHelper::calculate( fFontHeight, aPropRefSize, rReferenceSize )); + } + } + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( + rOutTextProperties.first, rOutTextProperties.second, aTextValueMap ); +} + +awt::Size lcl_createTextShapes( + const std::vector & rEntries, + const rtl::Reference & xTarget, + std::vector< rtl::Reference > & rOutTextShapes, + const tPropertyValues & rTextProperties ) +{ + awt::Size aResult; + + for (ViewLegendEntry const & rEntry : rEntries) + { + try + { + OUString aLabelString; + Sequence< Reference< XFormattedString2 > > aLabelSeq = rEntry.aLabel; + for( sal_Int32 i = 0; i < aLabelSeq.getLength(); ++i ) + { + // todo: support more than one text range + if( i == 1 ) + break; + + aLabelString += aLabelSeq[i]->getString(); + // workaround for Issue #i67540# + if( aLabelString.isEmpty()) + aLabelString = " "; + } + + rtl::Reference xEntry = + ShapeFactory::createText( xTarget, aLabelString, + rTextProperties.first, rTextProperties.second, uno::Any() ); + + // 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( xEntry ); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + + return aResult; +} + +void lcl_collectColumnWidths( std::vector< sal_Int32 >& rColumnWidths, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns, + const std::vector< rtl::Reference >& rTextShapes, sal_Int32 nSymbolPlusDistanceWidth ) +{ + rColumnWidths.clear(); + sal_Int32 nNumberOfEntries = rTextShapes.size(); + for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow ) + { + for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn ) + { + sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns; + if( nEntry < nNumberOfEntries ) + { + awt::Size aTextSize( rTextShapes[ nEntry ]->getSize() ); + sal_Int32 nWidth = nSymbolPlusDistanceWidth + aTextSize.Width; + if( nRow==0 ) + rColumnWidths.push_back( nWidth ); + else + rColumnWidths[nColumn] = std::max( nWidth, rColumnWidths[nColumn] ); + } + } + } +} + +void lcl_collectRowHeighs( std::vector< sal_Int32 >& rRowHeights, const sal_Int32 nNumberOfRows, const sal_Int32 nNumberOfColumns, + const std::vector< rtl::Reference >& rTextShapes ) +{ + // calculate maximum height for each row + // and collect column widths + rRowHeights.clear(); + sal_Int32 nNumberOfEntries = rTextShapes.size(); + for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow) + { + sal_Int32 nCurrentRowHeight = 0; + for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn) + { + sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns; + if( nEntry < nNumberOfEntries ) + { + awt::Size aTextSize( rTextShapes[ nEntry ]->getSize() ); + nCurrentRowHeight = std::max( nCurrentRowHeight, aTextSize.Height ); + } + } + rRowHeights.push_back( nCurrentRowHeight ); + } +} + +sal_Int32 lcl_getTextLineHeight( const std::vector< sal_Int32 >& aRowHeights, const sal_Int32 nNumberOfRows, double fViewFontSize ) +{ + const sal_Int32 nFontHeight = static_cast< sal_Int32 >( fViewFontSize ); + if (!nFontHeight) + return 0; + sal_Int32 nTextLineHeight = nFontHeight; + for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow) + { + sal_Int32 nFullTextHeight = aRowHeights[nRow]; + if( ( nFullTextHeight / nFontHeight ) <= 1 ) + { + nTextLineHeight = nFullTextHeight;//found an entry with one line-> have real text height + break; + } + } + return nTextLineHeight; +} + +//returns resulting legend size +awt::Size lcl_placeLegendEntries( + std::vector & rEntries, + css::chart::ChartLegendExpansion eExpansion, + bool bSymbolsLeftSide, + double fViewFontSize, + const awt::Size& rMaxSymbolExtent, + tPropertyValues & rTextProperties, + const rtl::Reference & xTarget, + const awt::Size& rRemainingSpace, + sal_Int32 nYStartPosition, + const awt::Size& rPageSize, + bool bIsPivotChart, + awt::Size& rDefaultLegendSize) +{ + bool bIsCustomSize = (eExpansion == css::chart::ChartLegendExpansion_CUSTOM); + awt::Size aResultingLegendSize(0,0); + // For Pivot charts set the *minimum* legend size as a function of page size. + if ( bIsPivotChart ) + aResultingLegendSize = awt::Size((rPageSize.Width * 13) / 80, (rPageSize.Height * 31) / 90); + if( bIsCustomSize ) + aResultingLegendSize = awt::Size(rRemainingSpace.Width, rRemainingSpace.Height + nYStartPosition); + + // #i109336# Improve auto positioning in chart + sal_Int32 nXPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.33 ) ); + sal_Int32 nXOffset = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.66 ) ); + sal_Int32 nYPadding = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) ); + sal_Int32 nYOffset = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.2 ) ); + + const sal_Int32 nSymbolToTextDistance = static_cast< sal_Int32 >( std::max( 100.0, fViewFontSize * 0.22 ) );//minimum 1mm + const sal_Int32 nSymbolPlusDistanceWidth = rMaxSymbolExtent.Width + nSymbolToTextDistance; + sal_Int32 nMaxTextWidth = rRemainingSpace.Width - nSymbolPlusDistanceWidth; + uno::Any* pFrameWidthAny = PropertyMapper::getValuePointer( rTextProperties.second, rTextProperties.first, u"TextMaximumFrameWidth"); + if(pFrameWidthAny) + { + if( eExpansion == css::chart::ChartLegendExpansion_HIGH ) + { + // limit the width of texts to 30% of the total available width + // #i109336# Improve auto positioning in chart + nMaxTextWidth = rRemainingSpace.Width * 3 / 10; + } + *pFrameWidthAny <<= nMaxTextWidth; + } + + std::vector< rtl::Reference > aTextShapes; + awt::Size aMaxEntryExtent = lcl_createTextShapes( rEntries, xTarget, aTextShapes, rTextProperties ); + OSL_ASSERT( aTextShapes.size() == rEntries.size()); + + sal_Int32 nMaxEntryWidth = nXOffset + nSymbolPlusDistanceWidth + aMaxEntryExtent.Width; + sal_Int32 nMaxEntryHeight = nYOffset + aMaxEntryExtent.Height; + sal_Int32 nNumberOfEntries = rEntries.size(); + + rDefaultLegendSize.Width = nMaxEntryWidth; + rDefaultLegendSize.Height = nMaxEntryHeight + nYPadding; + + sal_Int32 nNumberOfColumns = 0, nNumberOfRows = 0; + std::vector< sal_Int32 > aColumnWidths; + std::vector< sal_Int32 > aRowHeights; + + sal_Int32 nTextLineHeight = static_cast< sal_Int32 >( fViewFontSize ); + + // determine layout depending on LegendExpansion + if( eExpansion == css::chart::ChartLegendExpansion_CUSTOM ) + { + sal_Int32 nCurrentRow=0; + sal_Int32 nCurrentColumn=-1; + sal_Int32 nMaxColumnCount=-1; + for( sal_Int32 nN=0; nN(aTextShapes.size()); nN++ ) + { + rtl::Reference xShape( aTextShapes[nN] ); + if( !xShape.is() ) + continue; + awt::Size aSize( xShape->getSize() ); + sal_Int32 nNewWidth = aSize.Width + nSymbolPlusDistanceWidth; + sal_Int32 nCurrentColumnCount = aColumnWidths.size(); + + //are we allowed to add a new column? + if( nMaxColumnCount==-1 || (nCurrentColumn+1) < nMaxColumnCount ) + { + //try add a new column + nCurrentColumn++; + if( nCurrentColumn < nCurrentColumnCount ) + { + //check whether the current column width is sufficient for the new entry + if( aColumnWidths[nCurrentColumn]>=nNewWidth ) + { + //all good proceed with next entry + continue; + } + + aColumnWidths[nCurrentColumn] = std::max( nNewWidth, aColumnWidths[nCurrentColumn] ); + } else + aColumnWidths.push_back(nNewWidth); + + //do the columns still fit into the given size? + nCurrentColumnCount = aColumnWidths.size();//update count + sal_Int32 nSumWidth = 0; + for (sal_Int32 nColumn = 0; nColumn < nCurrentColumnCount; nColumn++) + nSumWidth += aColumnWidths[nColumn]; + + if( nSumWidth <= rRemainingSpace.Width || nCurrentColumnCount==1 ) + { + //all good proceed with next entry + continue; + } + else + { + //not enough space for the current amount of columns + //try again with less columns + nMaxColumnCount = nCurrentColumnCount-1; + nN=-1; + nCurrentRow=0; + nCurrentColumn=-1; + aColumnWidths.clear(); + } + } + else + { + //add a new row and try the same entry again + nCurrentRow++; + nCurrentColumn=-1; + nN--; + } + } + nNumberOfColumns = aColumnWidths.size(); + nNumberOfRows = nCurrentRow+1; + + //check if there is not enough space so that some entries must be removed + lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes ); + nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize ); + sal_Int32 nSumHeight = 0; + for (sal_Int32 nRow=0; nRow < nNumberOfRows; nRow++) + nSumHeight += aRowHeights[nRow]; + sal_Int32 nRemainingSpace = rRemainingSpace.Height - nSumHeight; + + if( nRemainingSpace < -100 ) // 1mm tolerance for OOXML interop tdf#90404 + { + //remove entries that are too big + for (sal_Int32 nRow = nNumberOfRows; nRow--; ) + { + for (sal_Int32 nColumn = nNumberOfColumns; nColumn--; ) + { + sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns; + if( nEntry < static_cast(aTextShapes.size()) ) + { + DrawModelWrapper::removeShape( aTextShapes[nEntry] ); + aTextShapes.pop_back(); + } + if( nEntry < nNumberOfEntries && ( nEntry != 0 || nNumberOfColumns != 1 ) ) + { + DrawModelWrapper::removeShape( rEntries[ nEntry ].xSymbol ); + rEntries.pop_back(); + nNumberOfEntries--; + } + } + if (nRow == 0 && nNumberOfColumns == 1) + { + try + { + OUString aLabelString = rEntries[0].aLabel[0]->getString(); + static const OUStringLiteral sDots = u"..."; + for (sal_Int32 nNewLen = aLabelString.getLength() - sDots.getLength(); nNewLen > 0; nNewLen--) + { + OUString aNewLabel = aLabelString.subView(0, nNewLen) + sDots; + rtl::Reference xEntry = ShapeFactory::createText( + xTarget, aNewLabel, rTextProperties.first, rTextProperties.second, uno::Any()); + nSumHeight = xEntry->getSize().Height; + nRemainingSpace = rRemainingSpace.Height - nSumHeight; + if (nRemainingSpace >= 0) + { + sal_Int32 nWidth = xEntry->getSize().Width + nSymbolPlusDistanceWidth; + if (rRemainingSpace.Width - nWidth >= 0) + { + aTextShapes.push_back(xEntry); + rEntries[0].aLabel[0]->setString(aNewLabel); + aRowHeights[0] = nSumHeight; + aColumnWidths[0] = nWidth; + break; + } + } + DrawModelWrapper::removeShape(xEntry); + } + if (aTextShapes.size() == 0) + { + DrawModelWrapper::removeShape(rEntries[0].xSymbol); + rEntries.pop_back(); + nNumberOfEntries--; + aRowHeights.pop_back(); + } + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + } + else + { + nSumHeight -= aRowHeights[nRow]; + aRowHeights.pop_back(); + nRemainingSpace = rRemainingSpace.Height - nSumHeight; + if (nRemainingSpace >= 0) + break; + } + } + nNumberOfRows = static_cast(aRowHeights.size()); + } + if( nRemainingSpace >= -100 ) // 1mm tolerance for OOXML interop tdf#90404 + { + sal_Int32 nNormalSpacingHeight = 2*nYPadding+(nNumberOfRows-1)*nYOffset; + if( nRemainingSpace < nNormalSpacingHeight ) + { + //reduce spacing between the entries + nYPadding = nYOffset = nRemainingSpace/(nNumberOfRows+1); + } + else + { + //we have some space left that should be spread equally between all rows + sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingHeight)/(nNumberOfRows+1); + nYPadding += nRemainingSingleSpace; + nYOffset += nRemainingSingleSpace; + } + } + + //check spacing between columns + sal_Int32 nSumWidth = 0; + for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; nColumn++) + nSumWidth += aColumnWidths[nColumn]; + nRemainingSpace = rRemainingSpace.Width - nSumWidth; + if( nRemainingSpace>=0 ) + { + sal_Int32 nNormalSpacingWidth = 2*nXPadding+(nNumberOfColumns-1)*nXOffset; + if( nRemainingSpace < nNormalSpacingWidth ) + { + //reduce spacing between the entries + nXPadding = nXOffset = nRemainingSpace/(nNumberOfColumns+1); + } + else + { + //we have some space left that should be spread equally between all columns + sal_Int32 nRemainingSingleSpace = (nRemainingSpace-nNormalSpacingWidth)/(nNumberOfColumns+1); + nXPadding += nRemainingSingleSpace; + nXOffset += nRemainingSingleSpace; + } + } + } + else if( eExpansion == css::chart::ChartLegendExpansion_HIGH ) + { + sal_Int32 nMaxNumberOfRows = nMaxEntryHeight + ? (rRemainingSpace.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 == css::chart::ChartLegendExpansion_WIDE ) + { + sal_Int32 nMaxNumberOfColumns = nMaxEntryWidth + ? (rRemainingSpace.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 // css::chart::ChartLegendExpansion_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 aResultingLegendSize; + + if( eExpansion != css::chart::ChartLegendExpansion_CUSTOM ) + { + lcl_collectColumnWidths( aColumnWidths, nNumberOfRows, nNumberOfColumns, aTextShapes, nSymbolPlusDistanceWidth ); + lcl_collectRowHeighs( aRowHeights, nNumberOfRows, nNumberOfColumns, aTextShapes ); + nTextLineHeight = lcl_getTextLineHeight( aRowHeights, nNumberOfRows, fViewFontSize ); + } + + sal_Int32 nCurrentXPos = bSymbolsLeftSide ? nXPadding : -nXPadding; + + // place entries into column and rows + sal_Int32 nMaxYPos = 0; + + for (sal_Int32 nColumn = 0; nColumn < nNumberOfColumns; ++nColumn) + { + sal_Int32 nCurrentYPos = nYPadding + nYStartPosition; + for (sal_Int32 nRow = 0; nRow < nNumberOfRows; ++nRow) + { + sal_Int32 nEntry = nColumn + nRow * nNumberOfColumns; + if( nEntry >= nNumberOfEntries ) + break; + + // text shape + rtl::Reference xTextShape( aTextShapes[nEntry] ); + if( xTextShape.is() ) + { + awt::Size aTextSize( xTextShape->getSize() ); + sal_Int32 nTextXPos = nCurrentXPos + nSymbolPlusDistanceWidth; + if( !bSymbolsLeftSide ) + nTextXPos = nCurrentXPos - nSymbolPlusDistanceWidth - aTextSize.Width; + xTextShape->setPosition( awt::Point( nTextXPos, nCurrentYPos )); + } + + // symbol + rtl::Reference & xSymbol( rEntries[ nEntry ].xSymbol ); + if( xSymbol.is() ) + { + awt::Size aSymbolSize( rMaxSymbolExtent ); + sal_Int32 nSymbolXPos = nCurrentXPos; + if( !bSymbolsLeftSide ) + nSymbolXPos = nCurrentXPos - rMaxSymbolExtent.Width; + sal_Int32 nSymbolYPos = nCurrentYPos + ( ( nTextLineHeight - aSymbolSize.Height ) / 2 ); + xSymbol->setPosition( awt::Point( nSymbolXPos, nSymbolYPos ) ); + } + + nCurrentYPos += aRowHeights[ nRow ]; + if( nRow+1 < nNumberOfRows ) + nCurrentYPos += nYOffset; + nMaxYPos = std::max( nMaxYPos, nCurrentYPos ); + } + if( bSymbolsLeftSide ) + { + nCurrentXPos += aColumnWidths[nColumn]; + if( nColumn+1 < nNumberOfColumns ) + nCurrentXPos += nXOffset; + } + else + { + nCurrentXPos -= aColumnWidths[nColumn]; + if( nColumn+1 < nNumberOfColumns ) + nCurrentXPos -= nXOffset; + } + } + + if( !bIsCustomSize ) + { + if( bSymbolsLeftSide ) + aResultingLegendSize.Width = std::max( aResultingLegendSize.Width, nCurrentXPos + nXPadding ); + else + { + sal_Int32 nLegendWidth = -(nCurrentXPos-nXPadding); + aResultingLegendSize.Width = std::max( aResultingLegendSize.Width, nLegendWidth ); + } + aResultingLegendSize.Height = std::max( aResultingLegendSize.Height, nMaxYPos + nYPadding ); + } + + if( !bSymbolsLeftSide ) + { + sal_Int32 nLegendWidth = aResultingLegendSize.Width; + awt::Point aPos(0,0); + for( sal_Int32 nEntry=0; nEntry & xSymbol( rEntries[ nEntry ].xSymbol ); + aPos = xSymbol->getPosition(); + aPos.X += nLegendWidth; + xSymbol->setPosition( aPos ); + rtl::Reference & xText( aTextShapes[ nEntry ] ); + aPos = xText->getPosition(); + aPos.X += nLegendWidth; + xText->setPosition( aPos ); + } + } + + return aResultingLegendSize; +} + +// #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(rOutAvailableSpace.Y)/static_cast(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 ); + + double fDistance = double(rPageSize.Height - (rOutAvailableSpace.Y + rOutAvailableSpace.Height)); + fDistance += fDefaultDistance; + fDistance /= double(rPageSize.Height); + + aResult = chart2::RelativePosition( + 0.5, 1.0 - fDistance, drawing::Alignment_BOTTOM ); + } + break; + case LegendPosition::LegendPosition_MAKE_FIXED_SIZE: + default: + // 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, + const chart2::RelativePosition& rRelPos, + LegendPosition ePos, + const awt::Size& aLegendSize, + bool bOverlay ) +{ + // calculate position + awt::Point aResult( + static_cast< sal_Int32 >( rRelPos.Primary * rPageSize.Width ), + static_cast< sal_Int32 >( rRelPos.Secondary * rPageSize.Height )); + + aResult = RelativePositionHelper::getUpperLeftCornerOfAnchoredObject( + aResult, aLegendSize, rRelPos.Anchor ); + + // adapt rRemainingSpace if LegendPosition is not CUSTOM + // #i109336# Improve auto positioning in chart + sal_Int32 nXDistance = lcl_getLegendLeftRightMargin(); + sal_Int32 nYDistance = lcl_getLegendTopBottomMargin(); + if (!bOverlay) 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; +} + +bool lcl_shouldSymbolsBePlacedOnTheLeftSide( const Reference< beans::XPropertySet >& xLegendProp, sal_Int16 nDefaultWritingMode ) +{ + bool bSymbolsLeftSide = true; + try + { + if( SvtCTLOptions().IsCTLFontEnabled() ) + { + if(xLegendProp.is()) + { + sal_Int16 nWritingMode=-1; + if( xLegendProp->getPropertyValue( "WritingMode" ) >>= nWritingMode ) + { + if( nWritingMode == text::WritingMode2::PAGE ) + nWritingMode = nDefaultWritingMode; + if( nWritingMode == text::WritingMode2::RL_TB ) + bSymbolsLeftSide=false; + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bSymbolsLeftSide; +} + +std::vector> lcl_createButtons( + rtl::Reference const & xLegendContainer, + ChartModel& rModel, bool bPlaceButtonsVertically, tools::Long & nUsedHeight) +{ + std::vector> aButtons; + + uno::Reference xPivotTableDataProvider(rModel.getDataProvider(), uno::UNO_QUERY); + if (!xPivotTableDataProvider.is()) + return aButtons; + + if (!xPivotTableDataProvider->getColumnFields().hasElements()) + return aButtons; + + awt::Size aSize(2000, 700); + int x = 100; + int y = 100; + + const css::uno::Sequence aPivotFieldEntries = xPivotTableDataProvider->getColumnFields(); + for (chart2::data::PivotTableFieldEntry const & sColumnFieldEntry : aPivotFieldEntries) + { + auto pButton = std::make_shared(); + aButtons.push_back(pButton); + pButton->init(xLegendContainer); + awt::Point aNewPosition(x, y); + pButton->setLabel(sColumnFieldEntry.Name); + pButton->setCID("FieldButton.Column." + OUString::number(sColumnFieldEntry.DimensionIndex)); + pButton->setPosition(aNewPosition); + pButton->setSize(aSize); + if (sColumnFieldEntry.Name == "Data") + { + pButton->showArrow(false); + pButton->setBGColor(Color(0x00F6F6F6)); + } + if (sColumnFieldEntry.HasHiddenMembers) + pButton->setArrowColor(Color(0x0000FF)); + + if (bPlaceButtonsVertically) + y += aSize.Height + 100; + else + x += aSize.Width + 100; + } + if (bPlaceButtonsVertically) + nUsedHeight += y + 100; + else + nUsedHeight += aSize.Height + 100; + + return aButtons; +} + +} // anonymous namespace + +VLegend::VLegend( + const rtl::Reference< Legend > & xLegend, + const Reference< uno::XComponentContext > & xContext, + std::vector< LegendEntryProvider* >&& rLegendEntryProviderList, + const rtl::Reference& xTargetPage, + ChartModel& rModel ) + : m_xTarget(xTargetPage) + , m_xLegend(xLegend) + , mrModel(rModel) + , m_xContext(xContext) + , m_aLegendEntryProviderList(std::move(rLegendEntryProviderList)) + , m_nDefaultWritingMode(text::WritingMode2::LR_TB) +{ +} + +void VLegend::setDefaultWritingMode( sal_Int16 nDefaultWritingMode ) +{ + m_nDefaultWritingMode = nDefaultWritingMode; +} + +bool VLegend::isVisible( const rtl::Reference< Legend > & xLegend ) +{ + if( ! xLegend.is()) + return false; + + bool bShow = false; + try + { + xLegend->getPropertyValue( "Show") >>= bShow; + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return bShow; +} + +void VLegend::createShapes( + const awt::Size & rAvailableSpace, + const awt::Size & rPageSize, + awt::Size & rDefaultLegendSize ) +{ + if(! (m_xLegend.is() && m_xTarget.is())) + return; + + try + { + //create shape and add to page + OUString aLegendParticle( ObjectIdentifier::createParticleForLegend( &mrModel ) ); + m_xShape = ShapeFactory::createGroup2D( m_xTarget, + ObjectIdentifier::createClassifiedIdentifierForParticle( aLegendParticle ) ); + + // create and insert sub-shapes + rtl::Reference xLegendContainer = m_xShape; + if( xLegendContainer.is() ) + { + // for quickly setting properties + tPropertyValues aLineFillProperties; + tPropertyValues aTextProperties; + + css::chart::ChartLegendExpansion eExpansion = css::chart::ChartLegendExpansion_HIGH; + awt::Size aLegendSize( rAvailableSpace ); + + bool bCustom = false; + LegendPosition eLegendPosition = LegendPosition_LINE_END; + // get Expansion property + m_xLegend->getPropertyValue("Expansion") >>= eExpansion; + if( eExpansion == css::chart::ChartLegendExpansion_CUSTOM ) + { + RelativeSize aRelativeSize; + if (m_xLegend->getPropertyValue("RelativeSize") >>= aRelativeSize) + { + aLegendSize.Width = static_cast(::rtl::math::approxCeil( aRelativeSize.Primary * rPageSize.Width )); + aLegendSize.Height = static_cast(::rtl::math::approxCeil( aRelativeSize.Secondary * rPageSize.Height )); + bCustom = true; + } + else + { + eExpansion = css::chart::ChartLegendExpansion_HIGH; + } + } + m_xLegend->getPropertyValue("AnchorPosition") >>= eLegendPosition; + lcl_getProperties( m_xLegend, aLineFillProperties, aTextProperties, rPageSize ); + + // create entries + double fViewFontSize = lcl_CalcViewFontSize( m_xLegend, rPageSize );//todo + // #i109336# Improve auto positioning in chart + sal_Int32 nSymbolHeight = static_cast< sal_Int32 >( fViewFontSize * 0.6 ); + sal_Int32 nSymbolWidth = nSymbolHeight; + + for (LegendEntryProvider* pLegendEntryProvider : m_aLegendEntryProviderList) + { + if (pLegendEntryProvider) + { + awt::Size aCurrentRatio = pLegendEntryProvider->getPreferredLegendKeyAspectRatio(); + sal_Int32 nCurrentWidth = aCurrentRatio.Width; + if( aCurrentRatio.Height > 0 ) + { + nCurrentWidth = nSymbolHeight* aCurrentRatio.Width/aCurrentRatio.Height; + } + nSymbolWidth = std::max( nSymbolWidth, nCurrentWidth ); + } + } + awt::Size aMaxSymbolExtent( nSymbolWidth, nSymbolHeight ); + + std::vector aViewEntries; + for(LegendEntryProvider* pLegendEntryProvider : m_aLegendEntryProviderList) + { + if (pLegendEntryProvider) + { + std::vector aNewEntries = pLegendEntryProvider->createLegendEntries( + aMaxSymbolExtent, eLegendPosition, m_xLegend, + xLegendContainer, m_xContext, mrModel); + aViewEntries.insert( aViewEntries.end(), aNewEntries.begin(), aNewEntries.end() ); + } + } + + bool bSymbolsLeftSide = lcl_shouldSymbolsBePlacedOnTheLeftSide( m_xLegend, m_nDefaultWritingMode ); + + uno::Reference xPivotTableDataProvider( mrModel.getDataProvider(), uno::UNO_QUERY ); + bool bIsPivotChart = xPivotTableDataProvider.is(); + + if ( !aViewEntries.empty() || bIsPivotChart ) + { + // create buttons + tools::Long nUsedButtonHeight = 0; + bool bPlaceButtonsVertically = (eLegendPosition != LegendPosition_PAGE_START && + eLegendPosition != LegendPosition_PAGE_END && + eExpansion != css::chart::ChartLegendExpansion_WIDE); + + std::vector> aButtons = lcl_createButtons(xLegendContainer, mrModel, bPlaceButtonsVertically, nUsedButtonHeight); + + // A custom size includes the size we used for buttons already, so we need to + // subtract that from the size that is available for the legend + if (bCustom) + aLegendSize.Height -= nUsedButtonHeight; + + // place the legend entries + aLegendSize = lcl_placeLegendEntries(aViewEntries, eExpansion, bSymbolsLeftSide, fViewFontSize, + aMaxSymbolExtent, aTextProperties, xLegendContainer, + aLegendSize, nUsedButtonHeight, rPageSize, bIsPivotChart, rDefaultLegendSize); + + uno::Reference xModelPage(mrModel.getPageBackground()); + + for (std::shared_ptr const & pButton : aButtons) + { + // adjust the width of the buttons if we place them vertically + if (bPlaceButtonsVertically) + pButton->setSize({aLegendSize.Width - 200, pButton->getSize().Height}); + + // create the buttons + pButton->createShapes(xModelPage); + } + + rtl::Reference xBorder = ShapeFactory::createRectangle( + xLegendContainer, aLegendSize, awt::Point(0, 0), aLineFillProperties.first, + aLineFillProperties.second, ShapeFactory::StackPosition::Bottom); + + //because of this name this border will be used for marking the legend + ShapeFactory::setShapeName(xBorder, "MarkHandles"); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +void VLegend::changePosition( + awt::Rectangle & rOutAvailableSpace, + const awt::Size & rPageSize, + const css::awt::Size & rDefaultLegendSize ) +{ + if(! m_xShape.is()) + return; + + try + { + // determine position and alignment depending on default position + awt::Size aLegendSize = m_xShape->getSize(); + chart2::RelativePosition aRelativePosition; + + bool bDefaultLegendSize = rDefaultLegendSize.Width != 0 || rDefaultLegendSize.Height != 0; + bool bAutoPosition = + ! (m_xLegend->getPropertyValue( "RelativePosition") >>= aRelativePosition); + + LegendPosition ePos = LegendPosition_LINE_END; + m_xLegend->getPropertyValue( "AnchorPosition") >>= ePos; + + bool bOverlay = false; + m_xLegend->getPropertyValue("Overlay") >>= bOverlay; + //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, bOverlay ); + 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, bDefaultLegendSize ? rDefaultLegendSize : aLegendSize, bOverlay ); + m_xShape->setPosition( aPos ); + + if (!bOverlay) + { + // calculate remaining space as if having autoposition: + aRelativePosition = lcl_getDefaultPosition( ePos, rOutAvailableSpace, rPageSize ); + lcl_calculatePositionAndRemainingSpace( + rOutAvailableSpace, rPageSize, aRelativePosition, ePos, bDefaultLegendSize ? rDefaultLegendSize : aLegendSize, bOverlay ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2" ); + } +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VLegend.hxx b/chart2/source/view/main/VLegend.hxx new file mode 100644 index 000000000..f47b21d26 --- /dev/null +++ b/chart2/source/view/main/VLegend.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include +#include +#include +#include + +namespace chart { class ChartModel; } +namespace com::sun::star::awt { struct Rectangle; } +namespace com::sun::star::awt { struct Size; } +namespace com::sun::star::chart2 { class XLegend; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +namespace com::sun::star::uno { class XComponentContext; } + +namespace chart +{ + +class Legend; +class LegendEntryProvider; + +class VLegend +{ +public: + VLegend( const rtl::Reference< ::chart::Legend > & xLegend, + const css::uno::Reference< css::uno::XComponentContext > & xContext, + std::vector< LegendEntryProvider* >&& rLegendEntryProviderList, + const rtl::Reference& xTargetPage, + ChartModel& rModel ); + + void setDefaultWritingMode( sal_Int16 nDefaultWritingMode ); + + void createShapes( const css::awt::Size & rAvailableSpace, + const css::awt::Size & rPageSize, + css::awt::Size & rDefaultLegendSize ); + + /** 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( + css::awt::Rectangle & rOutAvailableSpace, + const css::awt::Size & rReferenceSize, + const css::awt::Size & rDefaultLegendSize ); + + static bool isVisible( + const rtl::Reference< ::chart::Legend > & xLegend ); + +private: + rtl::Reference m_xTarget; + rtl::Reference<::chart::Legend> m_xLegend; + rtl::Reference< SvxShapeGroup > m_xShape; + + ChartModel& mrModel; + + css::uno::Reference< css::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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VLegendSymbolFactory.cxx b/chart2/source/view/main/VLegendSymbolFactory.cxx new file mode 100644 index 000000000..451e32e45 --- /dev/null +++ b/chart2/source/view/main/VLegendSymbolFactory.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::com::sun::star::uno::Reference; + +namespace +{ + +void getPropNamesAndValues( const Reference< beans::XPropertySet >& xProp, + ::chart::tNameSequence& rNames, + ::chart::tAnySequence& rValues, + ::chart::VLegendSymbolFactory::PropertyType ePropertyType, + const awt::Size& aMaxSymbolExtent) +{ + const ::chart::tPropertyNameMap & aFilledSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForFilledSeriesProperties()); + const ::chart::tPropertyNameMap & aLineSeriesNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineSeriesProperties()); + const ::chart::tPropertyNameMap & aLineNameMap( ::chart::PropertyMapper::getPropertyNameMapForLineProperties()); + + ::chart::tPropertyNameValueMap aValueMap; + switch( ePropertyType ) + { + case ::chart::VLegendSymbolFactory::PropertyType::FilledSeries: + ::chart::PropertyMapper::getValueMap( aValueMap, aFilledSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PropertyType::LineSeries: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineSeriesNameMap, xProp ); + break; + case ::chart::VLegendSymbolFactory::PropertyType::Line: + ::chart::PropertyMapper::getValueMap( aValueMap, aLineNameMap, xProp ); + break; + } + + ::chart::PropertyMapper::getMultiPropertyListsFromValueMap( rNames, rValues, aValueMap ); + + uno::Any* pLineWidthAny = ::chart::PropertyMapper::getValuePointer(rValues,rNames,u"LineWidth"); + sal_Int32 nLineWidth = 0; + if( pLineWidthAny && (*pLineWidthAny>>=nLineWidth) ) + { + // use legend entry height as upper limit for line width + sal_Int32 nMaxLineWidthForLegend = aMaxSymbolExtent.Height; + if( nLineWidth>nMaxLineWidthForLegend ) + *pLineWidthAny <<= nMaxLineWidthForLegend; + } +} + +void lcl_setPropertiesToShape( + const Reference< beans::XPropertySet > & xProp, + const rtl::Reference< SvxShape > & xShape, + ::chart::VLegendSymbolFactory::PropertyType ePropertyType, + const awt::Size& aMaxSymbolExtent) +{ + ::chart::tNameSequence aPropNames; + ::chart::tAnySequence aPropValues; + getPropNamesAndValues( xProp, aPropNames, aPropValues, + ePropertyType, aMaxSymbolExtent ); + + ::chart::PropertyMapper::setMultiProperties( aPropNames, aPropValues, *xShape ); +} + +} // anonymous namespace + +namespace chart +{ + +rtl::Reference< SvxShapeGroup > VLegendSymbolFactory::createSymbol( + const awt::Size& rEntryKeyAspectRatio, + const rtl::Reference& rSymbolContainer, + LegendSymbolStyle eStyle, + const Reference< beans::XPropertySet > & xLegendEntryProperties, + PropertyType ePropertyType, const uno::Any& rExplicitSymbol ) +{ + rtl::Reference< SvxShapeGroup > xResult; + + if( !rSymbolContainer) + return xResult; + + xResult = ShapeFactory::createGroup2D( rSymbolContainer ); + if( ! xResult) + return xResult; + + rtl::Reference xResultGroup = xResult; + + // add an invisible square box to maintain aspect ratio + ShapeFactory::createInvisibleRectangle( xResultGroup, rEntryKeyAspectRatio ); + + // create symbol + try + { + if( eStyle == LegendSymbolStyle::Line ) + { + rtl::Reference xLine = + ShapeFactory::createLine( xResultGroup, awt::Size( rEntryKeyAspectRatio.Width, 0 ), + awt::Point( 0, rEntryKeyAspectRatio.Height/2 )); + lcl_setPropertiesToShape( xLegendEntryProperties, xLine, ePropertyType, rEntryKeyAspectRatio ); + + const sal_Int32 nSize = std::min(rEntryKeyAspectRatio.Width,rEntryKeyAspectRatio.Height); + chart2::Symbol aSymbol; + if( rExplicitSymbol >>= aSymbol ) + { + drawing::Direction3D aSymbolSize( nSize, nSize, 0 ); + drawing::Position3D aPos( rEntryKeyAspectRatio.Width/2.0, rEntryKeyAspectRatio.Height/2.0, 0 ); + if( aSymbol.Style == chart2::SymbolStyle_STANDARD ) + { + // take series color as fill color + xLegendEntryProperties->getPropertyValue( "Color") >>= aSymbol.FillColor; + // border of symbols always same as fill color + aSymbol.BorderColor = aSymbol.FillColor; + + ShapeFactory::createSymbol2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.StandardSymbol, + aSymbol.BorderColor, + aSymbol.FillColor ); + } + else if( aSymbol.Style == chart2::SymbolStyle_GRAPHIC ) + { + ShapeFactory::createGraphic2D( + xResultGroup, + aPos, + aSymbolSize, + aSymbol.Graphic ); + } + else if( aSymbol.Style == chart2::SymbolStyle_AUTO ) + { + SAL_WARN("chart2", "the given parameter is not allowed to contain an automatic symbol style"); + } + } + } + else if( eStyle == LegendSymbolStyle::Circle ) + { + sal_Int32 nSize = std::min( rEntryKeyAspectRatio.Width, rEntryKeyAspectRatio.Height ); + rtl::Reference xShape = + ShapeFactory::createCircle( xResultGroup, awt::Size( nSize, nSize ), + awt::Point( rEntryKeyAspectRatio.Width/2-nSize/2, rEntryKeyAspectRatio.Height/2-nSize/2 )); + lcl_setPropertiesToShape( xLegendEntryProperties, xShape, ePropertyType, awt::Size(0,0) ); // PropertyType::FilledSeries ); + } + else // eStyle == LegendSymbolStyle::Box + { + tNameSequence aPropNames; + tAnySequence aPropValues; + + getPropNamesAndValues( xLegendEntryProperties, aPropNames, aPropValues, + ePropertyType, awt::Size(0,0) );// PropertyType::FilledSeries + + ShapeFactory::createRectangle( xResultGroup, + rEntryKeyAspectRatio, awt::Point( 0, 0 ), + aPropNames, aPropValues ); + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + + return xResult; +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VLineProperties.cxx b/chart2/source/view/main/VLineProperties.cxx new file mode 100644 index 000000000..49a3b4e77 --- /dev/null +++ b/chart2/source/view/main/VLineProperties.cxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; + +// get line properties from a propertyset + +VLineProperties::VLineProperties() +{ + Color <<= sal_Int32(0x000000); //type sal_Int32 UNO_NAME_LINECOLOR + LineStyle + <<= drawing::LineStyle_SOLID; //type drawing::LineStyle for property UNO_NAME_LINESTYLE + Transparence <<= sal_Int16(0); //type sal_Int16 for property UNO_NAME_LINETRANSPARENCE + Width <<= sal_Int32(0); //type sal_Int32 for property UNO_NAME_LINEWIDTH + LineCap <<= drawing::LineCap_BUTT; //type drawing::LineCap for property UNO_NAME_LINECAP +} + +void VLineProperties::initFromPropertySet(const uno::Reference& xProp) +{ + if (xProp.is()) + { + try + { + Color = xProp->getPropertyValue("LineColor"); + LineStyle = xProp->getPropertyValue("LineStyle"); + Transparence = xProp->getPropertyValue("LineTransparence"); + Width = xProp->getPropertyValue("LineWidth"); + DashName = xProp->getPropertyValue("LineDashName"); + LineCap = xProp->getPropertyValue("LineCap"); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("chart2", ""); + } + } + else + LineStyle <<= drawing::LineStyle_NONE; +} + +bool VLineProperties::isLineVisible() const +{ + bool bRet = false; + + drawing::LineStyle aLineStyle(drawing::LineStyle_SOLID); + LineStyle >>= aLineStyle; + if (aLineStyle != drawing::LineStyle_NONE) + { + sal_Int16 nLineTransparence = 0; + Transparence >>= nLineTransparence; + if (nLineTransparence != 100) + { + bRet = true; + } + } + + return bRet; +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VPolarTransformation.cxx b/chart2/source/view/main/VPolarTransformation.cxx new file mode 100644 index 000000000..9ec2eea3f --- /dev/null +++ b/chart2/source/view/main/VPolarTransformation.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Sequence; + +namespace chart +{ + +VPolarTransformation::VPolarTransformation( const PolarPlottingPositionHelper& rPositionHelper ) + : m_aPositionHelper(rPositionHelper) + , m_aUnitCartesianToScene( rPositionHelper.getUnitCartesianToScene() ) +{ +} + +VPolarTransformation::~VPolarTransformation() +{ +} + +// ____ XTransformation2 ____ +css::drawing::Position3D VPolarTransformation::transform( + const Sequence< double >& rSourceValues ) const +{ + 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 = basegfx::deg2rad(fAngleDegree); + 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 css::drawing::Position3D(aRet.getX(), aRet.getY(), aRet.getZ()); +} + +css::drawing::Position3D VPolarTransformation::transform( + const css::drawing::Position3D& rSourceValues ) const +{ + double fScaledLogicAngle = rSourceValues.PositionX; + double fScaledLogicRadius = rSourceValues.PositionY; + + if( m_aPositionHelper.isSwapXAndY() ) + std::swap(fScaledLogicAngle,fScaledLogicRadius); + + double fAngleDegree = m_aPositionHelper.transformToAngleDegree( fScaledLogicAngle, false ); + double fAnglePi = basegfx::deg2rad(fAngleDegree); + double fRadius = m_aPositionHelper.transformToRadius( fScaledLogicRadius, false); + + double fX=fRadius*cos(fAnglePi); + double fY=fRadius*sin(fAnglePi); + double fZ=rSourceValues.PositionZ; + + //!! 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 css::drawing::Position3D(aRet.getX(), aRet.getY(), aRet.getZ()); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VTitle.cxx b/chart2/source/view/main/VTitle.cxx new file mode 100644 index 000000000..74d276742 --- /dev/null +++ b/chart2/source/view/main/VTitle.cxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "VTitle.hxx" +#include +#include +#include +#include +#include + +namespace chart +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::chart2; + +VTitle::VTitle( const uno::Reference< XTitle > & xTitle ) + : m_xTitle(xTitle) + , m_fRotationAngleDegree(0.0) + , m_nXPos(0) + , m_nYPos(0) +{ +} + +VTitle::~VTitle() +{ +} + +void VTitle::init( + const rtl::Reference& xTargetPage + , const OUString& rCID ) +{ + m_xTarget = xTargetPage; + m_aCID = rCID; +} + +double VTitle::getRotationAnglePi() const +{ + return basegfx::deg2rad(m_fRotationAngleDegree); +} + +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; + 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( basegfx::deg2rad(-m_fRotationAngleDegree) );//#i78696#->#i80521# + aM.translate( m_nXPos, m_nYPos); + m_xShape->SvxShape::setPropertyValue( "Transformation", uno::Any( B2DHomMatrixToHomogenMatrix3(aM) ) ); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } +} + +bool VTitle::isVisible(const uno::Reference< XTitle >& xTitle) { + if (!xTitle.is()) { + return false; + } + bool bShow = true; + try { + uno::Reference< beans::XPropertySet > xTitleProps(xTitle, uno::UNO_QUERY_THROW); + xTitleProps->getPropertyValue("Visible") >>= bShow; + } catch (const uno::Exception &) { + DBG_UNHANDLED_EXCEPTION("chart2"); + } + return bShow; +} + + +void VTitle::createShapes( + const awt::Point& rPos + , const awt::Size& rReferenceSize + , const awt::Size& rTextMaxWidth + , bool bYAxisTitle ) +{ + if(!m_xTitle.is()) + return; + + uno::Sequence< uno::Reference< XFormattedString > > aStringList = m_xTitle->getText(); + if(!aStringList.hasElements()) + return; + + m_nXPos = rPos.X; + m_nYPos = rPos.Y; + + uno::Reference< beans::XPropertySet > xTitleProperties( m_xTitle, uno::UNO_QUERY ); + + try + { + double fAngleDegree = 0; + xTitleProperties->getPropertyValue( "TextRotation" ) >>= fAngleDegree; + m_fRotationAngleDegree += fAngleDegree; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + sal_Int32 nTextMaxWidth; + if (bYAxisTitle) + { + if (m_fRotationAngleDegree < 75.0 || m_fRotationAngleDegree > 285.0 + || (m_fRotationAngleDegree > 105.0 && m_fRotationAngleDegree < 255.0)) + nTextMaxWidth = rTextMaxWidth.Width; + else + nTextMaxWidth = rTextMaxWidth.Height; + } + else if (m_fRotationAngleDegree <= 15.0 || m_fRotationAngleDegree >= 345.0 + || (m_fRotationAngleDegree >= 165.0 && m_fRotationAngleDegree <= 195.0)) + nTextMaxWidth = rTextMaxWidth.Width; + else + nTextMaxWidth = rTextMaxWidth.Height; + + m_xShape = ShapeFactory::createText( m_xTarget, rReferenceSize, rPos, aStringList, xTitleProperties, + m_fRotationAngleDegree, m_aCID, nTextMaxWidth ); +} + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/VTitle.hxx b/chart2/source/view/main/VTitle.hxx new file mode 100644 index 000000000..566128b95 --- /dev/null +++ b/chart2/source/view/main/VTitle.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::awt { struct Point; } +namespace com::sun::star::chart2 { class XTitle; } +namespace com::sun::star::drawing { class XShape; } +namespace com::sun::star::drawing { class XShapes; } +namespace com::sun::star::lang { class XMultiServiceFactory; } +class SvxShapeText; + +namespace chart +{ + +class VTitle final +{ +public: + explicit VTitle( const css::uno::Reference< css::chart2::XTitle > & xTitle ); + ~VTitle(); + + void init( const rtl::Reference& xTargetPage + , const OUString& rCID ); + + void createShapes( const css::awt::Point& rPos + , const css::awt::Size& rReferenceSize + , const css::awt::Size& nTextMaxWidth + , bool bYAxisTitle ); + + double getRotationAnglePi() const; + css::awt::Size getUnrotatedSize() const; + css::awt::Size getFinalSize() const; + void changePosition( const css::awt::Point& rPos ); + static bool isVisible( + const css::uno::Reference< css::chart2::XTitle > & xTitle); + +private: + rtl::Reference m_xTarget; + css::uno::Reference< css::chart2::XTitle > m_xTitle; + rtl::Reference m_xShape; + OUString m_aCID; + + double m_fRotationAngleDegree; + sal_Int32 m_nXPos; + sal_Int32 m_nYPos; +}; + +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3