- // Setup the central widget
- _central_widget = new QWidget(this);
- _vertical_layout = new QVBoxLayout(_central_widget);
- _vertical_layout->setSpacing(6);
- _vertical_layout->setContentsMargins(0, 0, 0, 0);
- setCentralWidget(_central_widget);
-
- _view = new pv::view::View(_session, this);
-
- _vertical_layout->addWidget(_view);
-
- // Setup the menu bar
- QMenuBar *const menu_bar = new QMenuBar(this);
- menu_bar->setGeometry(QRect(0, 0, 400, 25));
-
- // File Menu
- QMenu *const menu_file = new QMenu;
- menu_file->setTitle(tr("&File"));
-
- QAction *const action_open = new QAction(this);
- action_open->setText(tr("&Open..."));
- action_open->setIcon(QIcon::fromTheme("document-open",
- QIcon(":/icons/document-open.png")));
- action_open->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
- action_open->setObjectName(QString::fromUtf8("actionOpen"));
- menu_file->addAction(action_open);
-
- QAction *const action_save_as = new QAction(this);
- action_save_as->setText(tr("&Save As..."));
- action_save_as->setIcon(QIcon::fromTheme("document-save-as",
- QIcon(":/icons/document-save-as.png")));
- action_save_as->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
- action_save_as->setObjectName(QString::fromUtf8("actionSaveAs"));
- menu_file->addAction(action_save_as);
-
- menu_file->addSeparator();
-
- QAction *const action_connect = new QAction(this);
- action_connect->setText(tr("&Connect to Device..."));
- action_connect->setObjectName(QString::fromUtf8("actionConnect"));
- menu_file->addAction(action_connect);
-
- menu_file->addSeparator();
-
- QAction *action_quit = new QAction(this);
- action_quit->setText(tr("&Quit"));
- action_quit->setIcon(QIcon::fromTheme("application-exit",
- QIcon(":/icons/application-exit.png")));
- action_quit->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
- action_quit->setObjectName(QString::fromUtf8("actionQuit"));
- menu_file->addAction(action_quit);
-
- // View Menu
- QMenu *menu_view = new QMenu;
- menu_view->setTitle(tr("&View"));
-
- QAction *const action_view_zoom_in = new QAction(this);
- action_view_zoom_in->setText(tr("Zoom &In"));
- action_view_zoom_in->setIcon(QIcon::fromTheme("zoom-in",
- QIcon(":/icons/zoom-in.png")));
- // simply using Qt::Key_Plus shows no + in the menu
- action_view_zoom_in->setShortcut(QKeySequence::ZoomIn);
- action_view_zoom_in->setObjectName(
- QString::fromUtf8("actionViewZoomIn"));
- menu_view->addAction(action_view_zoom_in);
-
- QAction *const action_view_zoom_out = new QAction(this);
- action_view_zoom_out->setText(tr("Zoom &Out"));
- action_view_zoom_out->setIcon(QIcon::fromTheme("zoom-out",
- QIcon(":/icons/zoom-out.png")));
- action_view_zoom_out->setShortcut(QKeySequence::ZoomOut);
- action_view_zoom_out->setObjectName(
- QString::fromUtf8("actionViewZoomOut"));
- menu_view->addAction(action_view_zoom_out);
-
- QAction *const action_view_zoom_fit = new QAction(this);
- action_view_zoom_fit->setText(tr("Zoom to &Fit"));
- action_view_zoom_fit->setIcon(QIcon::fromTheme("zoom-fit",
- QIcon(":/icons/zoom-fit.png")));
- action_view_zoom_fit->setShortcut(QKeySequence(Qt::Key_F));
- action_view_zoom_fit->setObjectName(
- QString::fromUtf8("actionViewZoomFit"));
- menu_view->addAction(action_view_zoom_fit);
-
- QAction *const action_view_zoom_one_to_one = new QAction(this);
- action_view_zoom_one_to_one->setText(tr("Zoom to &One-to-One"));
- action_view_zoom_one_to_one->setIcon(QIcon::fromTheme("zoom-original",
- QIcon(":/icons/zoom-original.png")));
- action_view_zoom_one_to_one->setShortcut(QKeySequence(Qt::Key_O));
- action_view_zoom_one_to_one->setObjectName(
- QString::fromUtf8("actionViewZoomOneToOne"));
- menu_view->addAction(action_view_zoom_one_to_one);
-
- menu_view->addSeparator();
-
- QAction *action_view_show_cursors = new QAction(this);
- action_view_show_cursors->setCheckable(true);
- action_view_show_cursors->setChecked(_view->cursors_shown());
- action_view_show_cursors->setShortcut(QKeySequence(Qt::Key_C));
- action_view_show_cursors->setObjectName(
- QString::fromUtf8("actionViewShowCursors"));
- action_view_show_cursors->setText(tr("Show &Cursors"));
- menu_view->addAction(action_view_show_cursors);
-
- // Decoders Menu
-#ifdef ENABLE_DECODE
- QMenu *const menu_decoders = new QMenu;
- menu_decoders->setTitle(tr("&Decoders"));
+ assert(main_window);
+
+ shared_ptr<MainBar> main_bar = session.main_bar();
+
+ QDockWidget* dock = new QDockWidget(title, main_window);
+ dock->setObjectName(title);
+ main_window->addDockWidget(Qt::TopDockWidgetArea, dock);
+
+ // Insert a QMainWindow into the dock widget to allow for a tool bar
+ QMainWindow *dock_main = new QMainWindow(dock);
+ dock_main->setWindowFlags(Qt::Widget); // Remove Qt::Window flag
+
+ if (type == views::ViewTypeTrace)
+ // 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);
+
+ if (!v)
+ return nullptr;
+
+ view_docks_[dock] = v;
+ session.register_view(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") // clazy:exclude=detaching-temporary
+ .front();
+
+ connect(close_btn, SIGNAL(clicked(bool)),
+ this, SLOT(on_view_close_clicked()));
+
+ connect(&session, SIGNAL(trigger_event(int, util::Timestamp)),
+ qobject_cast<views::ViewBase*>(v.get()),
+ SLOT(trigger_event(int, util::Timestamp)));
+
+ if (type == views::ViewTypeTrace) {
+ views::trace::View *tv =
+ qobject_cast<views::trace::View*>(v.get());
+
+ tv->enable_colored_bg(settings.value(GlobalSettings::Key_View_ColoredBG).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*)));
+ connect(main_bar.get(), SIGNAL(show_decoder_selector(Session*)),
+ this, SLOT(on_show_decoder_selector(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<subwindows::SubWindowBase> MainWindow::add_subwindow(
+ subwindows::SubWindowType type, Session &session)
+{
+ GlobalSettings settings;
+ shared_ptr<subwindows::SubWindowBase> v;
+
+ QMainWindow *main_window = nullptr;
+ for (auto entry : session_windows_)
+ if (entry.first.get() == &session)
+ main_window = entry.second;
+
+ assert(main_window);