# HG changeset patch # User Hasan Yavuz ÖZDERYA # Date 2016-03-21 18:28:28 # Node ID 1a05d0ad46b086b0ef84e7b173d3118c1e9fafcd # Parent 3f92e133ff7be14f4509b98b331c31e1c301efce integrated preliminary implementation of channelmanager channel name list is a loose widget, code is still a mess diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ add_executable(${PROGRAM_NAME} WIN32 src/dataformatpanel.cpp src/tooltipfilter.cpp src/sneakylineedit.cpp + src/channelmanager.cpp misc/windows_icon.rc ${UI_FILES} ${RES_FILES} diff --git a/serialplot.pro b/serialplot.pro --- a/serialplot.pro +++ b/serialplot.pro @@ -52,7 +52,8 @@ SOURCES += \ src/commandedit.cpp \ src/dataformatpanel.cpp \ src/tooltipfilter.cpp \ - src/sneakylineedit.cpp + src/sneakylineedit.cpp \ + src/channelmanager.cpp HEADERS += \ src/mainwindow.h \ @@ -75,7 +76,8 @@ HEADERS += \ src/commandedit.h \ src/dataformatpanel.h \ src/tooltipfilter.h \ - src/sneakylineedit.h + src/sneakylineedit.h \ + src/channelmanager.h FORMS += \ src/mainwindow.ui \ diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp new file mode 100644 --- /dev/null +++ b/src/channelmanager.cpp @@ -0,0 +1,148 @@ +/* + Copyright © 2016 Hasan Yavuz Özderya + + This file is part of serialplot. + + serialplot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + serialplot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with serialplot. If not, see . +*/ + +#include "channelmanager.h" + +#include +#include + +ChannelManager::ChannelManager(unsigned numberOfChannels, unsigned numberOfSamples, QObject *parent) : + QObject(parent) +{ + _numOfChannels = numberOfChannels; + _numOfSamples = numberOfSamples; + + QStringList channelNamesList; + + for (unsigned int i = 0; i < numberOfChannels; i++) + { + channelBuffers.append(new FrameBuffer(numberOfSamples)); + channelNamesList << QString("Channel %1").arg(i+1); + + // curves.append(new QwtPlotCurve(QString("Channel %1").arg(i+1))); + // curves[i]->setSamples(channelBuffers[i]); + // curves[i]->setPen(Plot::makeColor(i)); + // curves[i]->attach(ui->plot); + } + + _channelNames.setStringList(channelNamesList); + + connect(&_channelNames, &QStringListModel::dataChanged, + this, &ChannelManager::onChannelNameDataChange); +} + +ChannelManager::~ChannelManager() +{ + // TODO: remove all channelBuffers +} + +unsigned ChannelManager::numOfChannels() +{ + return channelBuffers.size(); +} + +unsigned ChannelManager::numOfSamples() +{ + return _numOfSamples; +} + +void ChannelManager::setNumOfChannels(unsigned number) +{ + unsigned int oldNum = channelBuffers.size(); + + if (number > oldNum) + { + // add new channels + for (unsigned int i = 0; i < number - oldNum; i++) + { + channelBuffers.append(new FrameBuffer(_numOfSamples)); + addChannelName(QString("Channel %1").arg(oldNum+i+1)); + } + } + else if(number < oldNum) + { + // remove channels + for (unsigned int i = 0; i < oldNum - number; i++) + { + // also deletes owned FrameBuffer + // delete curves.takeLast(); + // TODO: important, remove channelBuffer + channelBuffers.removeLast(); + } + } + + emit numOfChannelsChanged(number); +} + +void ChannelManager::setNumOfSamples(unsigned number) +{ + _numOfSamples = number; + + for (int ci = 0; ci < channelBuffers.size(); ci++) + { + channelBuffers[ci]->resize(_numOfSamples); + } + + emit numOfSamplesChanged(number); +} + +FrameBuffer* ChannelManager::channelBuffer(unsigned channel) +{ + return channelBuffers[channel]; +} + +QStringListModel* ChannelManager::channelNames() +{ + return &_channelNames; +} + +QString ChannelManager::channelName(unsigned channel) +{ + return _channelNames.data(_channelNames.index(channel, 0), Qt::DisplayRole).toString(); +} + +void ChannelManager::setChannelName(unsigned channel, QString name) +{ + _channelNames.setData(_channelNames.index(channel, 0), QVariant(name), Qt::DisplayRole); +} + +void ChannelManager::addChannelName(QString name) +{ + _channelNames.insertRow(_channelNames.rowCount()); + setChannelName(_channelNames.rowCount()-1, name); +} + +void ChannelManager::onChannelNameDataChange(const QModelIndex & topLeft, + const QModelIndex & bottomRight, + const QVector & roles) +{ + int start = topLeft.row(); + int end = bottomRight.row(); + + // TODO: maybe check `roles` parameter, can't think of a reason for current use case + for (int i = start; i <= end; i++) + { + emit channelNameChanged(i, channelName(i)); + } +} + +void ChannelManager::addChannelData(unsigned channel, double* data, unsigned size) +{ + channelBuffer(channel)->addSamples(data, size); +} diff --git a/src/channelmanager.h b/src/channelmanager.h new file mode 100644 --- /dev/null +++ b/src/channelmanager.h @@ -0,0 +1,68 @@ +/* + Copyright © 2016 Hasan Yavuz Özderya + + This file is part of serialplot. + + serialplot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + serialplot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with serialplot. If not, see . +*/ + +#ifndef CHANNELMANAGER_H +#define CHANNELMANAGER_H + +#include +#include +#include +#include + +#include "framebuffer.h" + +class ChannelManager : public QObject +{ + Q_OBJECT +public: + explicit ChannelManager(unsigned numberOfChannels, unsigned numberOfSamples, QObject *parent = 0); + ~ChannelManager(); + + unsigned numOfChannels(); + unsigned numOfSamples(); + FrameBuffer* channelBuffer(unsigned channel); + QStringListModel* channelNames(); + QString channelName(unsigned channel); + +signals: + void numOfChannelsChanged(unsigned value); + void numOfSamplesChanged(unsigned value); + void channelNameChanged(unsigned channel, QString name); + +public slots: + void setNumOfChannels(unsigned number); + void setNumOfSamples(unsigned number); + void setChannelName(unsigned channel, QString name); + void addChannelData(unsigned channel, double* data, unsigned size); + +private: + unsigned _numOfChannels; + unsigned _numOfSamples; + QList channelBuffers; + QStringListModel _channelNames; + + void addChannelName(QString name); /// appends a new channel name at the end of list + +private slots: + void onChannelNameDataChange(const QModelIndex & topLeft, + const QModelIndex & bottomRight, + const QVector & roles = QVector ()); +}; + +#endif // CHANNELMANAGER_H diff --git a/src/dataformatpanel.cpp b/src/dataformatpanel.cpp --- a/src/dataformatpanel.cpp +++ b/src/dataformatpanel.cpp @@ -26,7 +26,7 @@ #include "floatswap.h" DataFormatPanel::DataFormatPanel(QSerialPort* port, - QList* channelBuffers, + ChannelManager* channelMan, QWidget *parent) : QWidget(parent), ui(new Ui::DataFormatPanel) @@ -34,7 +34,7 @@ DataFormatPanel::DataFormatPanel(QSerial ui->setupUi(this); serialPort = port; - _channelBuffers = channelBuffers; + _channelMan = channelMan; paused = false; // setup number format buttons @@ -319,6 +319,6 @@ template double DataFormatPa void DataFormatPanel::addChannelData(unsigned int channel, double* data, unsigned size) { - (*_channelBuffers)[channel]->addSamples(data, size); + _channelMan->addChannelData(channel, data, size); sampleCount += size; } diff --git a/src/dataformatpanel.h b/src/dataformatpanel.h --- a/src/dataformatpanel.h +++ b/src/dataformatpanel.h @@ -28,6 +28,7 @@ #include #include "framebuffer.h" +#include "channelmanager.h" namespace Ui { class DataFormatPanel; @@ -39,7 +40,7 @@ class DataFormatPanel : public QWidget public: explicit DataFormatPanel(QSerialPort* port, - QList* channelBuffers, + ChannelManager* channelMan, QWidget *parent = 0); ~DataFormatPanel(); @@ -77,7 +78,7 @@ private: QButtonGroup numberFormatButtons; QSerialPort* serialPort; - QList* _channelBuffers; + ChannelManager* _channelMan; unsigned int _numOfChannels; NumberFormat numberFormat; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -31,6 +31,9 @@ #include #include +// test code +#include + #include #include "utils.h" @@ -54,9 +57,10 @@ MainWindow::MainWindow(QWidget *parent) ui(new Ui::MainWindow), aboutDialog(this), portControl(&serialPort), + channelMan(1, 1, this), commandPanel(&serialPort), - dataFormatPanel(&serialPort, &channelBuffers), - snapshotMan(this, &channelBuffers) + dataFormatPanel(&serialPort, &channelMan), + snapshotMan(this, &channelMan) { ui->setupUi(this); ui->tabWidget->insertTab(0, &portControl, "Port"); @@ -148,17 +152,28 @@ MainWindow::MainWindow(QWidget *parent) numOfSamples = ui->spNumOfSamples->value(); unsigned numOfChannels = dataFormatPanel.numOfChannels(); - QObject::connect(&dataFormatPanel, - &DataFormatPanel::numOfChannelsChanged, - this, - &MainWindow::onNumOfChannelsChanged); + channelMan.setNumOfSamples(ui->spNumOfSamples->value()); + channelMan.setNumOfChannels(dataFormatPanel.numOfChannels()); + + connect(&dataFormatPanel, &DataFormatPanel::numOfChannelsChanged, + &channelMan, &ChannelManager::setNumOfChannels); + + connect(&channelMan, &ChannelManager::numOfChannelsChanged, + this, &MainWindow::onNumOfChannelsChanged); + + connect(&channelMan, &ChannelManager::channelNameChanged, + this, &MainWindow::onChannelNameChanged); + + // TODO: move this into the plot tab + QListView* channelNamesView = new QListView(); + channelNamesView->setModel(channelMan.channelNames()); + channelNamesView->show(); // init channel data and curve list for (unsigned int i = 0; i < numOfChannels; i++) { - channelBuffers.append(new FrameBuffer(numOfSamples)); - curves.append(new QwtPlotCurve(QString("Channel %1").arg(i+1))); - curves[i]->setSamples(channelBuffers[i]); + curves.append(new QwtPlotCurve(channelMan.channelName(i))); + curves[i]->setSamples(channelMan.channelBuffer(i)); curves[i]->setPen(Plot::makeColor(i)); curves[i]->attach(ui->plot); } @@ -314,9 +329,9 @@ required privileges or device is already void MainWindow::clearPlot() { - for (int ci = 0; ci < channelBuffers.size(); ci++) + for (unsigned ci = 0; ci < channelMan.numOfChannels(); ci++) { - channelBuffers[ci]->clear(); + channelMan.channelBuffer(ci)->clear(); } ui->plot->replot(); } @@ -324,30 +339,28 @@ void MainWindow::clearPlot() void MainWindow::onNumOfSamplesChanged(int value) { numOfSamples = value; - - for (int ci = 0; ci < channelBuffers.size(); ci++) - { - channelBuffers[ci]->resize(numOfSamples); - } - + channelMan.setNumOfSamples(value); ui->plot->replot(); } void MainWindow::onNumOfChannelsChanged(unsigned value) { - unsigned int oldNum = channelBuffers.size(); + unsigned int oldNum = curves.size(); unsigned numOfChannels = value; if (numOfChannels > oldNum) { // add new channels - for (unsigned int i = 0; i < numOfChannels - oldNum; i++) + for (unsigned int i = oldNum; i < numOfChannels; i++) { - channelBuffers.append(new FrameBuffer(numOfSamples)); - curves.append(new QwtPlotCurve(QString("Channel %1").arg(oldNum+i+1))); - curves.last()->setSamples(channelBuffers.last()); - curves.last()->setPen(Plot::makeColor(curves.length()-1)); - curves.last()->attach(ui->plot); + QwtPlotCurve* curve = new QwtPlotCurve(channelMan.channelName(i)); + // TODO: create a wrapper around FrameBuffer that holds a + // pointer to it and provides the QwtDataSeries interface, + // that wrapper should be created for and owned by 'curve' + curve->setSamples(channelMan.channelBuffer(i)); + curve->setPen(Plot::makeColor(i)); + curve->attach(ui->plot); + curves.append(curve); } } else if(numOfChannels < oldNum) @@ -355,11 +368,24 @@ void MainWindow::onNumOfChannelsChanged( // remove channels for (unsigned int i = 0; i < oldNum - numOfChannels; i++) { - // also deletes owned FrameBuffer + // also deletes owned FrameBuffer TODO: which souldn't happen delete curves.takeLast(); - channelBuffers.removeLast(); } } + + ui->plot->replot(); +} + +void MainWindow::onChannelNameChanged(unsigned channel, QString name) +{ + // This slot is triggered also when a new channel is added, in + // this case curve list doesn't contain said channel. No worries, + // since `onNumOfChannelsChanged` slot will update curve list. + if (channel < curves.size()) // check if channel exists in curve list + { + curves[channel]->setTitle(name); + ui->plot->replot(); + } } void MainWindow::onAutoScaleChecked(bool checked) @@ -449,7 +475,7 @@ void MainWindow::onExportCsv() { QTextStream fileStream(&file); - unsigned numOfChannels = channelBuffers.size(); + unsigned numOfChannels = channelMan.numOfChannels(); for (unsigned int ci = 0; ci < numOfChannels; ci++) { fileStream << "Channel " << ci; @@ -461,7 +487,7 @@ void MainWindow::onExportCsv() { for (unsigned int ci = 0; ci < numOfChannels; ci++) { - fileStream << channelBuffers[ci]->sample(i).y(); + fileStream << channelMan.channelBuffer(ci)->sample(i).y(); if (ci != numOfChannels-1) fileStream << ","; } fileStream << '\n'; diff --git a/src/mainwindow.h b/src/mainwindow.h --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -39,6 +39,7 @@ #include "dataformatpanel.h" #include "ui_about_dialog.h" #include "framebuffer.h" +#include "channelmanager.h" #include "snapshotmanager.h" namespace Ui { @@ -69,7 +70,8 @@ private: QList curves; // Note: FrameBuffer s are owned by their respective QwtPlotCurve s. - QList channelBuffers; + // QList channelBuffers; + ChannelManager channelMan; QLabel spsLabel; @@ -90,6 +92,7 @@ private slots: void onYScaleChanged(); void onRangeSelected(); void onNumOfChannelsChanged(unsigned value); + void onChannelNameChanged(unsigned channel, QString name); void clearPlot(); diff --git a/src/snapshotmanager.cpp b/src/snapshotmanager.cpp --- a/src/snapshotmanager.cpp +++ b/src/snapshotmanager.cpp @@ -28,14 +28,14 @@ #include "snapshotmanager.h" SnapshotManager::SnapshotManager(QMainWindow* mainWindow, - QList* channelBuffers) : + ChannelManager* channelMan) : _menu("Snapshots"), _takeSnapshotAction("Take Snapshot", this), loadSnapshotAction("Load Snapshots", this), clearAction("Clear Snapshots", this) { _mainWindow = mainWindow; - _channelBuffers = channelBuffers; + _channelMan = channelMan; _takeSnapshotAction.setToolTip("Take a snapshot of current plot"); _takeSnapshotAction.setShortcut(QKeySequence("F5")); @@ -64,15 +64,15 @@ void SnapshotManager::takeSnapshot() QString name = QTime::currentTime().toString("'Snapshot ['HH:mm:ss']'"); auto snapshot = new Snapshot(_mainWindow, name); - unsigned numOfChannels = _channelBuffers->size(); - unsigned numOfSamples = _channelBuffers->at(0)->size(); + unsigned numOfChannels = _channelMan->numOfChannels(); + unsigned numOfSamples = _channelMan->numOfSamples(); for (unsigned ci = 0; ci < numOfChannels; ci++) { snapshot->data.append(QVector(numOfSamples)); for (unsigned i = 0; i < numOfSamples; i++) { - snapshot->data[ci][i] = _channelBuffers->at(ci)->sample(i); + snapshot->data[ci][i] = _channelMan->channelBuffer(ci)->sample(i); } } diff --git a/src/snapshotmanager.h b/src/snapshotmanager.h --- a/src/snapshotmanager.h +++ b/src/snapshotmanager.h @@ -25,6 +25,7 @@ #include #include "framebuffer.h" +#include "channelmanager.h" #include "snapshot.h" class SnapshotManager : public QObject @@ -32,7 +33,7 @@ class SnapshotManager : public QObject Q_OBJECT public: - SnapshotManager(QMainWindow* mainWindow, QList* channelBuffers); + SnapshotManager(QMainWindow* mainWindow, ChannelManager* channelMan); ~SnapshotManager(); QMenu* menu(); @@ -40,7 +41,7 @@ public: private: QMainWindow* _mainWindow; - QList* _channelBuffers; + ChannelManager* _channelMan; QList snapshots;