diff --git a/snapshotmanager.cpp b/snapshotmanager.cpp
new file mode 100644
--- /dev/null
+++ b/snapshotmanager.cpp
@@ -0,0 +1,198 @@
+/*
+  Copyright © 2015 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "snapshotmanager.h"
+
+SnapshotManager::SnapshotManager(QMainWindow* mainWindow,
+                                 QList* channelBuffers) :
+    _menu("Snapshots"),
+    _takeSnapshotAction("Take Snapshot", this),
+    loadSnapshotAction("Load Snapshots", this),
+    clearAction("Clear Snapshots", this)
+{
+    _mainWindow = mainWindow;
+    _channelBuffers = channelBuffers;
+
+    _takeSnapshotAction.setToolTip("Take a snapshot of current plot (F5)");
+    _takeSnapshotAction.setShortcut(QKeySequence("F5"));
+    loadSnapshotAction.setToolTip("Load snapshots from CSV files");
+    clearAction.setToolTip("Delete all snapshots");
+    connect(&_takeSnapshotAction, SIGNAL(triggered(bool)),
+            this, SLOT(takeSnapshot()));
+    connect(&clearAction, SIGNAL(triggered(bool)),
+            this, SLOT(clearSnapshots()));
+    connect(&loadSnapshotAction, SIGNAL(triggered(bool)),
+            this, SLOT(loadSnapshots()));
+
+    updateMenu();
+}
+
+SnapshotManager::~SnapshotManager()
+{
+    for (auto snapshot : snapshots)
+    {
+        delete snapshot;
+    }
+}
+
+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();
+
+    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);
+        }
+    }
+
+    addSnapshot(snapshot);
+}
+
+void SnapshotManager::addSnapshot(Snapshot* snapshot, bool update_menu)
+{
+    snapshots.append(snapshot);
+    QObject::connect(snapshot, &Snapshot::deleteRequested,
+                     this, &SnapshotManager::deleteSnapshot);
+    if (update_menu) updateMenu();
+}
+
+void SnapshotManager::updateMenu()
+{
+    _menu.clear();
+    _menu.addAction(&_takeSnapshotAction);
+    _menu.addAction(&loadSnapshotAction);
+    if (snapshots.size())
+    {
+        _menu.addSeparator();
+        for (auto ss : snapshots)
+        {
+            _menu.addAction(ss->showAction());
+        }
+        _menu.addSeparator();
+        _menu.addAction(&clearAction);
+    }
+}
+
+void SnapshotManager::clearSnapshots()
+{
+    for (auto snapshot : snapshots)
+    {
+        delete snapshot;
+    }
+    snapshots.clear();
+    updateMenu();
+}
+
+void SnapshotManager::deleteSnapshot(Snapshot* snapshot)
+{
+    snapshots.removeOne(snapshot);
+    snapshot->deleteLater(); // regular delete causes a crash when triggered from menu
+    updateMenu();
+}
+
+void SnapshotManager::loadSnapshots()
+{
+    auto files = QFileDialog::getOpenFileNames(_mainWindow, tr("Load CSV File"));
+
+    for (auto f : files)
+    {
+        if (!f.isNull()) loadSnapshotFromFile(f);
+    }
+
+    updateMenu();
+}
+
+void SnapshotManager::loadSnapshotFromFile(QString fileName)
+{
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+    {
+        qCritical() << "Couldn't open file: " << fileName;
+        qCritical() << file.errorString();
+        return;
+    }
+
+    // read first row as headlines and determine number of channels
+    auto headLine = QString(file.readLine());
+    unsigned numOfChannels = headLine.split(',').size();
+
+    // read data
+    QVector> data(numOfChannels);
+    unsigned lineNum = 1;
+    while (file.canReadLine())
+    {
+        // parse line
+        auto line = QString(file.readLine());
+        auto split = line.split(',');
+
+        if (split.size() != (int) numOfChannels)
+        {
+            qCritical() << "Parsing error at line " << lineNum
+                        << ": number of columns is not consistent.";
+            return;
+        }
+
+        for (unsigned ci = 0; ci < numOfChannels; ci++)
+        {
+            // parse column
+            bool ok;
+            double y = split[ci].toDouble(&ok);
+            if (!ok)
+            {
+                qCritical() << "Parsing error at line " << lineNum
+                            << ", column " << ci
+                            << ": can't convert \"" << split[ci]
+                            << "\" to double.";
+                return;
+            }
+            data[ci].append(QPointF(lineNum-1, y));
+        }
+        lineNum++;
+    }
+
+    auto snapshot = new Snapshot(_mainWindow, QFileInfo(fileName).baseName());
+    snapshot->data = data;
+
+    addSnapshot(snapshot, false);
+}
+
+QMenu* SnapshotManager::menu()
+{
+    return &_menu;
+}
+
+QAction* SnapshotManager::takeSnapshotAction()
+{
+    return &_takeSnapshotAction;
+}