diff --git a/Modules/Chart/CMakeLists.txt b/Modules/Chart/CMakeLists.txt index 09bd55d774..c233ff4980 100644 --- a/Modules/Chart/CMakeLists.txt +++ b/Modules/Chart/CMakeLists.txt @@ -1,6 +1,4 @@ MITK_CREATE_MODULE( DEPENDS MitkCore - PACKAGE_DEPENDS PUBLIC Qt5|WebEngineWidgets -) - -add_subdirectory(test) \ No newline at end of file + PACKAGE_DEPENDS PRIVATE Qt5|WebEngineWidgets +) \ No newline at end of file diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index 7a388fc155..830f56d8a2 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,231 +1,220 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkC3jsWidget_h #define QmitkC3jsWidget_h #include #include #include #include -class QmitkChartxyData; -class QmitkChartData; - /*! \brief QmitkChartWidget is a widget to display various charts based on the javascript chart library C3js. * \details Data is added via AddData1D() or AddData2D().\n * There can be multiple charts (of different types with different properties) created by calling AddData1D or AddData2D multiple times.\n\n * The following chart types are supported: * * line chart: http://c3js.org/samples/simple_multiple.html * * bar chart: http://c3js.org/samples/chart_bar.html * * spline chart: http://c3js.org/samples/chart_spline.html * * pie chart: http://c3js.org/samples/chart_pie.html * * scatter chart: http://c3js.org/samples/chart_scatter.html * * area chart: http://c3js.org/samples/chart_area.html * * area spline chart: http://c3js.org/samples/chart_area.html * * Technical details: The javascript code is embedded in a QWebEngineView. The actual js code is implemented in resource\Chart.js. * \sa http://c3js.org for further information about the used javaScript library. * \ingroup Modules/Chart */ class MITKCHART_EXPORT QmitkChartWidget : public QWidget { Q_OBJECT public: /*! * \brief enum of diagram types. */ enum class ChartType { bar, /*!< bar chart, see http://c3js.org/samples/chart_bar.html */ line, /*!< line chart, see http://c3js.org/samples/simple_multiple.html */ spline, /*!< spline chart (smoothed line chart), see http://c3js.org/samples/chart_spline.html */ pie, /*!< pie chart, see http://c3js.org/samples/chart_pie.html*/ area, /*!< area chart, see http://c3js.org/samples/chart_area.html*/ area_spline, /*!< area-spline chart, see http://c3js.org/samples/chart_area.html*/ scatter /*!< scatter chart, see http://c3js.org/samples/chart_scatter.html*/ }; /*! * \brief enum of chart style (modifies background and line color). */ enum class ChartStyle { darkstyle, /*!< background color: dark gray, line color: blue */ lightstyle /*!< background color: white, line color: blue */ }; enum class LineStyle { solid, dashed }; enum class AxisScale { linear, log }; /*! * \brief enum of legend position. * See http://c3js.org/reference.html#legend-position */ enum class LegendPosition { bottom, right, inset }; explicit QmitkChartWidget(QWidget* parent = nullptr); //for UnitTests explicit QmitkChartWidget(QWidget *parent, bool unitTest); ~QmitkChartWidget() override; /*! * \brief Adds 1D data to the widget * \details internally, the list is converted to a map with increasing integers keys starting at 0. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData1D(const std::vector& data1D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Adds 2D data to the widget. Call repeatedly for displaying multiple charts. * \details each entry represents a data point: key: value --> x-value: y-value. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData2D(const std::map& data2D, const std::string& label, ChartType chartType = ChartType::bar); - /*! - * \brief Get the data that is stored for displaying. - * \note Only needed for testing purposes. - */ - std::vector> * GetData() const; - - QmitkChartData * GetC3Data() const; - /*! * \brief Removes data from the widget, works for 1D and 2D Data * \param label the name of the data that is also used as identifier. * \note All data can be cleared with ClearDiagram() * \throws Invalid Argument Exception when the label cannot be found */ void RemoveData(const std::string& label); /*! * \brief Sets the color of one data entry (identifier is previously assigned label) * \details the color name can be "red" or a hex number (#FF0000). * \warning Either define all data entries with a color or no data entry. If a mixed approach is used, * C3 choses the color of the data entry (that could be the same as a user defined color). * \note If an unknown label is given, nothing happens. * \sa https://www.w3schools.com/cssref/css_colors.asp */ void SetColor(const std::string& label, const std::string& colorName); /*! * \brief Sets the line style of one data entry (identifier is previously assigned label) * \details two line styles are possible: LineStyle::solid and LineStyle::dashed. * The default line style is solid. * \note If an unknown label is given, nothing happens. * \warning only sets the line style if the current chart type is ChartType::line. * However, the line style remains also if the chart changes (e.g. new chart type) */ void SetLineStyle(const std::string& label, LineStyle style); /*! * \brief Sets the axis scale to either linear (default) or logarithmic. */ void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); /*! * \brief Sets a title for the chart. */ void SetTitle(const std::string &title); /*! * \brief Changes the chart type for all data entries and reloads the chart */ void SetChartTypeForAllDataAndReload(ChartType type); /*! * \brief Sets the chart type for a data entry * \details for available types, see ChartType * \note If an unknown label is given, nothing happens. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. * \sa DiagramType for available types */ void SetChartType(const std::string& label, ChartType type); /*! * \brief Sets the legend position. * \details Default position is bottom. * \sa LegendPosition for available types */ void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); void SetStackedData(bool stacked); /*! * \brief Displays the chart in the widget * \param showSubChart if a subchart is displayed inside the widget or not (see http://c3js.org/samples/options_subchart.html). * \exception if no data has been provided (\sa AddData1D AddData2D) */ void Show(bool showSubChart=false); /*! * \brief Either displays the dataPoints or not * \param showDataPoints if dataPoints are displayed inside the widget or not. * \details: example for not showing points: http://c3js.org/samples/point_show.html * example for showing the points: http://c3js.org/samples/simple_multiple.html */ void SetShowDataPoints(bool showDataPoints); /*! * \brief Clears all data inside and resets the widget. */ void Clear(); /*! * \brief Changes the theme of the widget. */ void SetTheme(ChartStyle themeEnabled); /*! * \brief Reloads the chart in the widget * \details reloading may be needed to display added data in an existing chart * \param showSubChart if a subchart is displayed inside the widget or not. */ void Reload(bool showSubChart); public slots: void OnLoadFinished(bool isLoadSuccessful); signals: void PageSuccessfullyLoaded(); private: class Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 9048356bb9..178bcfdabb 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,545 +1,507 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include "mitkExceptionMacro.h" #include #include class QmitkChartWidget::Impl final { public: - explicit Impl(QWidget *parent, bool unitTest); explicit Impl(QWidget *parent); ~Impl(); Impl(const Impl &) = delete; Impl &operator=(const Impl &) = delete; void AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType chartType); void AddData2D(const std::map &data2D, const std::string &label, QmitkChartWidget::ChartType chartType); void RemoveData(const std::string &label); void ClearData(); void SetColor(const std::string &label, const std::string &colorName); void SetLineStyle(const std::string &label, LineStyle style); void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string &label); void SetYAxisLabel(const std::string &label); void SetTitle(const std::string &title); void SetChartType(QmitkChartWidget::ChartType chartType); void SetChartTypeByLabel(const std::string &label, QmitkChartWidget::ChartType chartType); void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); void SetStackedData(bool stacked); void Show(bool showSubChart); void SetShowDataPoints(bool showDataPoints = false); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString &command); - // for testing - QmitkChartData *GetC3Data(); - std::vector> *GetC3xyData(); - private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList &labelList, const std::string &label) const; QmitkChartxyData *GetDataElementByLabel(const std::string &label) const; QList GetDataLabels(const ChartxyDataVector &c3xyData) const; void MapTypes(); QWebChannel *m_WebChannel; QWebEngineView *m_WebEngineView; QmitkChartData m_C3Data; ChartxyDataVector m_C3xyData; std::map m_ChartTypeToName; std::map m_LegendPositionToName; std::map m_LineStyleToName; std::map m_AxisScaleToName; }; QmitkChartWidget::Impl::Impl(QWidget *parent) - : m_WebChannel(new QWebChannel(parent)), m_WebEngineView(new QWebEngineView(parent)) + : m_WebChannel(new QWebChannel(parent)), + m_WebEngineView(new QWebEngineView(parent)) { // disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); // Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); parent->setLayout(layout); - MapTypes(); -} - -QmitkChartWidget::Impl::Impl(QWidget *parent, bool unitTest) -{ - MapTypes(); -} - -void QmitkChartWidget::Impl::MapTypes() -{ m_ChartTypeToName.emplace(ChartType::bar, "bar"); m_ChartTypeToName.emplace(ChartType::line, "line"); m_ChartTypeToName.emplace(ChartType::spline, "spline"); m_ChartTypeToName.emplace(ChartType::pie, "pie"); m_ChartTypeToName.emplace(ChartType::area, "area"); m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline"); m_ChartTypeToName.emplace(ChartType::scatter, "scatter"); m_LegendPositionToName.emplace(LegendPosition::bottom, "bottom"); m_LegendPositionToName.emplace(LegendPosition::right, "right"); m_LegendPositionToName.emplace(LegendPosition::inset, "inset"); m_LineStyleToName.emplace(LineStyle::solid, "solid"); m_LineStyleToName.emplace(LineStyle::dashed, "dashed"); m_AxisScaleToName.emplace(AxisScale::linear, ""); m_AxisScaleToName.emplace(AxisScale::log, "log"); } QmitkChartWidget::Impl::~Impl() {} std::string CheckForCorrectHex(const std::string &colorName) { std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); std::smatch match; if (!colorName.empty() && colorName.at(0) != '#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) { return "#" + colorName; } else { return colorName; } } void QmitkChartWidget::Impl::AddData1D(const std::vector &data1D, const std::string &label, QmitkChartWidget::ChartType chartType) { std::map transformedData2D; unsigned int count = 0; // transform the 1D data to 2D data for (const auto &ele : data1D) { transformedData2D[count] = ele; count++; } AddData2D(transformedData2D, label, chartType); } void QmitkChartWidget::Impl::AddData2D(const std::map &data2D, const std::string &label, QmitkChartWidget::ChartType chartType) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } m_C3xyData.push_back(std::make_unique( data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(chartTypeName)))); } void QmitkChartWidget::Impl::RemoveData(const std::string &label) { for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter) { if ((*iter)->GetLabel().toString().toStdString() == label) { m_C3xyData.erase(iter); return; } } throw std::invalid_argument("Cannot Remove Data because the label does not exist."); } void QmitkChartWidget::Impl::ClearData() { for (auto &xyData : m_C3xyData) { m_WebChannel->deregisterObject(xyData.get()); } m_C3xyData.clear(); } void QmitkChartWidget::Impl::SetColor(const std::string &label, const std::string &colorName) { auto element = GetDataElementByLabel(label); if (element) { auto colorChecked = CheckForCorrectHex(colorName); element->SetColor(QVariant(QString::fromStdString(colorName))); } } void QmitkChartWidget::Impl::SetLineStyle(const std::string &label, LineStyle style) { auto element = GetDataElementByLabel(label); // only has effect with chart type line if (element && element->GetChartType() == QVariant(QString::fromStdString(ConvertChartTypeToString(ChartType::line)))) { const std::string lineStyleName(m_LineStyleToName.at(style)); element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName))); } } void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale) { const std::string axisScaleName(m_AxisScaleToName.at(scale)); m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName)); } void QmitkChartWidget::Impl::SetXAxisLabel(const std::string &label) { m_C3Data.SetXAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string &label) { m_C3Data.SetYAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetTitle(const std::string &title) { m_C3Data.SetTitle(QString::fromStdString(title)); } void QmitkChartWidget::Impl::SetChartType(QmitkChartWidget::ChartType chartType) { for (auto iterator = m_C3xyData.begin(); iterator != m_C3xyData.end(); ++iterator) { SetChartTypeByLabel((*iterator)->GetLabel().toString().toStdString(), chartType); } auto chartTypeName = ConvertChartTypeToString(chartType); const QString command = QString::fromStdString("transformView('" + chartTypeName + "')"); CallJavaScriptFuntion(command); } void QmitkChartWidget::Impl::SetChartTypeByLabel(const std::string &label, QmitkChartWidget::ChartType chartType) { auto element = GetDataElementByLabel(label); if (element) { if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } auto chartTypeName = ConvertChartTypeToString(chartType); element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); } } void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition) { const std::string legendPositionName(m_LegendPositionToName.at(legendPosition)); m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName)); } void QmitkChartWidget::Impl::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } void QmitkChartWidget::Impl::SetStackedData(bool stacked) { m_C3Data.SetStackedData(stacked); } void QmitkChartWidget::Impl::Show(bool showSubChart) { if (m_C3xyData.empty()) { mitkThrow() << "no data available for display in chart"; } m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie")); InitializeJavaScriptChart(); } void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { if (showDataPoints == true) { m_C3Data.SetDataPointSize(3); } else { m_C3Data.SetDataPointSize(0); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } -QmitkChartData *QmitkChartWidget::Impl::GetC3Data() -{ - return &m_C3Data; -} - -std::vector> *QmitkChartWidget::Impl::GetC3xyData() -{ - return &m_C3xyData; -} - void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); } void QmitkChartWidget::Impl::InitializeJavaScriptChart() { m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data); unsigned count = 0; for (auto &xyData : m_C3xyData) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData.get()); count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///C3js/QmitkChartWidget.html"))); } void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString &command) { m_WebEngineView->page()->runJavaScript(command); } std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList &labelList, const std::string &label) const { QString currentLabel = QString::fromStdString(label); int counter = 0; while (labelList.contains(currentLabel)) { currentLabel = QString::fromStdString(label + std::to_string(counter)); counter++; } return currentLabel.toStdString(); } QmitkChartxyData *QmitkChartWidget::Impl::GetDataElementByLabel(const std::string &label) const { for (const auto &qmitkChartxyData : m_C3xyData) { if (qmitkChartxyData->GetLabel().toString() == label.c_str()) { return qmitkChartxyData.get(); } } MITK_WARN << "label " << label << " not found in QmitkChartWidget"; return nullptr; } QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector &c3xyData) const { QList dataLabels; for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) { dataLabels.push_back((*element)->GetLabel()); } return dataLabels; } QmitkChartWidget::QmitkChartWidget(QWidget *parent) : QWidget(parent), m_Impl(new Impl(this)) {} -QmitkChartWidget::QmitkChartWidget(QWidget *parent, bool unitTest) : QWidget(parent), m_Impl(new Impl(this, unitTest)) -{ -} - QmitkChartWidget::~QmitkChartWidget() {} -std::vector> *QmitkChartWidget::GetData() const -{ - return m_Impl->GetC3xyData(); -} - -QmitkChartData *QmitkChartWidget::GetC3Data() const -{ - return m_Impl->GetC3Data(); -} - void QmitkChartWidget::AddData1D(const std::vector &data1D, const std::string &label, ChartType type) { m_Impl->AddData1D(data1D, label, type); } void QmitkChartWidget::AddData2D(const std::map &data2D, const std::string &label, ChartType type) { m_Impl->AddData2D(data2D, label, type); } void QmitkChartWidget::RemoveData(const std::string &label) { m_Impl->RemoveData(label); } void QmitkChartWidget::SetColor(const std::string &label, const std::string &colorName) { m_Impl->SetColor(label, colorName); } void QmitkChartWidget::SetLineStyle(const std::string &label, LineStyle style) { m_Impl->SetLineStyle(label, style); } void QmitkChartWidget::SetYAxisScale(AxisScale scale) { m_Impl->SetYAxisScale(scale); } void QmitkChartWidget::SetXAxisLabel(const std::string &label) { m_Impl->SetXAxisLabel(label); } void QmitkChartWidget::SetYAxisLabel(const std::string &label) { m_Impl->SetYAxisLabel(label); } void QmitkChartWidget::SetTitle(const std::string &title) { m_Impl->SetTitle(title); } void QmitkChartWidget::SetChartTypeForAllDataAndReload(ChartType type) { m_Impl->SetChartType(type); } void QmitkChartWidget::SetChartType(const std::string &label, ChartType type) { m_Impl->SetChartTypeByLabel(label, type); } void QmitkChartWidget::SetLegendPosition(LegendPosition position) { m_Impl->SetLegendPosition(position); } void QmitkChartWidget::SetShowLegend(bool show) { m_Impl->SetShowLegend(show); } void QmitkChartWidget::SetStackedData(bool stacked) { m_Impl->SetStackedData(stacked); } void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) { m_Impl->SetShowDataPoints(showDataPoints); } void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful) { if (isLoadSuccessful) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::SetTheme(ChartStyle themeEnabled) { QString command; if (themeEnabled == ChartStyle::darkstyle) { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('light')"); } m_Impl->CallJavaScriptFuntion(command); } void QmitkChartWidget::Reload(bool showSubChart) { QString subChartString; if (showSubChart) { subChartString = "true"; } else { subChartString = "false"; } const QString command = QString("ReloadChart(" + subChartString + ")"); m_Impl->CallJavaScriptFuntion(command); } diff --git a/Modules/Chart/test/CMakeLists.txt b/Modules/Chart/test/CMakeLists.txt deleted file mode 100644 index 153cd81e2e..0000000000 --- a/Modules/Chart/test/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -MITK_CREATE_MODULE_TESTS() diff --git a/Modules/Chart/test/files.cmake b/Modules/Chart/test/files.cmake deleted file mode 100644 index d7046f87fc..0000000000 --- a/Modules/Chart/test/files.cmake +++ /dev/null @@ -1,6 +0,0 @@ -set(MODULE_TESTS - mitkChartWidgetTest.cpp -) - -SET(MODULE_CUSTOM_TESTS -) diff --git a/Modules/Chart/test/mitkChartWidgetTest.cpp b/Modules/Chart/test/mitkChartWidgetTest.cpp deleted file mode 100644 index 911136abee..0000000000 --- a/Modules/Chart/test/mitkChartWidgetTest.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -// Testing -#include "mitkTestFixture.h" -#include "mitkTestingMacros.h" - -// qt includes -#include "QApplication" - -// std includes -#include - -// MITK includes -#include "QmitkChartWidget.h" -#include "QmitkChartxyData.h" -#include "QmitkChartData.h" - -class mitkChartWidgetTestSuite : public mitk::TestFixture -{ - CPPUNIT_TEST_SUITE(mitkChartWidgetTestSuite); - - // Test the dicom property parsing - MITK_TEST(AddOnce_Test_Success); - MITK_TEST(AddSameLabelTwice_Test_Success); - MITK_TEST(RemoveNonexistingData_Failure); - MITK_TEST(RemoveData_Success); - MITK_TEST(SetandGet_Success); - MITK_TEST(SetC3DataAndGet_Success); - MITK_TEST(AddAndRemoveData_Sucess); - CPPUNIT_TEST_SUITE_END(); - -private: - std::vector data1D; - std::string label; - -public: - void setUp() override - { - data1D = {2, 4, 7, 8, 21, 5, 12, 65, 41, 9}; - label = "testLabel"; - - int argc = 1; - char *argv[] = {(char *)"AppName"}; - if (QApplication::instance() == nullptr) - { - new QApplication(argc, argv); - } - } - - void tearDown() override {} - - void AddOnce_Test_Success() - { - //use QmitkChartWidget without QWebEngineView - QmitkChartWidget widget(nullptr, true); - CPPUNIT_ASSERT_NO_THROW_MESSAGE("Adding data caused an exception", widget.AddData1D(data1D, label)); - - std::vector> *dataVector = widget.GetData(); - - CPPUNIT_ASSERT_MESSAGE("Adding data failed.", dataVector->size() == 1 && dataVector != nullptr); - QmitkChartxyData *dataPtr = dataVector->at(0).get(); - - CPPUNIT_ASSERT_MESSAGE("Label differs for no obvious reason", - dataPtr->GetLabel().toString().toStdString() == label); - - std::vector insertedYData = dataPtr->GetYData().toVector().toStdVector(); - CPPUNIT_ASSERT_MESSAGE("Data differs in size", insertedYData.size() == data1D.size()); - - for (size_t i = 0; i < data1D.size(); ++i) - { - CPPUNIT_ASSERT_MESSAGE("The inserted data differs when checked", data1D[i] == insertedYData[i]); - } - } - - void AddSameLabelTwice_Test_Success() - { - - - QmitkChartWidget widget(nullptr, true); - widget.AddData1D(data1D, label); - widget.AddData1D(data1D, label); - - auto dataVector = widget.GetData(); - - QmitkChartxyData* xyData1 = dataVector->at(0).get(); - QmitkChartxyData* xyData2 = dataVector->at(1).get(); - - QVariant dataLabel1 = xyData1->GetLabel(); - QVariant dataLabel2 = xyData2->GetLabel(); - CPPUNIT_ASSERT_MESSAGE("The two dataLabel are the same", dataLabel1 != dataLabel2); - - QString string1 = dataLabel1.toString(); - QString string2 = dataLabel2.toString(); - - std::string stdString1 = string1.toStdString(); - std::string stdString2 = string2.toStdString(); - CPPUNIT_ASSERT_MESSAGE("The first dataLabel isn't still the same", stdString1 == label); - CPPUNIT_ASSERT_MESSAGE("The second dataLabel is still the same", stdString2 != label); - } - - void AddAndRemoveData_Sucess() - { - std::vector data1D2 = {2, 2}; - std::string label2 = "testData2"; - std::vector data1D3 = {3, 3, 3}; - std::string label3 = "testData3"; - QmitkChartWidget widget(nullptr, true); - widget.AddData1D(data1D, label); - widget.AddData1D(data1D2, label2); - widget.AddData1D(data1D3, label3); - auto dataVector = widget.GetData(); - // data with {data1D0, data1D2, data1D3} - CPPUNIT_ASSERT_MESSAGE("Adding data failed.", dataVector->size() == 3 && dataVector != nullptr); - widget.RemoveData(label2); - // data with {data1D0, data1D3} - CPPUNIT_ASSERT_MESSAGE("Removing data failed.", dataVector->size() == 2 && dataVector != nullptr); - QmitkChartxyData *xyData1 = dataVector->at(0).get(); - std::vector insertedYData = xyData1->GetYData().toVector().toStdVector(); - for (size_t i = 0; i < data1D.size(); ++i) - { - CPPUNIT_ASSERT_MESSAGE("The inserted data differs when checked", data1D[i] == insertedYData[i]); - } - QmitkChartxyData *xyData2 = dataVector->at(1).get(); - insertedYData = xyData2->GetYData().toVector().toStdVector(); - for (size_t i = 0; i < data1D3.size(); ++i) - { - CPPUNIT_ASSERT_MESSAGE("The inserted data differs when checked", data1D3[i] == insertedYData[i]); - } - widget.RemoveData(label); - // data with {data1D3} - CPPUNIT_ASSERT_MESSAGE("Removing data failed.", dataVector->size() == 1 && dataVector != nullptr); - widget.AddData1D(data1D2, label2); - CPPUNIT_ASSERT_MESSAGE("Adding data failed.", dataVector->size() == 2 && dataVector != nullptr); - - //data with {data1D3, data1D2} - xyData1 = dataVector->at(0).get(); - insertedYData = xyData1->GetYData().toVector().toStdVector(); - for (size_t i = 0; i < data1D3.size(); ++i) - { - CPPUNIT_ASSERT_MESSAGE("The inserted data differs when checked", data1D3[i] == insertedYData[i]); - } - xyData2 = dataVector->at(1).get(); - insertedYData = xyData2->GetYData().toVector().toStdVector(); - for (size_t i = 0; i < data1D2.size(); ++i) - { - CPPUNIT_ASSERT_MESSAGE("The inserted data differs when checked", data1D2[i] == insertedYData[i]); - } - - } - - void RemoveNonexistingData_Failure() - { - QmitkChartWidget widget(nullptr, true); - - CPPUNIT_ASSERT_THROW_MESSAGE( - "Removin nonexistend label did not throw exception", widget.RemoveData(label), std::invalid_argument); - } - - void RemoveData_Success() - { - QmitkChartWidget widget(nullptr, true); - widget.AddData1D(data1D, label); - - CPPUNIT_ASSERT_NO_THROW_MESSAGE("Removin nonexistend label did not throw exception", widget.RemoveData(label)); - } - - void SetandGet_Success() - { - QmitkChartWidget widget(nullptr, true); - widget.AddData1D(data1D, label); - std::string colorName = "green"; - - auto mitkChartxyData = widget.GetData(); - QmitkChartxyData *xyData1 = mitkChartxyData->at(0).get(); - - - //set color test - widget.SetColor(label, colorName); - auto qVariantColor = xyData1->GetColor(); - QString qStringColor = qVariantColor.toString(); - CPPUNIT_ASSERT_MESSAGE("The color isn't the assigned color", colorName == qStringColor.toStdString()); - - //set line style test - QVariant defaultLineStyle = xyData1->GetLineStyle(); - - widget.SetLineStyle(label, QmitkChartWidget::LineStyle::dashed); - QVariant lineStyle = xyData1->GetLineStyle(); - - QVariant defaultChartType = xyData1->GetChartType(); - auto line= std::make_pair("line", QmitkChartWidget::ChartType::line); - if (defaultChartType.toString().toStdString() != line.first) - { - CPPUNIT_ASSERT_MESSAGE("The line style could be changed without ChartType line", - defaultLineStyle == lineStyle); - } - - //set ChartType - widget.SetChartType(label, QmitkChartWidget::ChartType::line); - QVariant chartType = xyData1->GetChartType(); - - - CPPUNIT_ASSERT_MESSAGE("The chart type could not be changed to line", - chartType.toString().toStdString() == line.first); - - //set line style with chart type line - widget.SetLineStyle(label, QmitkChartWidget::LineStyle::dashed); - lineStyle = xyData1->GetLineStyle(); - CPPUNIT_ASSERT_MESSAGE("The line style could not be changed", "dashed" == lineStyle.toString().toStdString()); - - - } - - void SetC3DataAndGet_Success() - { - QmitkChartWidget widget(nullptr, true); - widget.AddData1D(data1D, label); - - //set YAxisScale - widget.SetYAxisScale(QmitkChartWidget::AxisScale::log); - QmitkChartData *c3Data = widget.GetC3Data(); - QVariant yAxisScale = c3Data->GetYAxisScale(); - CPPUNIT_ASSERT_MESSAGE("The YAxisScale could not be changed", "log" == yAxisScale.toString().toStdString()); - - //set Title - std::string testTitle = "testTitle"; - widget.SetTitle(testTitle); - QVariant title = c3Data->GetTitle(); - CPPUNIT_ASSERT_MESSAGE("The title could not be set", testTitle == title.toString().toStdString()); - - //set LegendPosition - widget.SetLegendPosition(QmitkChartWidget::LegendPosition::right); - QVariant legendPosition = c3Data->GetLegendPosition(); - CPPUNIT_ASSERT_MESSAGE("The LegendPosition could not be changed", "right" == legendPosition.toString().toStdString()); - - //show legend - QVariant isShowLegend = c3Data->GetShowLegend(); - widget.SetShowLegend(!isShowLegend.toBool()); - QVariant isShowLegendInverted = c3Data->GetShowLegend(); - CPPUNIT_ASSERT_MESSAGE("The ShowLegend could not be changed", - isShowLegend.toBool() != isShowLegendInverted.toBool()); - - //show dataPoints - QVariant dataPointSize = c3Data->GetDataPointSize(); - bool showDataPoints = dataPointSize.toInt() > 0; - widget.SetShowDataPoints(!showDataPoints); - dataPointSize = c3Data->GetDataPointSize(); - bool showDataPointsInvert = dataPointSize.toInt() > 0; - CPPUNIT_ASSERT_MESSAGE("The DataPoints could not be changed", - showDataPoints != showDataPointsInvert); - } -}; - -MITK_TEST_SUITE_REGISTRATION(mitkChartWidget) \ No newline at end of file