]> sigrok.org Git - pulseview.git/commitdiff
Implement multi-session handling
authorSoeren Apel <redacted>
Sat, 27 Aug 2016 19:55:57 +0000 (21:55 +0200)
committerSoeren Apel <redacted>
Sat, 27 Aug 2016 19:55:57 +0000 (21:55 +0200)
This includes letting sessions restore their internal state on
their own and that there are unique names associated with each
session that the GUI can use when there is no data.

pv/mainwindow.cpp
pv/mainwindow.hpp
pv/session.cpp
pv/session.hpp
pv/toolbars/mainbar.cpp
pv/toolbars/mainbar.hpp

index f8463257b5b882531692abc3c0ab4803efdcfa64..6e408583a52d0cb1e7e2c45870c950cbedc4094f 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "devicemanager.hpp"
 #include "util.hpp"
+#include "devices/hardwaredevice.hpp"
 #include "dialogs/about.hpp"
 #include "toolbars/mainbar.hpp"
 #include "view/view.hpp"
@@ -46,6 +47,7 @@
 #include <stdarg.h>
 #include <libsigrokcxx/libsigrokcxx.hpp>
 
+using std::dynamic_pointer_cast;
 using std::list;
 using std::make_shared;
 using std::map;
@@ -65,9 +67,6 @@ MainWindow::MainWindow(DeviceManager &device_manager,
        QWidget *parent) :
        QMainWindow(parent),
        device_manager_(device_manager),
-       session_(device_manager),
-       open_file_name_(open_file_name),
-       open_file_format_(open_file_format),
        action_view_sticky_scrolling_(new QAction(this)),
        action_view_coloured_bg_(new QAction(this)),
        action_about_(new QAction(this))
@@ -76,6 +75,32 @@ MainWindow::MainWindow(DeviceManager &device_manager,
 
        setup_ui();
        restore_ui_settings();
+
+       if (!open_file_name.empty()) {
+               shared_ptr<Session> session = add_session();
+               session->main_bar()->load_init_file(open_file_name, open_file_format);
+       }
+
+       // Add empty default session if there aren't any sessions
+       if (sessions_.size() == 0) {
+               shared_ptr<Session> session = add_session();
+
+               map<string, string> dev_info;
+               shared_ptr<devices::HardwareDevice> other_device, demo_device;
+
+               // Use any available device that's not demo
+               for (shared_ptr<devices::HardwareDevice> dev : device_manager_.devices()) {
+                       if (dev->hardware_device()->driver()->name() == "demo") {
+                               demo_device = dev;
+                       } else {
+                               other_device = dev;
+                       }
+               }
+
+               // ...and if there isn't any, just use demo then
+               session->main_bar()->select_device(other_device ?
+                       other_device : demo_device);
+       }
 }
 
 MainWindow::~MainWindow()
@@ -92,7 +117,10 @@ MainWindow::~MainWindow()
                dock->setWidget(0);
 
                const std::shared_ptr<pv::view::View> view = entry.second;
-               session_.deregister_view(view);
+
+               for (shared_ptr<Session> session : sessions_)
+                       if (session->has_view(view))
+                               session->deregister_view(view);
        }
 }
 
@@ -173,13 +201,9 @@ shared_ptr<pv::view::View> MainWindow::add_view(const QString &title,
 
                        shared_ptr<MainBar> main_bar = session.main_bar();
                        if (!main_bar) {
-                               main_bar = make_shared<MainBar>(session_, *this,
-                                       open_file_name_, open_file_format_);
+                               main_bar = make_shared<MainBar>(session, *this);
                                dock_main->addToolBar(main_bar.get());
                                session.set_main_bar(main_bar);
-
-                               open_file_name_.clear();
-                               open_file_format_.clear();
                        }
                        main_bar->action_view_show_cursors()->setChecked(v->cursors_shown());
                }
@@ -188,6 +212,21 @@ shared_ptr<pv::view::View> MainWindow::add_view(const QString &title,
        return v;
 }
 
+shared_ptr<Session> MainWindow::add_session()
+{
+       int id = sessions_.size();
+       QString name = tr("Untitled-%1").arg(id + 1);
+
+       shared_ptr<Session> session = make_shared<Session>(device_manager_, name);
+
+       sessions_.push_back(session);
+
+       shared_ptr<view::View> main_view =
+               add_view(name, pv::view::TraceView, *session);
+
+       return session;
+}
+
 void MainWindow::setup_ui()
 {
        setObjectName(QString::fromUtf8("MainWindow"));
@@ -214,10 +253,6 @@ void MainWindow::setup_ui()
        action_about_->setObjectName(QString::fromUtf8("actionAbout"));
        action_about_->setText(tr("&About..."));
 
-       // Set up the initial view
-       shared_ptr<view::View> main_view =
-               add_view(tr("Untitled"), pv::view::TraceView, session_);
-
        // Set the title
        setWindowTitle(tr("PulseView"));
 }
@@ -225,41 +260,36 @@ void MainWindow::setup_ui()
 void MainWindow::save_ui_settings()
 {
        QSettings settings;
-
-       map<string, string> dev_info;
-       list<string> key_list;
+       int id = 0;
 
        settings.beginGroup("MainWindow");
        settings.setValue("state", saveState());
        settings.setValue("geometry", saveGeometry());
        settings.endGroup();
 
-       if (session_.device()) {
-               settings.beginGroup("Device");
-               key_list.push_back("vendor");
-               key_list.push_back("model");
-               key_list.push_back("version");
-               key_list.push_back("serial_num");
-               key_list.push_back("connection_id");
-
-               dev_info = device_manager_.get_device_info(
-                       session_.device());
-
-               for (string key : key_list) {
-                       if (dev_info.count(key))
-                               settings.setValue(QString::fromUtf8(key.c_str()),
-                                               QString::fromUtf8(dev_info.at(key).c_str()));
-                       else
-                               settings.remove(QString::fromUtf8(key.c_str()));
+       for (shared_ptr<Session> session : sessions_) {
+               // Ignore sessions using the demo device
+               if (session->device()) {
+                       shared_ptr<devices::HardwareDevice> device =
+                               dynamic_pointer_cast< devices::HardwareDevice >
+                               (session->device());
+
+                       if (device->hardware_device()->driver()->name() == "demo")
+                               continue;
                }
 
+               settings.beginGroup("Session" + QString::number(id++));
+               session->save_settings(settings);
                settings.endGroup();
        }
+
+       settings.setValue("sessions", id);
 }
 
 void MainWindow::restore_ui_settings()
 {
        QSettings settings;
+       int i, session_count;
 
        settings.beginGroup("MainWindow");
 
@@ -270,6 +300,15 @@ void MainWindow::restore_ui_settings()
                resize(1000, 720);
 
        settings.endGroup();
+
+       session_count = settings.value("sessions", 0).toInt();
+
+       for (i = 0; i < session_count; i++) {
+               settings.beginGroup("Session" + QString::number(i));
+               shared_ptr<Session> session = add_session();
+               session->restore_settings(settings);
+               settings.endGroup();
+       }
 }
 
 void MainWindow::closeEvent(QCloseEvent *event)
index 485b7b6df18243e8a7aa2085290639b86e6268e5..2e4c6bbdcd5e5d00f921acdb741016fb2a581f37 100644 (file)
@@ -74,6 +74,8 @@ public:
        std::shared_ptr<pv::view::View> add_view(const QString &title,
                view::ViewType type, Session &session);
 
+       std::shared_ptr<Session> add_session();
+
 private:
        void setup_ui();
 
@@ -98,13 +100,11 @@ private Q_SLOTS:
 private:
        DeviceManager &device_manager_;
 
-       Session session_;
+       std::vector< std::shared_ptr<Session> > sessions_;
 
        std::map< std::shared_ptr<QDockWidget>,
                std::shared_ptr<pv::view::View> > view_docks_;
 
-       std::string open_file_name_, open_file_format_;
-
        QAction *const action_view_sticky_scrolling_;
        QAction *const action_view_coloured_bg_;
        QAction *const action_about_;
index fd428ed0ebacd0b5ebe628c2b9893c51101ef8b1..99de77495307386a01be90099c6a6a28402871f5 100644 (file)
@@ -98,8 +98,9 @@ using Glib::VariantBase;
 using Glib::Variant;
 
 namespace pv {
-Session::Session(DeviceManager &device_manager) :
+Session::Session(DeviceManager &device_manager, QString name) :
        device_manager_(device_manager),
+       name_(name),
        capture_state_(Stopped),
        cur_samplerate_(0)
 {
@@ -133,6 +134,21 @@ shared_ptr<devices::Device> Session::device() const
        return device_;
 }
 
+QString Session::name() const
+{
+       return name_;
+}
+
+void Session::set_name(QString name)
+{
+       if (default_name_.isEmpty())
+               default_name_ = name;
+
+       name_ = name;
+
+       name_changed();
+}
+
 std::shared_ptr<pv::view::View> Session::main_view() const
 {
        return main_view_;
@@ -148,6 +164,71 @@ shared_ptr<pv::toolbars::MainBar> Session::main_bar() const
        return main_bar_;
 }
 
+void Session::save_settings(QSettings &settings) const
+{
+       map<string, string> dev_info;
+       list<string> key_list;
+
+       if (device_) {
+               settings.beginGroup("Device");
+               key_list.push_back("vendor");
+               key_list.push_back("model");
+               key_list.push_back("version");
+               key_list.push_back("serial_num");
+               key_list.push_back("connection_id");
+
+               dev_info = device_manager_.get_device_info(device_);
+
+               for (string key : key_list) {
+                       if (dev_info.count(key))
+                               settings.setValue(QString::fromUtf8(key.c_str()),
+                                               QString::fromUtf8(dev_info.at(key).c_str()));
+                       else
+                               settings.remove(QString::fromUtf8(key.c_str()));
+               }
+
+               // TODO Save channel settings and decoders
+
+               settings.endGroup();
+       }
+}
+
+void Session::restore_settings(QSettings &settings)
+{
+       map<string, string> dev_info;
+       list<string> key_list;
+       shared_ptr<devices::HardwareDevice> device;
+
+       // Re-select last used device if possible but only if it's not demo
+       settings.beginGroup("Device");
+       key_list.push_back("vendor");
+       key_list.push_back("model");
+       key_list.push_back("version");
+       key_list.push_back("serial_num");
+       key_list.push_back("connection_id");
+
+       for (string key : key_list) {
+               const QString k = QString::fromStdString(key);
+               if (!settings.contains(k))
+                       continue;
+
+               const string value = settings.value(k).toString().toStdString();
+               if (!value.empty())
+                       dev_info.insert(std::make_pair(key, value));
+       }
+
+       if (dev_info.count("model") > 0)
+               device = device_manager_.find_device_from_info(dev_info);
+
+       if (device) {
+               set_device(device);
+
+               // TODO Restore channel settings and decoders
+       }
+
+       settings.endGroup();
+}
+
 void Session::set_device(shared_ptr<devices::Device> device)
 {
        assert(device);
@@ -160,6 +241,10 @@ void Session::set_device(shared_ptr<devices::Device> device)
 
        device_.reset();
 
+       // Revert name back to default name (e.g. "Untitled-1") as the data is gone
+       name_ = default_name_;
+       name_changed();
+
        // Remove all stored data
        for (std::shared_ptr<pv::view::View> view : views_) {
                view->clear_signals();
@@ -248,6 +333,10 @@ void Session::start_capture(function<void (const QString)> error_handler)
        for (const shared_ptr<data::SignalData> d : all_signal_data_)
                d->clear();
 
+       // Revert name back to default name (e.g. "Untitled-1") as the data is gone
+       name_ = default_name_;
+       name_changed();
+
        // Begin the session
        sampling_thread_ = std::thread(
                &Session::sample_thread_proc, this, error_handler);
@@ -284,6 +373,11 @@ void Session::deregister_view(std::shared_ptr<pv::view::View> view)
        }
 }
 
+bool Session::has_view(std::shared_ptr<pv::view::View> view)
+{
+       return views_.find(view) != views_.end();
+}
+
 double Session::get_samplerate() const
 {
        double samplerate = 0.0;
index d6cfdd302c97815daec25bcf19b62e12008c96e2..258addb9a72de29108c63a94f9afd3dec3deaaa5 100644 (file)
@@ -38,6 +38,7 @@
 #include <boost/thread/shared_mutex.hpp>
 
 #include <QObject>
+#include <QSettings>
 #include <QString>
 
 #include "util.hpp"
@@ -92,7 +93,7 @@ public:
        };
 
 public:
-       Session(DeviceManager &device_manager);
+       Session(DeviceManager &device_manager, QString name);
 
        ~Session();
 
@@ -104,12 +105,20 @@ public:
 
        std::shared_ptr<devices::Device> device() const;
 
+       QString name() const;
+
+       void set_name(QString name);
+
        std::shared_ptr<pv::view::View> main_view() const;
 
        void set_main_bar(std::shared_ptr<pv::toolbars::MainBar> main_bar);
 
        std::shared_ptr<pv::toolbars::MainBar> main_bar() const;
 
+       void save_settings(QSettings &settings) const;
+
+       void restore_settings(QSettings &settings);
+
        /**
         * Sets device instance that will be used in the next capture session.
         */
@@ -129,6 +138,8 @@ public:
 
        void deregister_view(std::shared_ptr<pv::view::View> view);
 
+       bool has_view(std::shared_ptr<pv::view::View> view);
+
        const std::unordered_set< std::shared_ptr<data::SignalBase> >
                signalbases() const;
 
@@ -167,6 +178,7 @@ private:
 private:
        DeviceManager &device_manager_;
        std::shared_ptr<devices::Device> device_;
+       QString default_name_, name_;
 
        std::unordered_set< std::shared_ptr<pv::view::View> > views_;
        std::shared_ptr<pv::view::View> main_view_;
@@ -176,7 +188,6 @@ private:
        mutable std::mutex sampling_mutex_; //!< Protects access to capture_state_.
        capture_state capture_state_;
 
-
        std::unordered_set< std::shared_ptr<data::SignalBase> > signalbases_;
        std::unordered_set< std::shared_ptr<data::SignalData> > all_signal_data_;
 
@@ -197,6 +208,8 @@ Q_SIGNALS:
 
        void signals_changed();
 
+       void name_changed();
+
        void trigger_event(util::Timestamp location);
 
        void frame_began();
index a76ffbaa5c4c684c36addbca278a416ff9e1bf04..6a5992bf53ce60e7872d0e895ba09f49f35646d6 100644 (file)
@@ -87,8 +87,7 @@ const uint64_t MainBar::DefaultSampleCount = 1000000;
 const char *MainBar::SettingOpenDirectory = "MainWindow/OpenDirectory";
 const char *MainBar::SettingSaveDirectory = "MainWindow/SaveDirectory";
 
-MainBar::MainBar(Session &session, MainWindow &main_window,
-       string open_file_name, string open_file_format) :
+MainBar::MainBar(Session &session, MainWindow &main_window) :
        QToolBar("Sampling Bar", &main_window),
        action_open_(new QAction(this)),
        action_save_as_(new QAction(this)),
@@ -310,11 +309,7 @@ MainBar::MainBar(Session &session, MainWindow &main_window,
        connect(&session_, SIGNAL(device_selected()), this,
                SLOT(device_selected()));
 
-       // Figure out which file/device to use
-       if (open_file_name.empty())
-               select_init_device();
-       else
-               load_init_file(open_file_name, open_file_format);
+       update_device_list();
 }
 
 Session &MainBar::session(void) const
@@ -360,6 +355,47 @@ void MainBar::reset_device_selector()
        device_selector_.reset();
 }
 
+void MainBar::select_device(shared_ptr<devices::Device> device)
+{
+       try {
+               if (device)
+                       session_.set_device(device);
+               else
+                       session_.set_default_device();
+       } catch (const QString &e) {
+               QMessageBox msg(this);
+               msg.setText(e);
+               msg.setInformativeText(tr("Failed to Select Device"));
+               msg.setStandardButtons(QMessageBox::Ok);
+               msg.setIcon(QMessageBox::Warning);
+               msg.exec();
+       }
+}
+
+void MainBar::load_init_file(const std::string &file_name,
+       const std::string &format)
+{
+       shared_ptr<InputFormat> input_format;
+
+       DeviceManager& device_manager = session_.device_manager();
+
+       if (!format.empty()) {
+               const map<string, shared_ptr<InputFormat> > formats =
+                       device_manager.context()->input_formats();
+               const auto iter = find_if(formats.begin(), formats.end(),
+                       [&](const pair<string, shared_ptr<InputFormat> > f) {
+                               return f.first == format; });
+               if (iter == formats.end()) {
+                       cerr << "Unexpected input format: " << format << endl;
+                       return;
+               }
+
+               input_format = (*iter).second;
+       }
+
+       load_file(QString::fromStdString(file_name), input_format);
+}
+
 QAction* MainBar::action_open() const
 {
        return action_open_;
@@ -419,74 +455,6 @@ void MainBar::run_stop()
        }
 }
 
-void MainBar::select_device(shared_ptr<devices::Device> device)
-{
-       try {
-               if (device)
-                       session_.set_device(device);
-               else
-                       session_.set_default_device();
-       } catch (const QString &e) {
-               QMessageBox msg(this);
-               msg.setText(e);
-               msg.setInformativeText(tr("Failed to Select Device"));
-               msg.setStandardButtons(QMessageBox::Ok);
-               msg.setIcon(QMessageBox::Warning);
-               msg.exec();
-       }
-}
-
-void MainBar::select_init_device()
-{
-       QSettings settings;
-       map<string, string> dev_info;
-       list<string> key_list;
-       shared_ptr<devices::HardwareDevice> device;
-
-       DeviceManager& device_manager = session_.device_manager();
-
-       // Re-select last used device if possible but only if it's not demo
-       settings.beginGroup("Device");
-       key_list.push_back("vendor");
-       key_list.push_back("model");
-       key_list.push_back("version");
-       key_list.push_back("serial_num");
-       key_list.push_back("connection_id");
-
-       for (string key : key_list) {
-               const QString k = QString::fromStdString(key);
-               if (!settings.contains(k))
-                       continue;
-
-               const string value = settings.value(k).toString().toStdString();
-               if (!value.empty())
-                       dev_info.insert(std::make_pair(key, value));
-       }
-
-       if (dev_info.count("model") > 0)
-               if (dev_info.at("model").find("Demo device") == std::string::npos)
-                       device = device_manager.find_device_from_info(dev_info);
-
-       // When we can't find a device similar to the one we used last
-       // time and there is at least one device aside from demo, use it
-       if (!device) {
-               for (shared_ptr<devices::HardwareDevice> dev : device_manager.devices()) {
-                       dev_info = device_manager.get_device_info(dev);
-
-                       if (dev_info.count("model") > 0)
-                               if (dev_info.at("model").find("Demo device") == std::string::npos) {
-                                       device = dev;
-                                       break;
-                               }
-               }
-       }
-
-       select_device(device);
-       update_device_list();
-
-       settings.endGroup();
-}
-
 void MainBar::load_file(QString file_name,
        std::shared_ptr<sigrok::InputFormat> format,
        const std::map<std::string, Glib::VariantBase> &options)
@@ -515,36 +483,14 @@ void MainBar::load_file(QString file_name,
                return;
        }
 
+       session_.set_name(QFileInfo(file_name).fileName());
+
        update_device_list();
 
        session_.start_capture([&, errorMessage](QString infoMessage) {
                session_error(errorMessage, infoMessage); });
 }
 
-void MainBar::load_init_file(const std::string &file_name,
-       const std::string &format)
-{
-       shared_ptr<InputFormat> input_format;
-
-       DeviceManager& device_manager = session_.device_manager();
-
-       if (!format.empty()) {
-               const map<string, shared_ptr<InputFormat> > formats =
-                       device_manager.context()->input_formats();
-               const auto iter = find_if(formats.begin(), formats.end(),
-                       [&](const pair<string, shared_ptr<InputFormat> > f) {
-                               return f.first == format; });
-               if (iter == formats.end()) {
-                       cerr << "Unexpected input format: " << format << endl;
-                       return;
-               }
-
-               input_format = (*iter).second;
-       }
-
-       load_file(QString::fromStdString(file_name), input_format);
-}
-
 void MainBar::update_sample_rate_selector()
 {
        Glib::VariantContainerBase gvar_dict;
@@ -906,6 +852,8 @@ void MainBar::export_file(shared_ptr<OutputFormat> format,
                options = dlg.options();
        }
 
+       session_.set_name(QFileInfo(file_name).fileName());
+
        StoreProgress *dlg = new StoreProgress(file_name, format, options,
                sample_range, session_, this);
        dlg->run();
index 088efa2f73cb6a8597cd6b4ea517bbbe40409a39..c05a146e28f77518744cf50cb37a0232bf8b2b52 100644 (file)
@@ -78,9 +78,7 @@ private:
        static const char *SettingSaveDirectory;
 
 public:
-       MainBar(Session &session, pv::MainWindow &main_window,
-               std::string open_file_name = std::string(),
-               std::string open_file_format = std::string());
+       MainBar(Session &session, pv::MainWindow &main_window);
 
        Session &session(void) const;
 
@@ -90,6 +88,11 @@ public:
 
        void reset_device_selector();
 
+       void select_device(std::shared_ptr<devices::Device> device);
+
+       void load_init_file(const std::string &file_name,
+               const std::string &format);
+
        QAction* action_open() const;
        QAction* action_save_as() const;
        QAction* action_save_selection_as() const;
@@ -104,8 +107,6 @@ public:
 private:
        void run_stop();
 
-       void select_device(std::shared_ptr<devices::Device> device);
-
        void select_init_device();
 
        void load_file(QString file_name,
@@ -113,9 +114,6 @@ private:
                const std::map<std::string, Glib::VariantBase> &options =
                        std::map<std::string, Glib::VariantBase>());
 
-       void load_init_file(const std::string &file_name,
-               const std::string &format);
-
        void save_selection_to_file();
 
        void update_sample_rate_selector();