diff --git a/Licenses/ICONS.md b/Licenses/ICONS.md index 8c06f0387e..331cdcbfd7 100644 --- a/Licenses/ICONS.md +++ b/Licenses/ICONS.md @@ -1,11 +1,12 @@ MITK uses icons from various sources. Please respect their licenses. - [Crystal Clear](https://commons.wikimedia.org/wiki/Crystal_Clear) (LGPL 2.1) - [Font Awesome 4](https://fontawesome.com/v4.7.0/license/) (SIL OFL 1.1) - Noun Project (Creative Commons Attribution 3.0 Unported) - [Marek Polakovic](https://thenounproject.com/marekpolakovic/) - [Santiago Arias](https://thenounproject.com/Sa_arias/) - [Takao Umehara](https://thenounproject.com/takaoumehara/) - [The Python Logo](https://www.python.org/community/logos/) ([PSF Trademark Usage Policy 1.5.0](https://www.python.org/psf/trademarks/)) - [Tango](http://tango.freedesktop.org/Tango_Desktop_Project) (Public Domain) - [XNAT](https://www.xnat.org/) (Creative Commons Attribution 3.0 Unported) +- [FlatIcon] (https://www.freepik.com/) (CC 3.0 BY) diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 58a1e0eb14..570fac5a4b 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,535 +1,539 @@ /*=================================================================== 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 CustomPage : public QWebEnginePage { public: CustomPage(QObject* parent = 0) : QWebEnginePage(parent) {} virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel /*level*/, const QString &message, int lineNumber, const QString &/*sourceID*/) { MITK_INFO << "JS > " << lineNumber << ": " << message.toStdString(); } }; class QmitkChartWidget::Impl final { public: 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 SetLegendPosition(LegendPosition position); void SetChartTypeByLabel(const std::string &label, QmitkChartWidget::ChartType chartType); void Show(bool showSubChart); void SetShowLegend(bool show); void SetShowDataPoints(bool showDataPoints = false); void SetChartType(const std::string& label, QmitkChartWidget::ChartType chartType); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString &command); QSize sizeHint() const; 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)) { // disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); m_WebEngineView->setPage(new CustomPage()); // 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); 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 type) { 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, type); } void QmitkChartWidget::Impl::AddData2D(const std::map& data2D, const std::string& label, QmitkChartWidget::ChartType type) { QMap data2DConverted; for (const auto &aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(type)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (type == 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(colorChecked))); } } 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)); } 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; } 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::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::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { if (showDataPoints == true) { m_C3Data.SetDataPointSize(3); } else { m_C3Data.SetDataPointSize(0); } } void QmitkChartWidget::Impl::SetChartType(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"; } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } QSize QmitkChartWidget::Impl::sizeHint() const { return QSize(400, 300); } void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString& command) { m_WebEngineView->page()->runJavaScript(command); } 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"))); } 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(); } QmitkChartWidget::QmitkChartWidget(QWidget *parent) : QWidget(parent), m_Impl(new Impl(this)) {} QmitkChartWidget::~QmitkChartWidget() {} void QmitkChartWidget::AddData2D(const std::map &data2D, const std::string &label, ChartType type) { m_Impl->AddData2D(data2D, label, type); } 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::AddData1D(const std::vector& data1D, const std::string& label, ChartType type) { m_Impl->AddData1D(data1D, label, type); } void QmitkChartWidget::RemoveData(const std::string& label) { m_Impl->RemoveData(label); } 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::SetShowDataPoints(bool showDataPoints) { m_Impl->SetShowDataPoints(showDataPoints); } void QmitkChartWidget::SetChartType(const std::string &label, ChartType type) { m_Impl->SetChartType(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) { + MITK_WARN << "not yet implemented"; +} + void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessfull) { if(isLoadSuccessfull) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::SetChartTypeForAllDataAndReload(ChartType type) { m_Impl->SetChartType(type); } 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); } QSize QmitkChartWidget::sizeHint() const { return m_Impl->sizeHint(); } diff --git a/Plugins/org.mitk.gui.qt.chartExample/files.cmake b/Plugins/org.mitk.gui.qt.chartExample/files.cmake index ec8f914b40..b097c50982 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/files.cmake +++ b/Plugins/org.mitk.gui.qt.chartExample/files.cmake @@ -1,42 +1,42 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_chartExample_Activator.cpp ChartExample.cpp ) set(UI_FILES src/internal/ChartExampleControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_chartExample_Activator.h src/internal/ChartExample.h ) # list of resource files which can be used by the plug-in # system without loading the plug-ins shared library, # for example the icon used in the menu and tabs for the # plug-in views in the workbench set(CACHED_RESOURCE_FILES - resources/icon.xpm + resources/chart.svg plugin.xml ) # list of Qt .qrc files which contain additional resources # specific to this plugin set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.chartExample/plugin.xml b/Plugins/org.mitk.gui.qt.chartExample/plugin.xml index 2a960b8d78..ccea1d50e4 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/plugin.xml +++ b/Plugins/org.mitk.gui.qt.chartExample/plugin.xml @@ -1,11 +1,12 @@ + icon="resources/chart.svg"/> diff --git a/Plugins/org.mitk.gui.qt.chartExample/resources/chart.svg b/Plugins/org.mitk.gui.qt.chartExample/resources/chart.svg new file mode 100644 index 0000000000..e7cfc1e749 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.chartExample/resources/chart.svg @@ -0,0 +1,256 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.chartExample/resources/icon-license.txt b/Plugins/org.mitk.gui.qt.chartExample/resources/icon-license.txt new file mode 100644 index 0000000000..8e8134868b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.chartExample/resources/icon-license.txt @@ -0,0 +1 @@ +See [FlatIcon] in Licenses/ICONS.md \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.chartExample/resources/icon.xpm b/Plugins/org.mitk.gui.qt.chartExample/resources/icon.xpm deleted file mode 100644 index 9057c20bc6..0000000000 --- a/Plugins/org.mitk.gui.qt.chartExample/resources/icon.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static const char * icon_xpm[] = { -"16 16 2 1", -" c #FF0000", -". c #000000", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" ", -" "}; diff --git a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui b/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui index f10a0f1774..c862708844 100644 --- a/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui +++ b/Plugins/org.mitk.gui.qt.chartExample/src/internal/ChartExampleControls.ui @@ -1,319 +1,341 @@ ChartExampleControls 0 0 326 944 0 0 QmitkTemplate - - - - 0 - 50 - - + Data - - - 6 - - - 6 - - - 9 - - - 6 - - - - - data entry - - - - - - - - - - - - - - data label - - - - - - - - - - Chart type - - - - - - - - bar - + + + + + + + data label + + - - - line - + + + + + 0 + 0 + + + - - - area - + + + + data entry + + - - - spline - + + + + + 0 + 0 + + + + + + - - - area-spline - + + + + Color + + - - - scatter - + + + + + 0 + 0 + + + - - - - - - Color - - - - - - - - - - Line style - - - - - - - - solid - + + + + Line style + + + + + + + + 0 + 0 + + + + + solid + + + + + dashed + + + - - - dashed - + + + + Chart type + + - + + + + + 0 + 0 + + + + + bar + + + + + line + + + + + area + + + + + spline + + + + + area-spline + + + + + scatter + + + + + Add data 0 - 50 + 0 Global options - - - - - XAxis label - - - - - - - - - - YAxis label - - - - - - - - - - Y Axis scale - - - - - - - - linear - + + + + + + + XAxis label + + - - - logarithmic - + + - - - - - - Show legend - - - true - - - - - - - Show data points - - - true - - - - - - - Stacked data - - - - - - - Show Subchart - - + + + + YAxis label + + + + + + + + + + Y Axis scale + + + + + + + + linear + + + + + logarithmic + + + + + + + + Show legend + + + true + + + + + + + Stacked data + + + + + + + Show data points + + + true + + + + + + + Show Subchart + + + + Do image processing Create chart Clear chart Qt::Vertical 0 200 0 0 0 Qt::Vertical QSizePolicy::Expanding 20 - 220 + 0 QmitkChartWidget QWidget
QmitkChartWidget.h