chart2: offer the correlation circle plot in the chart type dialog

The entry sits next to the bubble chart, under the same switch that keeps the
chart types wanting free x values out of the list where they do not belong. It
has one sub type, no three dimensional look and no stacking.

The two images are placeholders: a circle with a cross and a few arrows
out of the middle. They need a designer's hand before this ships.

A test drives the wizard the way a user would: it picks the type, types one
range whose last two columns hold the dimensions, and checks that every column
before them became a series holding that column beside the two dimension
columns. A second test reopens the ranges of that chart and checks the range
comes back as it was given.

Change-Id: If8b5275244a2456a22235a6ce2d3d51fcff6cb94
Signed-off-by: Dennis Francis <dennis.francis@collabora.com>
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/8104
Reviewed-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
(cherry picked from commit 7a7fc603047e065ebbc20f8bc5dc814d6079e082)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210469
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
This commit is contained in:
Dennis Francis
2026-09-04 11:43:03 +02:00
committed by Xisco Fauli
parent 88abba97c6
commit 22adaa8073
11 changed files with 204 additions and 3 deletions
+4
View File
@@ -22,6 +22,10 @@ inline constexpr OUString BMP_TYPE_STOCK = u"chart2/res/typestock_16.png"_ustr;
inline constexpr OUString BMP_TYPE_COLUMN_LINE = u"chart2/res/typecolumnline_16.png"_ustr;
inline constexpr OUString BMP_TYPE_BUBBLE = u"chart2/res/typebubble_16.png"_ustr;
inline constexpr OUString BMP_BUBBLE_1 = u"chart2/res/bubble_52x60.png"_ustr;
inline constexpr OUString BMP_TYPE_CORRELATION_CIRCLE
= u"chart2/res/typecorrelationcircle_16.png"_ustr;
inline constexpr OUString BMP_CORRELATION_CIRCLE
= u"chart2/res/correlationcircle_52x60.png"_ustr;
inline constexpr OUString BMP_AREAS_2D = u"chart2/res/areas_52x60.png"_ustr;
inline constexpr OUString BMP_AREAS_2D_1 = u"chart2/res/areaspiled_52x60.png"_ustr;
inline constexpr OUString BMP_AREAS_2D_3 = u"chart2/res/areasfull_52x60.png"_ustr;
+2
View File
@@ -173,6 +173,8 @@
#define STR_FILLED NC_("STR_FILLED", "Filled")
#define STR_TYPE_BUBBLE NC_("STR_TYPE_BUBBLE", "Bubble")
#define STR_BUBBLE_1 NC_("STR_BUBBLE_1", "Bubble Chart")
#define STR_TYPE_CORRELATION_CIRCLE NC_("STR_TYPE_CORRELATION_CIRCLE", "Correlation Circle")
#define STR_CORRELATION_CIRCLE NC_("STR_CORRELATION_CIRCLE", "Correlation Circle Plot")
#define STR_INVALID_NUMBER NC_("STR_INVALID_NUMBER", "Numbers are required. Check your input.")
#define STR_STEP_GT_ZERO NC_("STR_STEP_GT_ZERO", "The major interval requires a positive number. Check your input.")
@@ -1431,6 +1431,56 @@ void CombiColumnLineChartDialogController::adjustParameterToSubType( ChartTypePa
}
}
//=========
// CorrelationCircleChartDialogController
//=========
CorrelationCircleChartDialogController::CorrelationCircleChartDialogController()
{
bSupports3D = false;
}
CorrelationCircleChartDialogController::~CorrelationCircleChartDialogController()
{
}
OUString CorrelationCircleChartDialogController::getName()
{
return SchResId(STR_TYPE_CORRELATION_CIRCLE);
}
OUString CorrelationCircleChartDialogController::getImage()
{
return BMP_TYPE_CORRELATION_CIRCLE;
}
const tTemplateServiceChartTypeParameterMap&
CorrelationCircleChartDialogController::getTemplateMap() const
{
static const tTemplateServiceChartTypeParameterMap s_aTemplateMap{
{"com.sun.star.chart2.template.CorrelationCircle" , ChartTypeParameter(1,true)}};
return s_aTemplateMap;
}
void CorrelationCircleChartDialogController::fillSubTypeList( ValueSet& rSubTypeList, const ChartTypeParameter& /*rParameter*/ )
{
rSubTypeList.Clear();
rSubTypeList.InsertItem(1, Image(StockImage::Yes, BMP_CORRELATION_CIRCLE));
rSubTypeList.SetItemText(1, SchResId(STR_CORRELATION_CIRCLE));
}
void CorrelationCircleChartDialogController::adjustParameterToSubType( ChartTypeParameter& rParameter )
{
rParameter.b3DLook = false;
rParameter.eStackMode = GlobalStackMode_NONE;
rParameter.bXAxisWithValues = true;
}
//=========
// BubbleChartDialogController
//=========
BubbleChartDialogController::BubbleChartDialogController()
{
}
@@ -427,6 +427,10 @@ OUString SeriesHeader::GetChartTypeImage(
{
aResult = BMP_TYPE_BUBBLE;
}
else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_CORRELATIONCIRCLE )
{
aResult = BMP_TYPE_CORRELATION_CIRCLE;
}
return aResult;
}
@@ -112,6 +112,8 @@ ChartTypeTabPage::ChartTypeTabPage(weld::Container* pPage, weld::DialogControlle
m_aChartTypeDialogControllerList.push_back(std::make_unique<XYChartDialogController>());
m_aChartTypeDialogControllerList.push_back(
std::make_unique<BubbleChartDialogController>());
m_aChartTypeDialogControllerList.push_back(
std::make_unique<CorrelationCircleChartDialogController>());
}
m_aChartTypeDialogControllerList.push_back(std::make_unique<NetChartDialogController>());
if (bEnableComplexChartTypes)
@@ -348,6 +348,20 @@ private:
std::unique_ptr<weld::SpinButton> m_xMF_NumberOfLines;
};
class CorrelationCircleChartDialogController final : public ChartTypeDialogController
{
public:
CorrelationCircleChartDialogController();
virtual ~CorrelationCircleChartDialogController() 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 BubbleChartDialogController final : public ChartTypeDialogController
{
public:
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

+105
View File
@@ -0,0 +1,105 @@
# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
#
# Copyright the LibreOffice contributors.
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
from uitest.framework import UITestCase
from uitest.uihelper.common import get_state_as_dict
from uitest.uihelper.chart import select_chart_type
from libreoffice.uno.propertyvalue import mkPropertyValues
FEATURES = ["length", "width", "span", "mass"]
DIMENSIONS = ["dim 1", "dim 2"]
INSTANCE_COUNT = 8
RANGE = "$Sheet1.$A$1:$F$9"
class correlationCircle(UITestCase):
def fill_sheet(self, document):
sheet = document.Sheets[0]
for column, name in enumerate(FEATURES + DIMENSIONS):
sheet.getCellByPosition(column, 0).setString(name)
for row in range(INSTANCE_COUNT):
for column in range(len(FEATURES)):
sheet.getCellByPosition(column, row + 1).setValue(row + column * 3 + 1)
for column in range(len(DIMENSIONS)):
sheet.getCellByPosition(len(FEATURES) + column, row + 1).setValue(
(row + 1) * (column + 1) * 0.25)
def replace_text(self, xEntry, rText):
xEntry.executeAction("TYPE", mkPropertyValues({"KEYCODE": "CTRL+A"}))
xEntry.executeAction("TYPE", mkPropertyValues({"KEYCODE": "BACKSPACE"}))
xEntry.executeAction("TYPE", mkPropertyValues({"TEXT": rText}))
def insert_correlation_circle(self, document):
with self.ui_test.execute_dialog_through_command(
".uno:InsertObjectChart", close_button="finish") as xChartDlg:
select_chart_type(self, xChartDlg, "Correlation Circle")
# The second wizard step holds the range.
xChartDlg.getChild("next").executeAction("CLICK", tuple())
self.replace_text(xChartDlg.getChild("ED_RANGE"), RANGE)
# Every column of the range before the last two is a feature, so
# the first one is not a column of instance names.
xFirstColumnAsLabel = xChartDlg.getChild("CB_FIRST_COLUMN_ASLABELS")
if get_state_as_dict(xFirstColumnAsLabel)["Selected"] == "true":
xFirstColumnAsLabel.executeAction("CLICK", tuple())
def roles_of_series(self, document):
xChartType = document.Sheets[0].Charts[0].getEmbeddedObject() \
.getFirstDiagram().CoordinateSystems[0].ChartTypes[0]
return [[(sequence.getValues().Role,
sequence.getValues().getSourceRangeRepresentation())
for sequence in series.getDataSequences()]
for series in xChartType.DataSeries]
# The last two columns of the range hold the dimensions and every column
# before them becomes a series holding that column beside those two.
def test_correlation_circle_one_range(self):
with self.ui_test.create_doc_in_start_center("calc") as document:
self.fill_sheet(document)
self.insert_correlation_circle(document)
aRolesPerSeries = self.roles_of_series(document)
self.assertEqual(len(FEATURES), len(aRolesPerSeries))
for index, aRoles in enumerate(aRolesPerSeries):
aColumn = chr(ord("A") + index)
self.assertEqual(
[("values-x", "$Sheet1.$E$2:$E$9"),
("values-y", "$Sheet1.$F$2:$F$9"),
("values-feature", "$Sheet1.$%s$2:$%s$9" % (aColumn, aColumn))],
aRoles)
# Reopening the ranges of such a chart shows the range it was given.
def test_the_range_comes_back(self):
with self.ui_test.create_doc_in_start_center("calc") as document:
self.fill_sheet(document)
self.insert_correlation_circle(document)
xCalcDoc = self.xUITest.getTopFocusWindow()
xGridWindow = xCalcDoc.getChild("grid_window")
xGridWindow.executeAction("SELECT", mkPropertyValues({"OBJECT": "Object 1"}))
xGridWindow.executeAction("ACTIVATE", tuple())
xChartWindow = self.xUITest.getTopFocusWindow().getChild("chart_window")
with self.ui_test.execute_dialog_through_action(
xChartWindow.getChild("CID/Page="), "COMMAND",
mkPropertyValues({"COMMAND": "DataRanges"}),
close_button="cancel") as xRangesDlg:
self.assertEqual(
RANGE, get_state_as_dict(xRangesDlg.getChild("ED_RANGE"))["Text"])
# Leave the chart, so that the document closes the way it would
# after any other edit.
xChartWindow.executeAction("TYPE", mkPropertyValues({"KEYCODE": "ESC"}))
# vim: set shiftwidth=4 softtabstop=4 expandtab:
+2 -3
View File
@@ -9,6 +9,7 @@
from libreoffice.uno.propertyvalue import mkPropertyValues
from uitest.uihelper.common import get_state_as_dict
from uitest.uihelper.chart import select_chart_type
from uitest.framework import UITestCase
@@ -27,9 +28,7 @@ class tdf138556( UITestCase ):
#Change Chart Type to Stock 1
#TODO: test other subtypes
with self.ui_test.execute_dialog_through_action( xChart, "COMMAND", mkPropertyValues({ "COMMAND" : "DiagramType" })) as xDialog:
xChartType = xDialog.getChild( "charttype" )
xStockType = xChartType.getChild("9")
xStockType.executeAction( "SELECT", tuple())
select_chart_type(self, xDialog, "Stock")
#Insert Data Series
with self.ui_test.execute_dialog_through_action( xChart, "COMMAND", mkPropertyValues({ "COMMAND" : "DiagramData" }), close_button="close") as xDialog:
+21
View File
@@ -0,0 +1,21 @@
# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
#
# Copyright the LibreOffice contributors.
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
from libreoffice.uno.propertyvalue import mkPropertyValues
from uitest.uihelper.common import get_state_as_dict
def select_chart_type(testCase, xDialog, rName):
xTypeList = xDialog.getChild("charttype")
for index in range(int(get_state_as_dict(xTypeList)["Children"])):
xEntry = xTypeList.getChild(str(index))
if get_state_as_dict(xEntry)["Text"] == rName:
xEntry.executeAction("SELECT", mkPropertyValues({}))
return
testCase.fail("the chart type dialog offers no " + rName)