]> sigrok.org Git - pulseview.git/blobdiff - pv/mainwindow.cpp
Session: Fix issue #67 by improving error handling
[pulseview.git] / pv / mainwindow.cpp
index 2823adc0ec08e1f9f3f341ef7e52415c506471b0..8646175e2b32f7a6b7f0a7ec7233f07d136d77fb 100644 (file)
@@ -40,6 +40,7 @@
 
 #include "mainwindow.hpp"
 
+#include "application.hpp"
 #include "devicemanager.hpp"
 #include "devices/hardwaredevice.hpp"
 #include "dialogs/settings.hpp"
@@ -51,7 +52,8 @@
 
 #ifdef ENABLE_DECODE
 #include "subwindows/decoder_selector/subwindow.hpp"
-#include "views/decoder_output/view.hpp"
+#include "views/decoder_binary/view.hpp"
+#include "views/tabular_decoder/view.hpp"
 #endif
 
 #include <libsigrokcxx/libsigrokcxx.hpp>
@@ -71,13 +73,14 @@ MainWindow::MainWindow(DeviceManager &device_manager, QWidget *parent) :
        QMainWindow(parent),
        device_manager_(device_manager),
        session_selector_(this),
-       session_state_mapper_(this),
        icon_red_(":/icons/status-red.svg"),
        icon_green_(":/icons/status-green.svg"),
        icon_grey_(":/icons/status-grey.svg")
 {
        setup_ui();
        restore_ui_settings();
+       connect(this, SIGNAL(session_error_raised(const QString, const QString)),
+               this, SLOT(on_session_error_raised(const QString, const QString)));
 }
 
 MainWindow::~MainWindow()
@@ -94,7 +97,7 @@ MainWindow::~MainWindow()
 void MainWindow::show_session_error(const QString text, const QString info_text)
 {
        // TODO Emulate noquote()
-       qDebug() << "Notifying user of session error:" << info_text;
+       qDebug() << "Notifying user of session error: " << text << "; " << info_text;
 
        QMessageBox msg;
        msg.setText(text + "\n\n" + info_text);
@@ -146,7 +149,7 @@ shared_ptr<views::ViewBase> MainWindow::add_view(views::ViewType type,
        // Only use the view type in the name if it's not the main view
        QString title;
        if (main_bar)
-               title = QString("%1 (%2)").arg(session.name()).arg(views::ViewTypeNames[type]);
+               title = QString("%1 (%2)").arg(session.name()views::ViewTypeNames[type]);
        else
                title = session.name();
 
@@ -162,8 +165,10 @@ shared_ptr<views::ViewBase> MainWindow::add_view(views::ViewType type,
                // This view will be the main view if there's no main bar yet
                v = make_shared<views::trace::View>(session, (main_bar ? false : true), dock_main);
 #ifdef ENABLE_DECODE
-       if (type == views::ViewTypeDecoderOutput)
-               v = make_shared<views::decoder_output::View>(session, false, dock_main);
+       if (type == views::ViewTypeDecoderBinary)
+               v = make_shared<views::decoder_binary::View>(session, false, dock_main);
+       if (type == views::ViewTypeTabularDecoder)
+               v = make_shared<views::tabular_decoder::View>(session, false, dock_main);
 #endif
 
        if (!v)
@@ -190,6 +195,9 @@ shared_ptr<views::ViewBase> MainWindow::add_view(views::ViewType type,
                qobject_cast<views::ViewBase*>(v.get()),
                SLOT(trigger_event(int, util::Timestamp)));
 
+       connect(&session, SIGNAL(session_error_raised(const QString, const QString)),
+               this, SLOT(on_session_error_raised(const QString, const QString)));
+
        if (type == views::ViewTypeTrace) {
                views::trace::View *tv =
                        qobject_cast<views::trace::View*>(v.get());
@@ -222,6 +230,8 @@ shared_ptr<views::ViewBase> MainWindow::add_view(views::ViewType type,
                }
        }
 
+       v->setFocus();
+
        return v;
 }
 
@@ -257,7 +267,7 @@ shared_ptr<subwindows::SubWindowBase> MainWindow::add_subwindow(
        subwindows::SubWindowType type, Session &session)
 {
        GlobalSettings settings;
-       shared_ptr<subwindows::SubWindowBase> v;
+       shared_ptr<subwindows::SubWindowBase> w;
 
        QMainWindow *main_window = nullptr;
        for (auto& entry : session_windows_)
@@ -288,14 +298,14 @@ shared_ptr<subwindows::SubWindowBase> MainWindow::add_subwindow(
 
 #ifdef ENABLE_DECODE
        if (type == subwindows::SubWindowTypeDecoderSelector)
-               v = make_shared<subwindows::decoder_selector::SubWindow>(session, dock_main);
+               w = make_shared<subwindows::decoder_selector::SubWindow>(session, dock_main);
 #endif
 
-       if (!v)
+       if (!w)
                return nullptr;
 
-       sub_windows_[dock] = v;
-       dock_main->setCentralWidget(v.get());
+       sub_windows_[dock] = w;
+       dock_main->setCentralWidget(w.get());
        dock->setWidget(dock_main);
 
        dock->setContextMenuPolicy(Qt::PreventContextMenu);
@@ -312,13 +322,13 @@ shared_ptr<subwindows::SubWindowBase> MainWindow::add_subwindow(
        connect(close_btn, SIGNAL(clicked(bool)),
                this, SLOT(on_sub_window_close_clicked()));
 
-       if (v->has_toolbar())
-               dock_main->addToolBar(v->create_toolbar(dock_main));
+       if (w->has_toolbar())
+               dock_main->addToolBar(w->create_toolbar(dock_main));
 
-       if (v->minimum_width() > 0)
-               dock->setMinimumSize(v->minimum_width(), 0);
+       if (w->minimum_width() > 0)
+               dock->setMinimumSize(w->minimum_width(), 0);
 
-       return v;
+       return w;
 }
 
 shared_ptr<Session> MainWindow::add_session()
@@ -328,13 +338,14 @@ shared_ptr<Session> MainWindow::add_session()
 
        shared_ptr<Session> session = make_shared<Session>(device_manager_, name);
 
-       connect(session.get(), SIGNAL(add_view(views::ViewType, Session*)),
-               this, SLOT(on_add_view(views::ViewType, Session*)));
+       connect(session.get(), SIGNAL(add_view(ViewType, Session*)),
+               this, SLOT(on_add_view(ViewType, Session*)));
        connect(session.get(), SIGNAL(name_changed()),
                this, SLOT(on_session_name_changed()));
-       session_state_mapper_.setMapping(session.get(), session.get());
+       connect(session.get(), SIGNAL(device_changed()),
+               this, SLOT(on_session_device_changed()));
        connect(session.get(), SIGNAL(capture_state_changed(int)),
-               &session_state_mapper_, SLOT(map()));
+               this, SLOT(on_session_capture_state_changed(int)));
 
        sessions_.push_back(session);
 
@@ -348,7 +359,7 @@ shared_ptr<Session> MainWindow::add_session()
 
        window->setDockNestingEnabled(true);
 
-       shared_ptr<views::ViewBase> main_view = add_view(views::ViewTypeTrace, *session);
+       add_view(views::ViewTypeTrace, *session);
 
        return session;
 }
@@ -541,17 +552,19 @@ void MainWindow::setup_ui()
        session_selector_.setCornerWidget(static_tab_widget_, Qt::TopLeftCorner);
        session_selector_.setTabsClosable(true);
 
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+       close_application_shortcut_ = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this, SLOT(close()));
+       close_current_tab_shortcut_ = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this, SLOT(on_close_current_tab()));
+#else
        close_application_shortcut_ = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
-       close_application_shortcut_->setAutoRepeat(false);
-
        close_current_tab_shortcut_ = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this, SLOT(on_close_current_tab()));
+#endif
+       close_application_shortcut_->setAutoRepeat(false);
 
        connect(new_session_button_, SIGNAL(clicked(bool)),
                this, SLOT(on_new_session_clicked()));
        connect(run_stop_button_, SIGNAL(clicked(bool)),
                this, SLOT(on_run_stop_clicked()));
-       connect(&session_state_mapper_, SIGNAL(mapped(QObject*)),
-               this, SLOT(on_capture_state_changed(QObject*)));
        connect(settings_button_, SIGNAL(clicked(bool)),
                this, SLOT(on_settings_clicked()));
 
@@ -566,6 +579,25 @@ void MainWindow::setup_ui()
                this, SLOT(on_focus_changed()));
 }
 
+void MainWindow::update_acq_button(Session *session)
+{
+       int state;
+       QString run_caption;
+
+       if (session) {
+               state = session->get_capture_state();
+               run_caption = session->using_file_device() ? tr("Reload") : tr("Run");
+       } else {
+               state = Session::Stopped;
+               run_caption = tr("Run");
+       }
+
+       const QIcon *icons[] = {&icon_grey_, &icon_red_, &icon_green_};
+       run_stop_button_->setIcon(*icons[state]);
+       run_stop_button_->setText((state == pv::Session::Stopped) ?
+               run_caption : tr("Stop"));
+}
+
 void MainWindow::save_ui_settings()
 {
        QSettings settings;
@@ -636,6 +668,54 @@ bool MainWindow::restoreState(const QByteArray &state, int version)
        return false;
 }
 
+void MainWindow::on_run_stop_clicked()
+{
+       GlobalSettings settings;
+       bool all_sessions = settings.value(GlobalSettings::Key_General_StartAllSessions).toBool();
+
+       if (all_sessions)
+       {
+               vector< shared_ptr<Session> > hw_sessions;
+
+               // Make a list of all sessions where a hardware device is used
+               for (const shared_ptr<Session>& s : sessions_) {
+                       shared_ptr<devices::HardwareDevice> hw_device =
+                                       dynamic_pointer_cast< devices::HardwareDevice >(s->device());
+                       if (!hw_device)
+                               continue;
+                       hw_sessions.push_back(s);
+               }
+
+               // Stop all acquisitions if there are any running ones, start all otherwise
+               bool any_running = any_of(hw_sessions.begin(), hw_sessions.end(),
+                               [](const shared_ptr<Session> &s)
+                               { return (s->get_capture_state() == Session::AwaitingTrigger) ||
+                                               (s->get_capture_state() == Session::Running); });
+
+               for (shared_ptr<Session> s : hw_sessions)
+                       if (any_running)
+                               s->stop_capture();
+                       else
+                               s->start_capture([&](QString message) {Q_EMIT session_error_raised("Capture failed", message);});
+       } else {
+
+               shared_ptr<Session> session = last_focused_session_;
+
+               if (!session)
+                       return;
+
+               switch (session->get_capture_state()) {
+               case Session::Stopped:
+                       session->start_capture([&](QString message) {Q_EMIT session_error_raised("Capture failed", message);});
+                       break;
+               case Session::AwaitingTrigger:
+               case Session::Running:
+                       session->stop_capture();
+                       break;
+               }
+       }
+}
+
 void MainWindow::on_add_view(views::ViewType type, Session *session)
 {
        // We get a pointer and need a reference
@@ -678,7 +758,7 @@ void MainWindow::on_focused_session_changed(shared_ptr<Session> session)
        setWindowTitle(session->name() + " - " + WindowTitle);
 
        // Update the state of the run/stop button, too
-       on_capture_state_changed(session.get());
+       update_acq_button(session.get());
 }
 
 void MainWindow::on_new_session_clicked()
@@ -686,25 +766,6 @@ void MainWindow::on_new_session_clicked()
        add_session();
 }
 
-void MainWindow::on_run_stop_clicked()
-{
-       shared_ptr<Session> session = last_focused_session_;
-
-       if (!session)
-               return;
-
-       switch (session->get_capture_state()) {
-       case Session::Stopped:
-               session->start_capture([&](QString message) {
-                       show_session_error("Capture failed", message); });
-               break;
-       case Session::AwaitingTrigger:
-       case Session::Running:
-               session->stop_capture();
-               break;
-       }
-}
-
 void MainWindow::on_settings_clicked()
 {
        dialogs::Settings dlg(device_manager_);
@@ -739,21 +800,32 @@ void MainWindow::on_session_name_changed()
                setWindowTitle(session->name() + " - " + WindowTitle);
 }
 
-void MainWindow::on_capture_state_changed(QObject *obj)
+void MainWindow::on_session_device_changed()
 {
-       Session *caller = qobject_cast<Session*>(obj);
+       Session *session = qobject_cast<Session*>(QObject::sender());
+       assert(session);
 
        // Ignore if caller is not the currently focused session
        // unless there is only one session
-       if ((sessions_.size() > 1) && (caller != last_focused_session_.get()))
+       if ((sessions_.size() > 1) && (session != last_focused_session_.get()))
                return;
 
-       int state = caller->get_capture_state();
+       update_acq_button(session);
+}
 
-       const QIcon *icons[] = {&icon_grey_, &icon_red_, &icon_green_};
-       run_stop_button_->setIcon(*icons[state]);
-       run_stop_button_->setText((state == pv::Session::Stopped) ?
-               tr("Run") : tr("Stop"));
+void MainWindow::on_session_capture_state_changed(int state)
+{
+       (void)state;
+
+       Session *session = qobject_cast<Session*>(QObject::sender());
+       assert(session);
+
+       // Ignore if caller is not the currently focused session
+       // unless there is only one session
+       if ((sessions_.size() > 1) && (session != last_focused_session_.get()))
+               return;
+
+       update_acq_button(session);
 }
 
 void MainWindow::on_new_view(Session *session, int view_type)
@@ -822,6 +894,9 @@ void MainWindow::on_tab_close_requested(int index)
                tr("This session contains unsaved data. Close it anyway?"),
                QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes))
                remove_session(session);
+
+       if (sessions_.empty())
+               update_acq_button(nullptr);
 }
 
 void MainWindow::on_show_decoder_selector(Session *session)
@@ -844,6 +919,8 @@ void MainWindow::on_show_decoder_selector(Session *session)
        for (shared_ptr<Session>& s : sessions_)
                if (s.get() == session)
                        add_subwindow(subwindows::SubWindowTypeDecoderSelector, *s);
+#else
+       (void)session;
 #endif
 }
 
@@ -862,6 +939,10 @@ void MainWindow::on_sub_window_close_clicked()
 
        sub_windows_.erase(dock);
        dock->close();
+
+       // Restore focus to the last used main view
+       if (last_focused_session_)
+               last_focused_session_->main_view()->setFocus();
 }
 
 void MainWindow::on_view_colored_bg_shortcut()
@@ -903,4 +984,8 @@ void MainWindow::on_close_current_tab()
        on_tab_close_requested(tab);
 }
 
+void MainWindow::on_session_error_raised(const QString text, const QString info_text) {
+       MainWindow::show_session_error(text, info_text);
+}
+
 } // namespace pv