From: Soeren Apel Date: Sat, 27 Aug 2016 19:55:57 +0000 (+0200) Subject: Implement multi-session handling X-Git-Tag: pulseview-0.4.0~264 X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=commitdiff_plain;h=101e7a9b40cc97fcd94aca7a1bed086b1f56f269 Implement multi-session handling 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. --- diff --git a/pv/mainwindow.cpp b/pv/mainwindow.cpp index f8463257..6e408583 100644 --- a/pv/mainwindow.cpp +++ b/pv/mainwindow.cpp @@ -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 #include +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 = 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 = add_session(); + + map dev_info; + shared_ptr other_device, demo_device; + + // Use any available device that's not demo + for (shared_ptr 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 view = entry.second; - session_.deregister_view(view); + + for (shared_ptr session : sessions_) + if (session->has_view(view)) + session->deregister_view(view); } } @@ -173,13 +201,9 @@ shared_ptr MainWindow::add_view(const QString &title, shared_ptr main_bar = session.main_bar(); if (!main_bar) { - main_bar = make_shared(session_, *this, - open_file_name_, open_file_format_); + main_bar = make_shared(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 MainWindow::add_view(const QString &title, return v; } +shared_ptr MainWindow::add_session() +{ + int id = sessions_.size(); + QString name = tr("Untitled-%1").arg(id + 1); + + shared_ptr session = make_shared(device_manager_, name); + + sessions_.push_back(session); + + shared_ptr 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 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 dev_info; - list 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 : sessions_) { + // Ignore sessions using the demo device + if (session->device()) { + shared_ptr 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 = add_session(); + session->restore_settings(settings); + settings.endGroup(); + } } void MainWindow::closeEvent(QCloseEvent *event) diff --git a/pv/mainwindow.hpp b/pv/mainwindow.hpp index 485b7b6d..2e4c6bbd 100644 --- a/pv/mainwindow.hpp +++ b/pv/mainwindow.hpp @@ -74,6 +74,8 @@ public: std::shared_ptr add_view(const QString &title, view::ViewType type, Session &session); + std::shared_ptr add_session(); + private: void setup_ui(); @@ -98,13 +100,11 @@ private Q_SLOTS: private: DeviceManager &device_manager_; - Session session_; + std::vector< std::shared_ptr > sessions_; std::map< std::shared_ptr, std::shared_ptr > 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_; diff --git a/pv/session.cpp b/pv/session.cpp index fd428ed0..99de7749 100644 --- a/pv/session.cpp +++ b/pv/session.cpp @@ -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 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 Session::main_view() const { return main_view_; @@ -148,6 +164,71 @@ shared_ptr Session::main_bar() const return main_bar_; } +void Session::save_settings(QSettings &settings) const +{ + map dev_info; + list 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 dev_info; + list key_list; + shared_ptr 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 device) { assert(device); @@ -160,6 +241,10 @@ void Session::set_device(shared_ptr 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 view : views_) { view->clear_signals(); @@ -248,6 +333,10 @@ void Session::start_capture(function error_handler) for (const shared_ptr 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 view) } } +bool Session::has_view(std::shared_ptr view) +{ + return views_.find(view) != views_.end(); +} + double Session::get_samplerate() const { double samplerate = 0.0; diff --git a/pv/session.hpp b/pv/session.hpp index d6cfdd30..258addb9 100644 --- a/pv/session.hpp +++ b/pv/session.hpp @@ -38,6 +38,7 @@ #include #include +#include #include #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 device() const; + QString name() const; + + void set_name(QString name); + std::shared_ptr main_view() const; void set_main_bar(std::shared_ptr main_bar); std::shared_ptr 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 view); + bool has_view(std::shared_ptr view); + const std::unordered_set< std::shared_ptr > signalbases() const; @@ -167,6 +178,7 @@ private: private: DeviceManager &device_manager_; std::shared_ptr device_; + QString default_name_, name_; std::unordered_set< std::shared_ptr > views_; std::shared_ptr 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 > signalbases_; std::unordered_set< std::shared_ptr > all_signal_data_; @@ -197,6 +208,8 @@ Q_SIGNALS: void signals_changed(); + void name_changed(); + void trigger_event(util::Timestamp location); void frame_began(); diff --git a/pv/toolbars/mainbar.cpp b/pv/toolbars/mainbar.cpp index a76ffbaa..6a5992bf 100644 --- a/pv/toolbars/mainbar.cpp +++ b/pv/toolbars/mainbar.cpp @@ -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 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 input_format; + + DeviceManager& device_manager = session_.device_manager(); + + if (!format.empty()) { + const map > formats = + device_manager.context()->input_formats(); + const auto iter = find_if(formats.begin(), formats.end(), + [&](const pair > 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 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 dev_info; - list key_list; - shared_ptr 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 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 format, const std::map &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 input_format; - - DeviceManager& device_manager = session_.device_manager(); - - if (!format.empty()) { - const map > formats = - device_manager.context()->input_formats(); - const auto iter = find_if(formats.begin(), formats.end(), - [&](const pair > 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 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(); diff --git a/pv/toolbars/mainbar.hpp b/pv/toolbars/mainbar.hpp index 088efa2f..c05a146e 100644 --- a/pv/toolbars/mainbar.hpp +++ b/pv/toolbars/mainbar.hpp @@ -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 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 device); - void select_init_device(); void load_file(QString file_name, @@ -113,9 +114,6 @@ private: const std::map &options = std::map()); - void load_init_file(const std::string &file_name, - const std::string &format); - void save_selection_to_file(); void update_sample_rate_selector();