+ tv->enable_coloured_bg(settings.value(GlobalSettings::Key_View_ColouredBG).toBool());
+ tv->enable_show_sampling_points(settings.value(GlobalSettings::Key_View_ShowSamplingPoints).toBool());
+ tv->enable_show_analog_minor_grid(settings.value(GlobalSettings::Key_View_ShowAnalogMinorGrid).toBool());
+
+ if (!main_bar) {
+ /* Initial view, create the main bar */
+ main_bar = make_shared<MainBar>(session, this, tv);
+ dock_main->addToolBar(main_bar.get());
+ session.set_main_bar(main_bar);
+
+ connect(main_bar.get(), SIGNAL(new_view(Session*)),
+ this, SLOT(on_new_view(Session*)));
+
+ main_bar->action_view_show_cursors()->setChecked(tv->cursors_shown());
+
+ /* For the main view we need to prevent the dock widget from
+ * closing itself when its close button is clicked. This is
+ * so we can confirm with the user first. Regular views don't
+ * need this */
+ close_btn->disconnect(SIGNAL(clicked()), dock, SLOT(close()));
+ } else {
+ /* Additional view, create a standard bar */
+ pv::views::trace::StandardBar *standard_bar =
+ new pv::views::trace::StandardBar(session, this, tv);
+ dock_main->addToolBar(standard_bar);
+
+ standard_bar->action_view_show_cursors()->setChecked(tv->cursors_shown());
+ }
+ }
+
+ return v;
+}
+
+void MainWindow::remove_view(shared_ptr<views::ViewBase> view)
+{
+ for (shared_ptr<Session> session : sessions_) {
+ if (!session->has_view(view))
+ continue;
+
+ // Find the dock the view is contained in and remove it
+ for (auto entry : view_docks_)
+ if (entry.second == view) {
+ // Remove the view from the session
+ session->deregister_view(view);
+
+ // Remove the view from its parent; otherwise, Qt will
+ // call deleteLater() on it, which causes a double free
+ // since the shared_ptr in view_docks_ doesn't know
+ // that Qt keeps a pointer to the view around
+ view->setParent(nullptr);
+
+ // Delete the view's dock widget and all widgets inside it
+ entry.first->deleteLater();
+
+ // Remove the dock widget from the list and stop iterating
+ view_docks_.erase(entry.first);
+ break;
+ }
+ }
+}
+
+shared_ptr<Session> MainWindow::add_session()
+{
+ static int last_session_id = 1;
+ QString name = tr("Session %1").arg(last_session_id++);
+
+ shared_ptr<Session> session = make_shared<Session>(device_manager_, name);
+
+ connect(session.get(), SIGNAL(add_view(const QString&, views::ViewType, Session*)),
+ this, SLOT(on_add_view(const QString&, views::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(capture_state_changed(int)),
+ &session_state_mapper_, SLOT(map()));
+
+ sessions_.push_back(session);
+
+ QMainWindow *window = new QMainWindow();
+ window->setWindowFlags(Qt::Widget); // Remove Qt::Window flag
+ session_windows_[session] = window;
+
+ int index = session_selector_.addTab(window, name);
+ session_selector_.setCurrentIndex(index);
+ last_focused_session_ = session;
+
+ window->setDockNestingEnabled(true);
+
+ shared_ptr<views::ViewBase> main_view =
+ add_view(name, views::ViewTypeTrace, *session);
+
+ return session;
+}
+
+void MainWindow::remove_session(shared_ptr<Session> session)
+{
+ // Determine the height of the button before it collapses
+ int h = new_session_button_->height();
+
+ // Stop capture while the session still exists so that the UI can be
+ // updated in case we're currently running. If so, this will schedule a
+ // call to our on_capture_state_changed() slot for the next run of the
+ // event loop. We need to have this executed immediately or else it will
+ // be dismissed since the session object will be deleted by the time we
+ // leave this method and the event loop gets a chance to run again.
+ session->stop_capture();
+ QApplication::processEvents();
+
+ for (shared_ptr<views::ViewBase> view : session->views())
+ remove_view(view);
+
+ QMainWindow *window = session_windows_.at(session);
+ session_selector_.removeTab(session_selector_.indexOf(window));
+
+ session_windows_.erase(session);
+
+ if (last_focused_session_ == session)
+ last_focused_session_.reset();
+
+ // Remove the session from our list of sessions (which also destroys it)
+ sessions_.remove_if([&](shared_ptr<Session> s) {
+ return s == session; });
+
+ if (sessions_.empty()) {
+ // When there are no more tabs, the height of the QTabWidget
+ // drops to zero. We must prevent this to keep the static
+ // widgets visible
+ for (QWidget *w : static_tab_widget_->findChildren<QWidget*>())
+ w->setMinimumHeight(h);
+
+ int margin = static_tab_widget_->layout()->contentsMargins().bottom();
+ static_tab_widget_->setMinimumHeight(h + 2 * margin);
+ session_selector_.setMinimumHeight(h + 2 * margin);
+
+ // Update the window title if there is no view left to
+ // generate focus change events
+ setWindowTitle(WindowTitle);
+ }
+}
+
+void MainWindow::add_session_with_file(string open_file_name,
+ string open_file_format)
+{
+ shared_ptr<Session> session = add_session();
+ session->load_init_file(open_file_name, open_file_format);
+}
+
+void MainWindow::add_default_session()
+{
+ // Only add the default session if there would be no session otherwise
+ if (sessions_.size() > 0)
+ return;
+
+ shared_ptr<Session> session = add_session();
+
+ // Check the list of available devices. Prefer the one that was
+ // found with user supplied scan specs (if applicable). Then try
+ // one of the auto detected devices that are not the demo device.
+ // Pick demo in the absence of "genuine" hardware devices.
+ shared_ptr<devices::HardwareDevice> user_device, other_device, demo_device;
+ for (shared_ptr<devices::HardwareDevice> dev : device_manager_.devices()) {
+ if (dev == device_manager_.user_spec_device()) {
+ user_device = dev;
+ } else if (dev->hardware_device()->driver()->name() == "demo") {
+ demo_device = dev;
+ } else {
+ other_device = dev;
+ }
+ }
+ if (user_device)
+ session->select_device(user_device);
+ else if (other_device)
+ session->select_device(other_device);
+ else
+ session->select_device(demo_device);
+}
+
+void MainWindow::save_sessions()
+{
+ QSettings settings;
+ int id = 0;
+
+ for (shared_ptr<Session> session : sessions_) {
+ // Ignore sessions using the demo device or no device at all
+ if (session->device()) {
+ shared_ptr<devices::HardwareDevice> device =
+ dynamic_pointer_cast< devices::HardwareDevice >
+ (session->device());
+
+ if (device &&
+ device->hardware_device()->driver()->name() == "demo")
+ continue;
+
+ settings.beginGroup("Session" + QString::number(id++));
+ settings.remove(""); // Remove all keys in this group
+ session->save_settings(settings);
+ settings.endGroup();
+ }
+ }
+
+ settings.setValue("sessions", id);
+}
+
+void MainWindow::restore_sessions()
+{
+ QSettings settings;
+ int i, session_count;
+
+ 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::on_setting_changed(const QString &key, const QVariant &value)
+{
+ if (key == GlobalSettings::Key_View_ColouredBG)
+ on_settingViewColouredBg_changed(value);