#include "xlruchartclass.h" #include #include #include #include //#include using namespace QtCharts; XlruChartClass::XlruChartClass(QWidget *parent) : QWidget(parent), report(0) #ifdef TELEMETRY ,telemetry(0) #endif { init(); SensorsTable = NULL; } XlruChartClass::~XlruChartClass() { delete mainView; //delete report; } void XlruChartClass::setTitle(QString aTitle) { title = aTitle; } QString XlruChartClass::getTitle() { return title; } void XlruChartClass::init() { ch = new QChart(); mainView = new QChartView(); ch=mainView->chart(); m_tooltip = 0; mainView->setRubberBand( QChartView::HorizontalRubberBand ); ch->setMargins(QMargins(0, 0, 0, 0)); ch->setAnimationOptions(QChart::NoAnimation); ch->setMinimumSize(CHART_DIMX_DEF, CHART_DIMY_DEF); ch->setAcceptHoverEvents(true); ch->setTitle(title); QHBoxLayout *layout = new QHBoxLayout(); #ifdef TRACKING_VALUE valueToScreen = new QLabel(this); valueToScreen->setText("prova"); layout->addWidget(valueToScreen); #endif layout->addWidget(mainView); setLayout(layout); QFont font; // Customize chart title font.setPixelSize(FONT_DIM_DEF); timeNow=QDateTime::currentDateTime(); timeNowMs=timeNow.toMSecsSinceEpoch(); timeStart=timeNow; timeStartMs=timeNowMs; commonX= new QDateTimeAxis; commonX->setFormat("h:mm:ss"); commonX->setTickCount(0); commonX->setGridLineVisible(false); commonX->setMin(timeNow.addSecs(-60)); if (UPDATE_OPTIMIZED) commonX->setMax(timeNow.addSecs(TIME_UPDATE_XMAX)); else commonX->setMax(timeNow); temperatureY=new QValueAxis; temperatureY->setGridLineVisible(false); temperatureY->setVisible(true); temperatureY->setTitleText("Temp(C)"); temperatureY->setTitleFont(font); temperatureY->setTitleVisible(true); temperatureY->setRange(TEMP_DEF_MIN, TEMP_DEF_MAX); currentY=new QValueAxis; currentY->setGridLineVisible(false); currentY->setVisible(true); currentY->setTitleText("Curr(A)"); currentY->setTitleFont(font); currentY->setTitleVisible(true); currentY->setRange(CURR_DEF_MIN, CURR_DEF_MAX); voltageY=new QValueAxis; voltageY->setGridLineVisible(false); voltageY->setVisible(true); voltageY->setTitleText("Volt(V)"); voltageY->setTitleFont(font); voltageY->setTitleVisible(true); voltageY->setRange(VOLT_DEF_MIN, VOLT_DEF_MAX); ch->addAxis(commonX, AXIS_ALIGNMENT_DATE); mainView->setOptimizationFlag(QGraphicsView::DontSavePainterState, true); mainView->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, true); mainView->setRenderHint(QPainter::Antialiasing, false); mainView->setRenderHint(QPainter::TextAntialiasing, false); mainView->setRenderHint(QPainter::SmoothPixmapTransform, false); mainView->setRubberBand( QChartView::HorizontalRubberBand ); mainView->chart()->setBackgroundRoundness(0); mainView->chart()->setMargins(QMargins(0, 0, 0, 0)); mainView->chart()->legend()->setVisible(true); mainView->chart()->legend()->setAlignment(Qt::AlignTop); autopurge_enabled = Qt::Unchecked; setPenDim(PEN_DIM_DEF); report_enabled = REPORT_ENABLED_DEF; } int XlruChartClass::findSensor(QString _label) { int idx = 0; foreach (Sensor *s, list_sensors) { if (s->label == _label) return idx; idx++; } return -1; } int XlruChartClass::findSensorName(QString _name) { int idx = 0; foreach (Sensor *s, list_sensors) { if (s->name == _name) return idx; idx++; } return -1; } int XlruChartClass::addSensorFromConfig(sensor_config_t *sensor_config) { //int count_sensor = list_sensors.count(); int idx = findSensorName(sensor_config->name); if (idx != -1) { //Already exist!! return -1; } if ((report_enabled) && (report!=0)) report->addSensorCol(sensor_config->label_sensor); Sensor *newSensor = new Sensor(); QLineSeries* s; newSensor->view=mainView; newSensor->name = sensor_config->name; newSensor->label = sensor_config->label_sensor; newSensor->type_serie = sensor_config->type; newSensor->limit = sensor_config->limit; newSensor->limitFlag = true; newSensor->fpga_ch = sensor_config->fpga_ch; switch (newSensor->type_serie) { case type_s_temperature: newSensor->axis=temperatureY; if (ch->axes().indexOf(temperatureY, 0)==-1) ch->addAxis(temperatureY, AXIS_ALIGNMENT_TEMP); s=addSeries(sensor_config->label_sensor, temperatureY); break; case type_s_current: newSensor->axis=currentY; if (ch->axes().indexOf(currentY, 0)==-1) ch->addAxis(currentY, AXIS_ALIGNMENT_CURR); s=addSeries(sensor_config->label_sensor, currentY); break; case type_s_voltage: newSensor->axis=voltageY; if (ch->axes().indexOf(voltageY, 0)==-1) ch->addAxis(voltageY, AXIS_ALIGNMENT_CURR); s=addSeries(sensor_config->label_sensor, voltageY); break; default: break; } QPen pen = s->pen(); pen.setWidth(penDim); s->setPen(pen); s->setName(QString("%1(%2)").arg(sensor_config->label_sensor).arg(sensor_config->limit)); newSensor->series=s; list_sensors.append(newSensor); #ifdef USE_TABLE //add sensor table if (SensorsTable!=nullptr) { SensorsTable->addNewSensor(sensor_config->label_sensor); } #endif return list_sensors.size(); } QLineSeries* XlruChartClass::addSeries(QString _name, QValueAxis* _axis) { QLineSeries* new_series=new QLineSeries; //list_series.append(new_series); ch->addSeries(new_series); ch->setAxisX(commonX, new_series); ch->setAxisY(_axis, new_series); new_series->setName(_name); return new_series; } void XlruChartClass::addSample(QString name_sensor , float value) { int idx = findSensorName(name_sensor); if (idx == -1) { //sensor not exists return; } QLineSeries* s=list_sensors[idx]->series; QString sensor_label = list_sensors[idx]->label; if (s==0) return; #ifdef TELEMETRY if (telemetry!=0) telemetry->start("add to serie"); #endif if (UPDATE_OPTIMIZED) { //controlla se manca meno di TIME_DELTA_XMAX secondi da xmax qint64 axisXmaxNum= commonX->max().toMSecsSinceEpoch(); qint64 nowNum= timeNow.toMSecsSinceEpoch(); qint64 delta = axisXmaxNum - nowNum; if (delta< TIME_DELTA_XMAX*1000) //10 seconds { QDateTime newmax = timeNow.addSecs(TIME_UPDATE_XMAX); commonX->setMax(newmax); } } lastSampleMs=timeNowMs; s->append(timeNowMs, value); #ifdef TELEMETRY if (telemetry!=0) telemetry->stop(); #endif if ((report!=0) && (report_enabled)) { #ifdef TELEMETRY if (telemetry!=0) telemetry->start("update report"); #endif report->addValueCol(sensor_label , value); #ifdef TELEMETRY if (telemetry!=0) telemetry->stop(); #endif } #ifdef TRACKING_VALUE valueToScreen->setText(QString("%1 %2").arg(timeNowMs).arg(value)); #endif #ifdef TELEMETRY if (telemetry!=0) telemetry->start("update axis"); #endif Sensor *se = list_sensors[idx]; QtCharts::QValueAxis *a=se->axis; if (a!=0) { if (a->min()>value) { a->setMin(value-1.0); } else if (a->max()setMax(value+1.0); } } //if (!getRemoveLimit()) { if ((se->limitFlag) && (value>=se->limit)) { QApplication::beep(); switch (se->type_serie) { case type_s_temperature: showWarning(QString("%1 -> Over-temperature (%2 celsius)").arg(s->name()).arg(value)); break; case type_s_current: showWarning(QString("%1 -> Over-current (%2 ampere)").arg(s->name()).arg(value)); break; case type_s_voltage: showWarning(QString("%1 -> Over-voltage (%2 volt)").arg(s->name()).arg(value)); break; } } } #ifdef USE_TABLE //add sensor table if (SensorsTable!=nullptr) { SensorsTable->update_sensor(sensor_label, value); } #endif #ifdef TELEMETRY if (telemetry!=0) telemetry->stop(); #endif } void XlruChartClass::timerEvent() { timeNow=QDateTime::currentDateTime(); timeNowMs=timeNow.toMSecsSinceEpoch(); if ((timeNowMs-lastSampleMs)>1000*10) //Dead? { //p_.tgtAlive=false; } else { if (! UPDATE_OPTIMIZED) commonX->setMax(timeNow); switch(autopurge_enabled) { default: case Qt::Unchecked: break; case Qt::PartiallyChecked: { qint64 delta=timeNowMs-timeStartMs; if (delta>(1000*60*60)) //1h { timeStart=timeNow.addMSecs(-60*PURGE_PARTIAL_DEF*1000); timeStartMs=timeStart.toMSecsSinceEpoch(); commonX->setMin(timeStart); } } break; case Qt::Checked: { //if (!p_.tgtAlive) { timeStart=timeNow.addMSecs(-60*PURGE_DEF*1000); timeStartMs=timeStart.toMSecsSinceEpoch(); commonX->setMin(timeStart); } } break; } } } void XlruChartClass::setReport(bool enabled) { report_enabled = enabled; } void XlruChartClass::connectMarkers() { // Connect all markers to handler foreach (QLegendMarker* marker, ch->legend()->markers()) { // Disconnect possible existing connection to avoid multiple connections QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked())); QObject::connect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked())); } } void XlruChartClass::disconnectMarkers() { foreach (QLegendMarker* marker, ch->legend()->markers()) { QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked())); } } void XlruChartClass::handleMarkerClicked() { QLegendMarker* marker = qobject_cast (sender()); Q_ASSERT(marker); switch (marker->type()) { case QLegendMarker::LegendMarkerTypeXY: { // Toggle visibility of series marker->series()->setVisible(!marker->series()->isVisible()); // Turn legend marker back to visible, since hiding series also hides the marker // and we don't want it to happen now. marker->setVisible(true); // Dim the marker, if series is not visible qreal alpha = 1.0; if (!marker->series()->isVisible()) { alpha = 0.5; } QColor color; QBrush brush = marker->labelBrush(); color = brush.color(); color.setAlphaF(alpha); brush.setColor(color); marker->setLabelBrush(brush); brush = marker->brush(); color = brush.color(); color.setAlphaF(alpha); brush.setColor(color); marker->setBrush(brush); QPen pen = marker->pen(); color = pen.color(); color.setAlphaF(alpha); pen.setColor(color); marker->setPen(pen); break; } default: { qDebug() << "Unknown marker type"; break; } } } void XlruChartClass::connectTooltip() { // Connect all series to handler foreach (Sensor *s, list_sensors) { connect(s->series, &QLineSeries::clicked, this, &XlruChartClass::keepCallout); connect(s->series, &QLineSeries::hovered, this, &XlruChartClass::tooltip); } } void XlruChartClass::keepCallout() { QAbstractSeries *series = qobject_cast(sender()); m_callouts.append(m_tooltip); m_tooltip = new Callout(ch, series); m_tooltip->hide(); } void XlruChartClass::tooltip(QPointF point, bool state) { QAbstractSeries *series = qobject_cast(sender()); if (m_tooltip == 0) { m_tooltip = new Callout(ch, series); } if (state) { m_tooltip->setSeries(series); //QPointF pointFound = ch->mapToValue(point, series); qreal yVal = point.y(); m_tooltip->setText(QString().sprintf("%s\n %0.2f", series->name().toStdString().c_str(), yVal)); m_tooltip->setAnchor(point); m_tooltip->updateGeometry(); m_tooltip->show(); } else { m_tooltip->hide(); } } void XlruChartClass::showWarning(QString _mess) { alertBox.setText(_mess); alertBox.setIcon(QMessageBox::Warning); alertBox.setWindowTitle("WARNING"); alertBox.setWindowFlags(Qt::WindowStaysOnTopHint); alertBox.setModal( false ); alertBox.show(); alertBox.raise(); } void XlruChartClass::setPenDim(int _dim) { penDim = _dim; } void XlruChartClass::purge() { auto ts=timeNow.addSecs(-60*PURGE_DEF); timeStart=ts; timeStartMs=ts.toMSecsSinceEpoch(); commonX->setMin(ts); } void XlruChartClass::clear() { foreach (Sensor *s, list_sensors) { s->series->clear(); } commonX->setMin(commonX->max().addSecs(-60)); } void XlruChartClass::save_header_info() { if ((report!=0) && (report_enabled)) { report->saveHeader(); } } void XlruChartClass::save_all_sample() { if ((report!=0) && (report_enabled)) { report->saveValue(); } } void XlruChartClass::setRemoveLimit(bool new_value) { remove_limit = new_value; } bool XlruChartClass::getRemoveLimit() { return remove_limit; } #ifdef TELEMETRY void XlruChartClass::setTelemetry(telemetryClass *_telemetry) { telemetry = _telemetry; } #endif