Qt Charts: first working version v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 18 Nov 2018 00:38:49 +0100
branchv_0
changeset 28 04f1ac8a931b
parent 27 8c5364450a46
child 29 0f9f7d6564cd
Qt Charts: first working version
nbproject/configurations.xml
src/CMakeLists.txt
src/RelpipeChartMainWindow.cpp
src/RelpipeChartMainWindow.h
src/RelpipeChartWidget.h
src/RelpipeTableModel.h
src/relpipe-out-chart.cpp
--- a/nbproject/configurations.xml	Tue Oct 30 23:52:55 2018 +0100
+++ b/nbproject/configurations.xml	Sun Nov 18 00:38:49 2018 +0100
@@ -103,9 +103,9 @@
         <rebuildPropChanged>false</rebuildPropChanged>
       </toolsSet>
       <flagsDictionary>
-        <element flagsID="0"
+        <element flagsID="0" commonFlags="-fsanitize=address -fPIC -std=gnu++11"/>
+        <element flagsID="1"
                  commonFlags="-mtune=generic -march=x86-64 -std=gnu++11 -fsanitize=address -fPIC -fstack-protector-strong"/>
-        <element flagsID="1" commonFlags="-std=c++14"/>
       </flagsDictionary>
       <codeAssistance>
       </codeAssistance>
@@ -126,8 +126,6 @@
             ex="false"
             tool="1"
             flavor2="11">
-        <ccTool flags="1">
-        </ccTool>
       </item>
       <item path="build/Debug/src/relpipe-out-chart_autogen/EWIEGA46WW/moc_QtRelationalReaderStringHadler.cpp"
             ex="true"
@@ -153,7 +151,7 @@
             ex="false"
             tool="1"
             flavor2="8">
-        <ccTool flags="0">
+        <ccTool flags="1">
         </ccTool>
       </item>
       <item path="build/Debug/src/relpipe-out-gui_autogen/mocs_compilation.cpp"
@@ -166,7 +164,17 @@
       <folder path="0">
         <ccTool>
           <incDir>
+            <pElem>build/Debug/src</pElem>
+            <pElem>src</pElem>
+            <pElem>build/Debug/src/relpipe-out-gui_autogen/include</pElem>
+            <pElem>../relpipe-lib-reader.cpp/include</pElem>
+            <pElem>../relpipe-lib-cli.cpp/include</pElem>
+            <pElem>/usr/include/x86_64-linux-gnu/qt5</pElem>
+            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtWidgets</pElem>
+            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtGui</pElem>
             <pElem>/usr/include/x86_64-linux-gnu/qt5/QtCore</pElem>
+            <pElem>/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++</pElem>
+            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtCharts</pElem>
           </incDir>
           <preprocessorList>
             <Elem>QT_CHARTS_LIB</Elem>
@@ -176,24 +184,6 @@
           </preprocessorList>
         </ccTool>
       </folder>
-      <folder path="0/build">
-        <ccTool>
-          <incDir>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader/handlers</pElem>
-            <pElem>src</pElem>
-            <pElem>build/Debug/src/relpipe-out-gui_autogen/EWIEGA46WW</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtGui</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtWidgets</pElem>
-            <pElem>build/Debug/src/relpipe-out-gui_autogen/include</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtCharts</pElem>
-            <pElem>build/Debug/src/relpipe-out-gui_autogen</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include</pElem>
-            <pElem>build/Debug/src</pElem>
-          </incDir>
-        </ccTool>
-      </folder>
       <folder path="Modules">
         <ccTool>
           <incDir>
@@ -239,36 +229,10 @@
       </folder>
       <item path="src/RelpipeChartMainWindow.cpp" ex="false" tool="1" flavor2="8">
         <ccTool flags="0">
-          <incDir>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtWidgets</pElem>
-            <pElem>build/Debug/src/relpipe-out-gui_autogen/include</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader/handlers</pElem>
-            <pElem>src</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtGui</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtCharts</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include</pElem>
-            <pElem>build/Debug/src</pElem>
-          </incDir>
         </ccTool>
       </item>
       <item path="src/relpipe-out-chart.cpp" ex="false" tool="1" flavor2="8">
         <ccTool flags="0">
-          <incDir>
-            <pElem>../relpipe-lib-cli.cpp/include/relpipe/cli</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader/handlers</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include/relpipe/reader</pElem>
-            <pElem>src</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtGui</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtWidgets</pElem>
-            <pElem>build/Debug/src/relpipe-out-gui_autogen/include</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5/QtCharts</pElem>
-            <pElem>../relpipe-lib-cli.cpp/include</pElem>
-            <pElem>../relpipe-lib-reader.cpp/include</pElem>
-            <pElem>/usr/include/x86_64-linux-gnu/qt5</pElem>
-            <pElem>build/Debug/src</pElem>
-          </incDir>
         </ccTool>
       </item>
     </conf>
--- a/src/CMakeLists.txt	Tue Oct 30 23:52:55 2018 +0100
+++ b/src/CMakeLists.txt	Sun Nov 18 00:38:49 2018 +0100
@@ -22,7 +22,7 @@
 add_executable(
 	${EXECUTABLE_FILE}
 	QtRelationalReaderStringHadler.h # QObjects must be listed here (including them from other files is not enough)
-	#RelpipeChartWidget.h
+	RelpipeChartWidget.h
 	RelpipeTableModel.h
 	RelpipeChartMainWindow.ui
 	RelpipeChartMainWindow.cpp
--- a/src/RelpipeChartMainWindow.cpp	Tue Oct 30 23:52:55 2018 +0100
+++ b/src/RelpipeChartMainWindow.cpp	Sun Nov 18 00:38:49 2018 +0100
@@ -1,22 +1,13 @@
 #include <vector>
 
 #include <QPushButton>
-#include <QSplitter>
 #include <QTableView>
 
-#include <QChart>
-#include <QChartView>
-#include <QStackedBarSeries>
-#include <QBarCategoryAxis>
-#include <QVBarModelMapper>
-
 #include "RelpipeChartMainWindow.h"
 
 using namespace relpipe::reader;
 using namespace relpipe::reader::handlers;
 
-QT_CHARTS_USE_NAMESPACE
-
 RelpipeChartMainWindow::RelpipeChartMainWindow() {
 	widget.setupUi(this);
 
@@ -31,16 +22,18 @@
 
 void RelpipeChartMainWindow::startRelation(const string_t name, std::vector<AttributeMetadata> attributes) {
 	setStatusMessage(L"Reading relation: " + name);
-	QSplitter* splitter = new QSplitter(Qt::Orientation::Vertical, tabs);
 
 	currentModel = new RelpipeTableModel(attributes, this);
 	QTableView* tableView = new QTableView(this);
 	tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::ResizeToContents);
 	tableView->setModel(currentModel);
-	
-	// TODO: chart
-	splitter->addWidget(new QPushButton("here will be the chart", splitter));
+
+	if (currentChartWidget) currentChartWidget->endOfRelation();
+	currentChartWidget = new RelpipeChartWidget(currentModel, splitter);
+	splitter->addWidget(currentChartWidget);
 	splitter->addWidget(tableView);
+	splitter->setSizes({currentChartWidget->hasChartData() ? 1 : 0, 1});
+	// splitter->setStretchFactor(currentChartWidget->hasChartData() ? 1 : 0, 1); // FIXME: 50:50 if chart is present
 	int index = tabs->addTab(splitter, QString::fromWCharArray(name.c_str()));
 	if (tabs->count() == 2) tabs->setCurrentIndex(index); // switch to the first relation (first tab is Options tab)
 	tabs->setTabIcon(index, QIcon::fromTheme("application-vnd.oasis.opendocument.spreadsheet"));
@@ -55,5 +48,6 @@
 }
 
 void RelpipeChartMainWindow::endOfPipe() {
+	if (currentChartWidget) currentChartWidget->endOfRelation();
 	setStatusMessage(L"Reading successfully finished.");
 }
--- a/src/RelpipeChartMainWindow.h	Tue Oct 30 23:52:55 2018 +0100
+++ b/src/RelpipeChartMainWindow.h	Sun Nov 18 00:38:49 2018 +0100
@@ -2,6 +2,7 @@
 
 #include <QTableWidget>
 #include <QLabel>
+#include <QSplitter>
 
 #include "ui_RelpipeChartMainWindow.h"
 
@@ -11,6 +12,7 @@
 #include <relpipe/reader/handlers/AttributeMetadata.h>
 
 #include "RelpipeTableModel.h"
+#include "RelpipeChartWidget.h"
 
 using namespace relpipe::reader;
 using namespace relpipe::reader::handlers;
@@ -28,6 +30,8 @@
 private:
 	Ui::RelpipeChartMainWindow widget;
 	QTabWidget* tabs = new QTabWidget(this);
+	QSplitter* splitter = new QSplitter(Qt::Orientation::Vertical, tabs);
 	RelpipeTableModel* currentModel;
+	RelpipeChartWidget* currentChartWidget;
 	QLabel* status = new QLabel();
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/RelpipeChartWidget.h	Sun Nov 18 00:38:49 2018 +0100
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <iostream>
+
+#include <QWidget>
+#include <QGridLayout>
+#include <QLabel>
+
+#include <QChart>
+#include <QChartView>
+#include <QStackedBarSeries>
+#include <QBarCategoryAxis>
+#include <QVBarModelMapper>
+
+
+#include <relpipe/reader/typedefs.h>
+#include <relpipe/reader/TypeId.h>
+#include <relpipe/reader/handlers/AttributeMetadata.h>
+
+#include "RelpipeTableModel.h"
+
+using namespace relpipe::reader;
+using namespace relpipe::reader::handlers;
+
+QT_CHARTS_USE_NAMESPACE
+
+class RelpipeChartWidget : public QWidget {
+	Q_OBJECT
+private:
+	RelpipeTableModel* model;
+
+	QGridLayout* layout;
+	QChart* chart;
+	QChartView* chartView;
+	QVBarModelMapper* mapper;
+	QStackedBarSeries* series;
+	QBarCategoryAxis* axis;
+
+	boolean_t isNumeric(TypeId typeId) {
+		return typeId == TypeId::INTEGER;
+	}
+
+	int firstValueColumn() {
+		int first = lastValueColumn();
+		for (int i = first; i > 0; i--) if (isNumeric(model->attributeType(i))) first = i; else break;
+		return first;
+	}
+
+	int lastValueColumn() {
+		return model->columnCount() - 1;
+	}
+
+public:
+
+	RelpipeChartWidget(RelpipeTableModel* model, QWidget* parent = Q_NULLPTR) : model(model), QWidget(parent) {
+		layout = new QGridLayout();
+		setLayout(layout);
+	}
+
+	void endOfRelation() {
+		if (hasChartData()) {
+			chart = new QChart();
+			chartView = new QChartView(chart, this);
+			mapper = new QVBarModelMapper(chartView);
+			series = new QStackedBarSeries(mapper);
+			mapper->setFirstBarSetColumn(firstValueColumn());
+			mapper->setLastBarSetColumn(lastValueColumn());
+			mapper->setSeries(series);
+			mapper->setModel(model);
+
+
+			axis = new QBarCategoryAxis(chartView);
+			for (int i = 0; i < model->rowCount(); i++) axis->append(model->data(model->index(i, 0)).toString());
+			chart->addSeries(series);
+			chart->createDefaultAxes();
+			chart->setAxisX(axis, series);
+			layout->addWidget(chartView);
+		} else {
+			layout->addWidget(new QLabel("This relation can't be displayed as a chart.", this));
+		}
+	}
+
+	/**
+	 * @return whether drawing a chart makes sense for this relation
+	 */
+	boolean_t hasChartData() {
+		return model->columnCount() >= 2 // first = category, last = numeric value
+				&& isNumeric(model->attributeType(lastValueColumn())); // at least the last attribute must be numeric
+	}
+};
--- a/src/RelpipeTableModel.h	Tue Oct 30 23:52:55 2018 +0100
+++ b/src/RelpipeTableModel.h	Sun Nov 18 00:38:49 2018 +0100
@@ -91,6 +91,10 @@
 		if (column == 0) emit layoutChanged(); // FIXME: emit other signal ~ begin..., end..., rowsInserted(???  index(0,0), row, row);
 		attributeCounter++;
 	}
+	
+	TypeId attributeType(int section) {
+		return attributes[section].getTypeId();
+	}
 
 	Qt::ItemFlags flags(const QModelIndex &index) const {
 		if (isFilled(index)) {
--- a/src/relpipe-out-chart.cpp	Tue Oct 30 23:52:55 2018 +0100
+++ b/src/relpipe-out-chart.cpp	Sun Nov 18 00:38:49 2018 +0100
@@ -1,3 +1,6 @@
+#include <sys/prctl.h>
+#include <stdio.h>
+#include <unistd.h>
 #include <iostream>
 
 #include <QApplication>