+ if (!v)
+ return nullptr;
+
+ sub_windows_[dock] = v;
+ dock_main->setCentralWidget(v.get());
+ dock->setWidget(dock_main);
+
+ dock->setContextMenuPolicy(Qt::PreventContextMenu);
+ dock->setFeatures(QDockWidget::DockWidgetMovable |
+ QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
+
+ QAbstractButton *close_btn =
+ dock->findChildren<QAbstractButton*>
+ ("qt_dockwidget_closebutton").front();
+
+ 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));
+
+ return v;
+}
+
+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 (const 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*>()) // clazy:exclude=range-loop
+ 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 (const 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);
+}