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;