From 4d40f2984ae9fbe683a1aee466bcf28fe970e96a Mon Sep 17 00:00:00 2001 From: Don Gagne Date: Mon, 29 Dec 2014 19:17:30 -0800 Subject: [PATCH] New MainWindow central and dock widget architecture - Central widget no longer stacked. Views are added/removed to layout to switch view - Dock Widgets are globals with single instance of each type - Both central views and dock widgets are just-in-time created saving lots of memory --- qgroundcontrol.pro | 6 +- src/QGCConfig.h | 2 +- src/QGCDockWidget.cc | 39 ++ src/QGCDockWidget.h | 44 ++ src/ui/MainWindow.cc | 1046 +++++++++++++++-------------------- src/ui/MainWindow.h | 181 +++--- src/ui/MainWindow.ui | 1 - src/ui/menuactionhelper.cpp | 178 ------ src/ui/menuactionhelper.h | 51 -- src/ui/submainwindow.cpp | 6 - src/ui/submainwindow.h | 17 - 11 files changed, 601 insertions(+), 970 deletions(-) create mode 100644 src/QGCDockWidget.cc create mode 100644 src/QGCDockWidget.h delete mode 100644 src/ui/menuactionhelper.cpp delete mode 100644 src/ui/menuactionhelper.h delete mode 100644 src/ui/submainwindow.cpp delete mode 100644 src/ui/submainwindow.h diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 26d0dab76..19364cb67 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -451,7 +451,6 @@ HEADERS += \ src/ui/QGCHilFlightGearConfiguration.h \ src/ui/QGCHilJSBSimConfiguration.h \ src/ui/QGCHilXPlaneConfiguration.h \ - src/ui/submainwindow.h \ src/ui/uas/UASQuickView.h \ src/ui/uas/UASQuickViewItem.h \ src/ui/linechart/ChartPlot.h \ @@ -480,7 +479,6 @@ HEADERS += \ src/ui/px4_configuration/PX4Bootloader.h \ src/ui/px4_configuration/PX4FirmwareUpgradeThread.h \ src/ui/px4_configuration/PX4FirmwareUpgrade.h \ - src/ui/menuactionhelper.h \ src/uas/UASManagerInterface.h \ src/uas/QGCUASParamManagerInterface.h \ src/uas/QGCUASFileManager.h \ @@ -495,6 +493,7 @@ HEADERS += \ src/QGCQuickWidget.h \ src/QGCPalette.h \ src/QGCQmlWidgetHolder.h \ + src/QGCDockWidget.h \ SOURCES += \ src/main.cc \ @@ -595,7 +594,6 @@ SOURCES += \ src/ui/QGCHilFlightGearConfiguration.cc \ src/ui/QGCHilJSBSimConfiguration.cc \ src/ui/QGCHilXPlaneConfiguration.cc \ - src/ui/submainwindow.cpp \ src/ui/uas/UASQuickViewItem.cc \ src/ui/uas/UASQuickView.cc \ src/ui/linechart/ChartPlot.cc \ @@ -624,7 +622,6 @@ SOURCES += \ src/ui/px4_configuration/PX4Bootloader.cc \ src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc \ src/ui/px4_configuration/PX4FirmwareUpgrade.cc \ - src/ui/menuactionhelper.cpp \ src/uas/QGCUASFileManager.cc \ src/ui/QGCUASFileView.cc \ src/CmdLineOptParser.cc \ @@ -636,6 +633,7 @@ SOURCES += \ src/QGCQuickWidget.cc \ src/QGCPalette.cc \ src/QGCQmlWidgetHolder.cpp \ + src/QGCDockWidget.cc \ # # Unit Test specific configuration goes here diff --git a/src/QGCConfig.h b/src/QGCConfig.h index fad5b727d..a119bc823 100644 --- a/src/QGCConfig.h +++ b/src/QGCConfig.h @@ -12,7 +12,7 @@ // If you need to make an incompatible changes to stored settings, bump this version number // up by 1. This will caused store settings to be cleared on next boot. -#define QGC_SETTINGS_VERSION 2 +#define QGC_SETTINGS_VERSION 3 #define QGC_APPLICATION_NAME "QGroundControl" #define QGC_ORG_NAME "QGroundControl.org" diff --git a/src/QGCDockWidget.cc b/src/QGCDockWidget.cc new file mode 100644 index 000000000..b087abbba --- /dev/null +++ b/src/QGCDockWidget.cc @@ -0,0 +1,39 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#include "QGCDockWidget.h" + +#include + +QGCDockWidget::QGCDockWidget(const QString& title, QWidget *parent, Qt::WindowFlags flags) : + QDockWidget(title, parent, flags) +{ + +} + +// Instead of destroying the widget just hide it +void QGCDockWidget::closeEvent(QCloseEvent* event) +{ + event->ignore(); + setVisible(false); +} diff --git a/src/QGCDockWidget.h b/src/QGCDockWidget.h new file mode 100644 index 000000000..ffc2fb135 --- /dev/null +++ b/src/QGCDockWidget.h @@ -0,0 +1,44 @@ +/*===================================================================== + + QGroundControl Open Source Ground Control Station + + (c) 2009 - 2014 QGROUNDCONTROL PROJECT + + This file is part of the QGROUNDCONTROL project + + QGROUNDCONTROL is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + QGROUNDCONTROL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with QGROUNDCONTROL. If not, see . + + ======================================================================*/ + +#ifndef QGCDockWidget_h +#define QGCDockWidget_h + +#include + +/// @file +/// @brief Subclass of QDockWidget so we can intercept the closeEvent. +/// +/// @author Don Gagne + +class QGCDockWidget : public QDockWidget { + Q_OBJECT + +public: + QGCDockWidget(const QString& title, QWidget *parent = 0, Qt::WindowFlags flags = 0); + + void closeEvent(QCloseEvent* event); +}; + + +#endif diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index 058ffab1d..a885ab52f 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -28,7 +28,6 @@ This file is part of the QGROUNDCONTROL project */ #include -#include #include #include #include @@ -66,11 +65,11 @@ This file is part of the QGROUNDCONTROL project #include "SetupView.h" #include "SerialSettingsDialog.h" #include "terminalconsole.h" -#include "menuactionhelper.h" #include "QGCUASFileViewMulti.h" #include "QGCApplication.h" #include "QGCFileDialog.h" #include "QGCMessageBox.h" +#include "QGCDockWidget.h" #ifdef QGC_OSG_ENABLED #include "Q3DWidgetFactory.h" @@ -78,6 +77,22 @@ This file is part of the QGROUNDCONTROL project #include "LogCompressor.h" +const char* MainWindow::_uasControlDockWidgetName = "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET"; +const char* MainWindow::_uasListDockWidgetName = "UNMANNED_SYSTEM_LIST_DOCKWIDGET"; +const char* MainWindow::_waypointsDockWidgetName = "WAYPOINT_LIST_DOCKWIDGET"; +const char* MainWindow::_mavlinkDockWidgetName = "MAVLINK_INSPECTOR_DOCKWIDGET"; +const char* MainWindow::_parametersDockWidgetName = "PARAMETER_INTERFACE_DOCKWIDGET"; +const char* MainWindow::_filesDockWidgetName = "FILE_VIEW_DOCKWIDGET"; +const char* MainWindow::_uasStatusDetailsDockWidgetName = "UAS_STATUS_DETAILS_DOCKWIDGET"; +const char* MainWindow::_mapViewDockWidgetName = "MAP_VIEW_DOCKWIDGET"; +const char* MainWindow::_hsiDockWidgetName = "HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET"; +const char* MainWindow::_hdd1DockWidgetName = "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"; +const char* MainWindow::_hdd2DockWidgetName = "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"; +const char* MainWindow::_pfdDockWidgetName = "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET"; +const char* MainWindow::_hudDockWidgetName = "HEAD_UP_DISPLAY_DOCKWIDGET"; +const char* MainWindow::_uasInfoViewDockWidgetName = "UAS_INFO_INFOVIEW_DOCKWIDGET"; +const char* MainWindow::_debugConsoleDockWidgetName = "COMMUNICATION_CONSOLE_DOCKWIDGET"; + static MainWindow* _instance = NULL; ///< @brief MainWindow singleton MainWindow* MainWindow::_create(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE mode) @@ -106,13 +121,13 @@ void MainWindow::deleteInstance(void) /// by MainWindow::_create method. Hence no other code should have access to /// constructor. MainWindow::MainWindow(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE mode) : - currentView(VIEW_FLIGHT), centerStackActionGroup(new QActionGroup(this)), autoReconnect(false), simulationLink(NULL), lowPowerMode(false), customMode(mode), - menuActionHelper(new MenuActionHelper()), + _currentView(VIEW_FLIGHT), + _currentViewWidget(NULL), _splashScreen(splashScreen) { Q_ASSERT(_instance == NULL); @@ -122,52 +137,42 @@ MainWindow::MainWindow(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE connect(this, &MainWindow::initStatusChanged, splashScreen, &QSplashScreen::showMessage); } - connect(menuActionHelper, SIGNAL(needToShowDockWidget(QString,bool)),SLOT(showDockWidget(QString,bool))); - loadSettings(); - if (settings.contains("ADVANCED_MODE")) - { - menuActionHelper->setAdvancedMode(settings.value("ADVANCED_MODE").toBool()); - } - // Select the proper view. Default to the flight view or load the last one used if it's supported. - if (!settings.contains("CURRENT_VIEW")) - { - settings.setValue("CURRENT_VIEW", currentView); - } - else - { - VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt(); - switch (currentViewCandidate) { - case VIEW_ENGINEER: - case VIEW_MISSION: - case VIEW_FLIGHT: - case VIEW_SIMULATION: - case VIEW_SETUP: - case VIEW_TERMINAL: - -// And only re-load views if they're supported with the current QGC build + VIEW_SECTIONS currentViewCandidate = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", _currentView).toInt(); + switch (currentViewCandidate) { + case VIEW_ENGINEER: + case VIEW_MISSION: + case VIEW_FLIGHT: + case VIEW_SIMULATION: + case VIEW_SETUP: + case VIEW_TERMINAL: #ifdef QGC_OSG_ENABLED - case VIEW_LOCAL3D: + case VIEW_LOCAL3D: #endif #ifdef QGC_GOOGLE_EARTH_ENABLED - case VIEW_GOOGLEEARTH: + case VIEW_GOOGLEEARTH: #endif - - currentView = currentViewCandidate; - default: - // If an invalid view candidate was found in the settings file, just use the default view and re-save. - settings.setValue("CURRENT_VIEW", currentView); - break; - } + _currentView = currentViewCandidate; + break; + + default: + // Leave _currentView to the default + break; } + + // Put it back, which will set it to a valid value + settings.setValue("CURRENT_VIEW", _currentView); emit initStatusChanged(tr("Setting up user interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); // Setup user interface ui.setupUi(this); - menuActionHelper->setMenu(ui.menuTools); + + // Setup central widget with a layout to hold the views + _centralLayout = new QVBoxLayout(); + centralWidget()->setLayout(_centralLayout); // Set dock options setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks); @@ -186,10 +191,6 @@ MainWindow::MainWindow(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE // Setup UI state machines centerStackActionGroup->setExclusive(true); - centerStack = new QStackedWidget(this); - setCentralWidget(centerStack); - - // Load Toolbar toolBar = new QGCToolBar(this); this->addToolBar(toolBar); @@ -215,8 +216,7 @@ MainWindow::MainWindow(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE emit initStatusChanged(tr("Building common widgets."), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - buildCommonWidgets(); - connectCommonWidgets(); + _buildCommonWidgets(); emit initStatusChanged(tr("Building common actions"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); @@ -267,13 +267,10 @@ MainWindow::MainWindow(QSplashScreen* splashScreen, enum MainWindow::CUSTOM_MODE // Set low power mode enableLowPowerMode(lowPowerMode); - // Initialize window state - windowStateVal = windowState(); - emit initStatusChanged(tr("Restoring last view state"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); // Restore the window setup - loadViewState(); + _loadCurrentViewState(); emit initStatusChanged(tr("Restoring last window size"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); // Restore the window position and size @@ -363,31 +360,7 @@ MainWindow::~MainWindow() joystick = NULL; } - // Get and delete all dockwidgets and contained - // widgets - QObjectList childList(this->children()); - - QObjectList::iterator i; - QDockWidget* dockWidget; - for (i = childList.begin(); i != childList.end(); ++i) - { - dockWidget = dynamic_cast(*i); - if (dockWidget) - { - // Remove dock widget from main window - // removeDockWidget(dockWidget); - // delete dockWidget->widget(); - delete dockWidget; - dockWidget = NULL; - } - else if (dynamic_cast(*i)) - { - delete dynamic_cast(*i); - *i = NULL; - } - } // Delete all UAS objects - delete menuActionHelper; for (int i=0;ideleteLater(); @@ -405,10 +378,10 @@ QString MainWindow::getWindowStateKey() { if (UASManager::instance()->getActiveUAS()) { - return QString::number(currentView)+"_windowstate_" + QString::number(getCustomMode()) + "_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName(); + return QString::number(_currentView)+"_windowstate_" + QString::number(getCustomMode()) + "_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName(); } else - return QString::number(currentView)+"_windowstate_" + QString::number(getCustomMode()); + return QString::number(_currentView)+"_windowstate_" + QString::number(getCustomMode()); } QString MainWindow::getWindowGeometryKey() @@ -416,64 +389,61 @@ QString MainWindow::getWindowGeometryKey() return "_geometry"; } -void MainWindow::buildCustomWidget() +void MainWindow::_buildCustomWidgets(void) { + Q_ASSERT(_customWidgets.count() == 0); + // Create custom widgets - QList widgets = QGCToolWidget::createWidgetsFromSettings(this); + _customWidgets = QGCToolWidget::createWidgetsFromSettings(this); - if (widgets.size() > 0) + if (_customWidgets.size() > 0) { ui.menuTools->addSeparator(); } - - for(int i = 0; i < widgets.size(); ++i) - { + + foreach(QGCToolWidget* tool, _customWidgets) { // Check if this widget already has a parent, do not create it in this case - QGCToolWidget* tool = widgets.at(i); QDockWidget* dock = dynamic_cast(tool->parentWidget()); - if (!dock) - { - QSettings settings; - settings.beginGroup("QGC_MAINWINDOW"); - - // Load dock widget location (default is bottom) - Qt::DockWidgetArea location = tool->getDockWidgetArea(currentView); - - int view = settings.value(QString("TOOL_PARENT_") + tool->objectName(),-1).toInt(); - settings.endGroup(); - - QDockWidget* dock; - - switch (view) - { - case VIEW_ENGINEER: - dock = createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - default: // Flight view is the default. - case VIEW_FLIGHT: - dock = createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - case VIEW_SIMULATION: - dock = createDockWidget(simView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - case VIEW_MISSION: - dock = createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - case VIEW_GOOGLEEARTH: - dock = createDockWidget(googleEarthView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - case VIEW_LOCAL3D: - dock = createDockWidget(local3DView,tool,tool->getTitle(),tool->objectName(),(VIEW_SECTIONS)view,location); - break; - } - - // XXX temporary "fix" - dock->hide(); + + if (!dock) { + _createDockWidget(tool->getTitle(), tool->objectName(), Qt::BottomDockWidgetArea, tool); } } } -void MainWindow::buildCommonWidgets() +void MainWindow::_createDockWidget(const QString& title, const QString& name, Qt::DockWidgetArea area, QWidget* innerWidget) +{ + Q_ASSERT(!_mapName2DockWidget.contains(name)); + + QGCDockWidget* dockWidget = new QGCDockWidget(title, this); + Q_CHECK_PTR(dockWidget); + dockWidget->setObjectName(name); + dockWidget->setVisible (false); + + if (innerWidget) { + // Put inner widget inside QDockWidget + innerWidget->setParent(dockWidget); + dockWidget->setWidget(innerWidget); + innerWidget->setVisible(true); + } + + // Add to menu + + QAction* action = new QAction(title, NULL); + action->setCheckable(true); + action->setData(name); + + connect(action, &QAction::triggered, this, &MainWindow::_showDockWidgetAction); + + ui.menuTools->addAction(action); + + _mapName2DockWidget[name] = dockWidget; + _mapDockWidget2Action[dockWidget] = action; + + addDockWidget(area, dockWidget); +} + +void MainWindow::_buildCommonWidgets(void) { // Add generic MAVLink decoder mavlinkDecoder = new MAVLinkDecoder(MAVLinkProtocol::instance(), this); @@ -484,274 +454,246 @@ void MainWindow::buildCommonWidgets() logPlayer = new QGCMAVLinkLogPlayer(MAVLinkProtocol::instance(), statusBar()); statusBar()->addPermanentWidget(logPlayer); - // Initialize all of the views, if they haven't been already, and add their central widgets - if (!plannerView) - { - plannerView = new SubMainWindow(this); - plannerView->setObjectName("VIEW_MISSION"); - plannerView->setCentralWidget(new QGCMapTool(this)); - addToCentralStackedWidget(plannerView, VIEW_MISSION, "Maps"); - } - if (!pilotView) - { - pilotView = new SubMainWindow(this); - pilotView->setObjectName("VIEW_FLIGHT"); - pilotView->setCentralWidget(new PrimaryFlightDisplay(this)); - addToCentralStackedWidget(pilotView, VIEW_FLIGHT, "Pilot"); - } - if (!terminalView) - { - terminalView = new SubMainWindow(this); - terminalView->setObjectName("VIEW_TERMINAL"); - TerminalConsole *terminalConsole = new TerminalConsole(this); - terminalView->setCentralWidget(terminalConsole); - addToCentralStackedWidget(terminalView, VIEW_TERMINAL, tr("Terminal View")); - } - if (!setupView) - { - setupView = new SubMainWindow(this); - setupView->setObjectName("VIEW_SETUP"); - setupView->setCentralWidget((QWidget*)new SetupView(this)); - addToCentralStackedWidget(setupView, VIEW_SETUP, "Setup"); - } - if (!engineeringView) - { - engineeringView = new SubMainWindow(this); - engineeringView->setObjectName("VIEW_ENGINEER"); - engineeringView->setCentralWidget(new QGCDataPlot2D(this)); - addToCentralStackedWidget(engineeringView, VIEW_ENGINEER, tr("Logfile Plot")); - } -#ifdef QGC_GOOGLE_EARTH_ENABLED - if (!googleEarthView) - { - googleEarthView = new SubMainWindow(this); - googleEarthView->setObjectName("VIEW_GOOGLEEARTH"); - googleEarthView->setCentralWidget(new QGCGoogleEarthView(this)); - addToCentralStackedWidget(googleEarthView, VIEW_GOOGLEEARTH, tr("Google Earth View")); + // In order for Qt to save and restore state of widgets all widgets must be created ahead of time. We only create the QDockWidget + // holders. We do not create the actual inner widget until it is needed. This saves memory and cpu from running widgets that are + // never shown. + + struct DockWidgetInfo { + const char* name; + const char* title; + Qt::DockWidgetArea area; + }; + + static const struct DockWidgetInfo rgDockWidgetInfo[] = { + { _uasControlDockWidgetName, "Control", Qt::LeftDockWidgetArea }, + { _uasListDockWidgetName, "Unmanned Systems", Qt::RightDockWidgetArea }, + { _waypointsDockWidgetName, "Mission Plan", Qt::BottomDockWidgetArea }, + { _mavlinkDockWidgetName, "MAVLink Inspector", Qt::RightDockWidgetArea }, + { _parametersDockWidgetName, "Onboard Parameters", Qt::RightDockWidgetArea }, + { _filesDockWidgetName, "Onboard Files", Qt::RightDockWidgetArea }, + { _uasStatusDetailsDockWidgetName, "Status Details", Qt::RightDockWidgetArea }, + { _mapViewDockWidgetName, "Map view", Qt::RightDockWidgetArea }, + { _hsiDockWidgetName, "Horizontal Situation", Qt::BottomDockWidgetArea }, + { _hdd1DockWidgetName, "Flight Display", Qt::RightDockWidgetArea }, + { _hdd2DockWidgetName, "Actuator Status", Qt::RightDockWidgetArea }, + { _pfdDockWidgetName, "Primary Flight Display", Qt::RightDockWidgetArea }, + { _hudDockWidgetName, "Video Downlink", Qt::RightDockWidgetArea }, + { _uasInfoViewDockWidgetName, "Info View", Qt::LeftDockWidgetArea }, + { _debugConsoleDockWidgetName, "Communications Console", Qt::LeftDockWidgetArea } + }; + static const size_t cDockWidgetInfo = sizeof(rgDockWidgetInfo) / sizeof(rgDockWidgetInfo[0]); + + for (size_t i=0; ititle, pDockInfo->name, pDockInfo->area, NULL /* no inner widget yet */); } -#endif -#ifdef QGC_OSG_ENABLED - if (!local3DView) - { - q3DWidget = Q3DWidgetFactory::get("PIXHAWK", this); - q3DWidget->setObjectName("VIEW_3DWIDGET"); - local3DView = new SubMainWindow(this); - local3DView->setObjectName("VIEW_LOCAL3D"); - local3DView->setCentralWidget(q3DWidget); - addToCentralStackedWidget(local3DView, VIEW_LOCAL3D, tr("Local 3D View")); - } -#endif + _buildCustomWidgets(); +} - if (!simView) - { - simView = new SubMainWindow(this); - simView->setObjectName("VIEW_SIMULATOR"); - simView->setCentralWidget(new QGCMapTool(this)); - addToCentralStackedWidget(simView, VIEW_SIMULATION, tr("Simulation View")); +void MainWindow::_buildPlannerView(void) +{ + if (!_plannerView) { + _plannerView = new QGCMapTool(this); + _plannerView->setVisible(false); } +} - // Add dock widgets for the planner view - createDockWidget(plannerView, new UASListWidget(this), tr("Unmanned Systems"), "UNMANNED_SYSTEM_LIST_DOCKWIDGET", VIEW_MISSION, Qt::LeftDockWidgetArea); - createDockWidget(plannerView, new QGCWaypointListMulti(this), tr("Mission Plan"), "WAYPOINT_LIST_DOCKWIDGET", VIEW_MISSION, Qt::BottomDockWidgetArea); - - // Add dock widgets for the pilot view - createDockWidget(pilotView, new DebugConsole(this), tr("Communications Console"), "COMMUNICATION_CONSOLE_DOCKWIDGET", VIEW_FLIGHT, Qt::LeftDockWidgetArea); - QGCTabbedInfoView *infoview = new QGCTabbedInfoView(this); - infoview->addSource(mavlinkDecoder); - createDockWidget(pilotView, infoview, tr("Info View"), "UAS_INFO_INFOVIEW_DOCKWIDGET", VIEW_FLIGHT, Qt::LeftDockWidgetArea); - - // Add dock widgets for the simulation view - createDockWidget(simView,new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",VIEW_SIMULATION,Qt::LeftDockWidgetArea); - createDockWidget(simView,new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",VIEW_SIMULATION,Qt::BottomDockWidgetArea); - createDockWidget(simView, new ParameterInterface(this), tr("Onboard Parameters"), "PARAMETER_INTERFACE_DOCKWIDGET", VIEW_SIMULATION, Qt::RightDockWidgetArea); - createDockWidget(simView, new PrimaryFlightDisplay(this), tr("Primary Flight Display"), "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET", VIEW_SIMULATION, Qt::RightDockWidgetArea); - - // Add dock widgets for the engineering view - createDockWidget(engineeringView, new QGCMAVLinkInspector(MAVLinkProtocol::instance(), this), tr("MAVLink Inspector"), "MAVLINK_INSPECTOR_DOCKWIDGET", VIEW_ENGINEER, Qt::RightDockWidgetArea); - createDockWidget(engineeringView, new ParameterInterface(this), tr("Onboard Parameters"), "PARAMETER_INTERFACE_DOCKWIDGET", VIEW_ENGINEER, Qt::RightDockWidgetArea); - createDockWidget(engineeringView, new QGCUASFileViewMulti(this), tr("Onboard Files"), "FILE_VIEW_DOCKWIDGET", VIEW_ENGINEER, Qt::RightDockWidgetArea); - createDockWidget(engineeringView, new HUD(320, 240, this), tr("Video Downlink"), "HEAD_UP_DISPLAY_DOCKWIDGET", VIEW_ENGINEER, Qt::RightDockWidgetArea); - - // Add some extra widgets to the Tool Widgets menu - menuActionHelper->createToolAction(tr("Map View"), "MAP_VIEW_DOCKWIDGET"); - menuActionHelper->createToolAction(tr("Status Details"), "UAS_STATUS_DETAILS_DOCKWIDGET"); - menuActionHelper->createToolAction(tr("Flight Display"), "HEAD_DOWN_DISPLAY_1_DOCKWIDGET"); - menuActionHelper->createToolAction(tr("Actuator Status"), "HEAD_DOWN_DISPLAY_2_DOCKWIDGET"); - - // Add any custom widgets last to all menus and layouts - buildCustomWidget(); +void MainWindow::_buildPilotView(void) +{ + if (!_pilotView) { + _pilotView = new PrimaryFlightDisplay(this); + _pilotView->setVisible(false); + } } -void MainWindow::addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area) +void MainWindow::_buildSetupView(void) { - menuActionHelper->createToolActionForCustomDockWidget(title, widget->objectName(), widget, view); - parent->addDockWidget(area,widget); + if (!_setupView) { + _setupView = new SetupView(this); + _setupView->setVisible(false); + } } -QDockWidget* MainWindow::createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectName,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize) +void MainWindow::_buildEngineeringView(void) { - SubMainWindow *parent = qobject_cast(subMainWindowParent); - Q_ASSERT(parent); - QDockWidget* dockWidget = menuActionHelper->createDockWidget(title, objectName); - child->setObjectName(objectName); - dockWidget->setWidget(child); //Set child objectName before setting dockwidget, since the dock widget might react to object name changes - connect(child, SIGNAL(destroyed()), dockWidget, SLOT(deleteLater())); //Our dockwidget only has only child widget, so kill the dock widget if the child is deleted + if (!_engineeringView) { + _engineeringView = new QGCDataPlot2D(this); + _engineeringView->setVisible(false); + } +} - if (minSize.height() >= 0) - dockWidget->setMinimumHeight(minSize.height()); - if (minSize.width() >= 0) - dockWidget->setMinimumWidth(minSize.width()); - addTool(parent,view,dockWidget,title,area); - return dockWidget; +void MainWindow::_buildSimView(void) +{ + if (!_simView) { + _simView = new QGCMapTool(this); + _simView->setVisible(false); + } } -void MainWindow::showDockWidget(const QString& name, bool show) +void MainWindow::_buildTerminalView(void) { - QDockWidget *dockWidget = menuActionHelper->getDockWidget(currentView, name); - if(dockWidget) - dockWidget->setVisible(show); - else if (show) - loadDockWidget(name); + if (!_terminalView) { + _terminalView = new TerminalConsole(this); + _terminalView->setVisible(false); + } } -void MainWindow::fullScreenActionItemCallback() +void MainWindow::_buildGoogleEarthView(void) { - ui.actionNormal->setChecked(false); +#ifdef QGC_GOOGLE_EARTH_ENABLED + if (!_googleEarthView) { + _googleEarthView = new QGCGoogleEarthView(this); + _googleEarthView->setVisible(false); + } +#endif } -void MainWindow::normalActionItemCallback() +void MainWindow::_buildLocal3DView(void) { - ui.actionFullscreen->setChecked(false); +#ifdef QGC_OSG_ENABLED + if (!_local3DView) { + _local3DView = Q3DWidgetFactory::get("PIXHAWK", this); + _local3DView->setVisible(false); + } +#endif } -void MainWindow::loadDockWidget(const QString& name) +/// Shows or hides the specified dock widget, creating if necessary +void MainWindow::_showDockWidget(const QString& name, bool show) { - if(menuActionHelper->containsDockWidget(currentView, name)) + if (!_mapName2DockWidget.contains(name)) { + qWarning() << "Attempt to show unknown dock widget" << name; return; - - if (name.startsWith("HIL_CONFIG")) - { - //It's a HIL widget. - showHILConfigurationWidget(UASManager::instance()->getActiveUAS()); - } - else if (name == "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new UASControlWidget(this),tr("Control"),"UNMANNED_SYSTEM_CONTROL_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea); - } - else if (name == "UNMANNED_SYSTEM_LIST_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new UASListWidget(this),tr("Unmanned Systems"),"UNMANNED_SYSTEM_LIST_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "WAYPOINT_LIST_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new QGCWaypointListMulti(this),tr("Mission Plan"),"WAYPOINT_LIST_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea); - } - else if (name == "MAVLINK_INSPECTOR_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new QGCMAVLinkInspector(MAVLinkProtocol::instance(),this),tr("MAVLink Inspector"),"MAVLINK_INSPECTOR_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "PARAMETER_INTERFACE_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new ParameterInterface(this),tr("Onboard Parameters"),"PARAMETER_INTERFACE_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "FILE_VIEW_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new QGCUASFileViewMulti(this),tr("Onboard Files"),"FILE_VIEW_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "UAS_STATUS_DETAILS_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new UASInfoWidget(this),tr("Status Details"),"UAS_STATUS_DETAILS_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); } - else if (name == "MAP_VIEW_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new QGCMapTool(this),tr("Map view"),"MAP_VIEW_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET") - { - //This is now a permanently detached window. - } - else if (name == "HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new HSIDisplay(this),tr("Horizontal Situation"),"HORIZONTAL_SITUATION_INDICATOR_DOCKWIDGET",currentView,Qt::BottomDockWidgetArea); + + // Create the inner widget if we need to + if (!_mapName2DockWidget[name]->widget()) { + _createInnerDockWidget(name); } - else if (name == "HEAD_DOWN_DISPLAY_1_DOCKWIDGET") - { + + Q_ASSERT(_mapName2DockWidget.contains(name)); + QDockWidget* dockWidget = _mapName2DockWidget[name]; + Q_ASSERT(dockWidget); + + dockWidget->setVisible(show); + + Q_ASSERT(_mapDockWidget2Action.contains(dockWidget)); + _mapDockWidget2Action[dockWidget]->setChecked(show); +} + +/// Creates the specified inner dock widget and adds to the QDockWidget +void MainWindow::_createInnerDockWidget(const QString& widgetName) +{ + Q_ASSERT(_mapName2DockWidget.contains(widgetName)); // QDockWidget should already exist + Q_ASSERT(!_mapName2DockWidget[widgetName]->widget()); // Inner widget should not + + QWidget* widget = NULL; + + if (widgetName == _uasControlDockWidgetName) { + widget = new UASControlWidget(this); + } else if (widgetName == _uasListDockWidgetName) { + widget = new UASListWidget(this); + } else if (widgetName == _waypointsDockWidgetName) { + widget = new QGCWaypointListMulti(this); + } else if (widgetName == _mavlinkDockWidgetName) { + widget = new QGCMAVLinkInspector(MAVLinkProtocol::instance(),this); + } else if (widgetName == _parametersDockWidgetName) { + widget = new ParameterInterface(this); + } else if (widgetName == _filesDockWidgetName) { + widget = new QGCUASFileViewMulti(this); + } else if (widgetName == _uasStatusDetailsDockWidgetName) { + widget = new UASInfoWidget(this); + } else if (widgetName == _mapViewDockWidgetName) { + widget = new QGCMapTool(this); + } else if (widgetName == _hsiDockWidgetName) { + widget = new HSIDisplay(this); + } else if (widgetName == _hdd1DockWidgetName) { QStringList acceptList; acceptList.append("-3.3,ATTITUDE.roll,rad,+3.3,s"); acceptList.append("-3.3,ATTITUDE.pitch,deg,+3.3,s"); acceptList.append("-3.3,ATTITUDE.yaw,deg,+3.3,s"); HDDisplay *hddisplay = new HDDisplay(acceptList,"Flight Display",this); hddisplay->addSource(mavlinkDecoder); - createDockWidget(centerStack->currentWidget(),hddisplay,tr("Flight Display"),"HEAD_DOWN_DISPLAY_1_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "HEAD_DOWN_DISPLAY_2_DOCKWIDGET") - { + + widget = hddisplay; + } else if (widgetName == _hdd2DockWidgetName) { QStringList acceptList; acceptList.append("0,RAW_PRESSURE.pres_abs,hPa,65500"); HDDisplay *hddisplay = new HDDisplay(acceptList,"Actuator Status",this); hddisplay->addSource(mavlinkDecoder); - createDockWidget(centerStack->currentWidget(),hddisplay,tr("Actuator Status"),"HEAD_DOWN_DISPLAY_2_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new PrimaryFlightDisplay(this),tr("Primary Flight Display"),"PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "HEAD_UP_DISPLAY_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new HUD(320,240,this),tr("Video Downlink"),"HEAD_UP_DISPLAY_DOCKWIDGET",currentView,Qt::RightDockWidgetArea); - } - else if (name == "UAS_INFO_QUICKVIEW_DOCKWIDGET") - { - createDockWidget(centerStack->currentWidget(),new UASQuickView(this),tr("Quick View"),"UAS_INFO_QUICKVIEW_DOCKWIDGET",currentView,Qt::LeftDockWidgetArea); + + widget = hddisplay; + } else if (widgetName == _pfdDockWidgetName) { + widget = new PrimaryFlightDisplay(this); + } else if (widgetName == _hudDockWidgetName) { + widget = new HUD(320,240,this); + } else if (widgetName == _uasInfoViewDockWidgetName) { + widget = new QGCTabbedInfoView(this); + } else if (widgetName == _debugConsoleDockWidgetName) { + widget = new DebugConsole(this); + } else { + qWarning() << "Attempt to create unknown Inner Dock Widget" << widgetName; } - else - { - if (customWidgetNameToFilenameMap.contains(name)) - { - loadCustomWidget(customWidgetNameToFilenameMap[name],currentView); - } - else - { - qDebug() << "Error loading window:" << name; - } + + if (widget) { + QDockWidget* dockWidget = _mapName2DockWidget[widgetName]; + Q_CHECK_PTR(dockWidget); + + widget->setParent(dockWidget); + dockWidget->setWidget(widget); } } -void MainWindow::addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title) +void MainWindow::_showHILConfigurationWidgets(void) { - Q_UNUSED(viewSection); - Q_UNUSED(title); - Q_ASSERT(widget->objectName().length() != 0); + UASInterface* uas = UASManager::instance()->getActiveUAS(); + + if (!uas) { + return; + } + + UAS* mav = dynamic_cast(uas); + Q_ASSERT(mav); + + int uasId = mav->getUASID(); - // Check if this widget already has been added - if (centerStack->indexOf(widget) == -1) - { - centerStack->addWidget(widget); + if (!_mapUasId2HilDockWidget.contains(uasId)) { + + // Create QDockWidget + QGCDockWidget* dockWidget = new QGCDockWidget(tr("HIL Config %1").arg(uasId), this); + Q_CHECK_PTR(dockWidget); + dockWidget->setObjectName(tr("HIL_CONFIG_%1").arg(uasId)); + dockWidget->setVisible (false); + + // Create inner widget and set it + QWidget* widget = new QGCHilConfiguration(mav, dockWidget); + + widget->setParent(dockWidget); + dockWidget->setWidget(widget); + + _mapUasId2HilDockWidget[uasId] = dockWidget; + + addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + } + + if (_currentView == VIEW_SIMULATION) { + // HIL dock widgets only show up on simulation view + foreach (QDockWidget* dockWidget, _mapUasId2HilDockWidget) { + dockWidget->setVisible(true); + } } } - -void MainWindow::showCentralWidget() +void MainWindow::fullScreenActionItemCallback() { - QAction* act = qobject_cast(sender()); - QWidget* widget = act->data().value(); - centerStack->setCurrentWidget(widget); + ui.actionNormal->setChecked(false); } -void MainWindow::showHILConfigurationWidget(UASInterface* uas) +void MainWindow::normalActionItemCallback() { - // Add simulation configuration widget - UAS* mav = dynamic_cast(uas); - - if (mav && !hilDocks.contains(mav->getUASID())) - { - QGCHilConfiguration* hconf = new QGCHilConfiguration(mav, this); - QString hilDockName = tr("HIL Config %1").arg(uas->getUASName()); - QString hilDockObjectName = QString("HIL_CONFIG_%1").arg(uas->getUASName().toUpper().replace(' ','_')); - QDockWidget* hilDock = createDockWidget(simView, hconf,hilDockName, hilDockObjectName,VIEW_SIMULATION,Qt::LeftDockWidgetArea); - hilDocks.insert(mav->getUASID(), hilDock); - } + ui.actionFullscreen->setChecked(false); } void MainWindow::closeEvent(QCloseEvent *event) @@ -790,25 +732,13 @@ void MainWindow::closeEvent(QCloseEvent *event) Q_ASSERT(!link->isConnected()); } - storeViewState(); + _storeCurrentViewState(); storeSettings(); UASManager::instance()->storeSettings(); event->accept(); } -/** - * Connect the signals and slots of the common window widgets - */ -void MainWindow::connectCommonWidgets() -{ - if (infoDockWidget && infoDockWidget->widget()) - { - connect(MAVLinkProtocol::instance(), SIGNAL(receiveLossChanged(int, float)), - infoDockWidget->widget(), SLOT(updateSendLoss(int, float))); - } -} - -void MainWindow::createCustomWidget() +void MainWindow::_createNewCustomWidget(void) { if (QGCToolWidget::instances()->isEmpty()) { @@ -826,110 +756,23 @@ void MainWindow::createCustomWidget() QString title = tr("Custom Tool %1").arg(customToolIndex ); QGCToolWidget* tool = new QGCToolWidget(objectName, title); - createDockWidget(centerStack->currentWidget(),tool,title,objectName,currentView,Qt::BottomDockWidgetArea); - - QSettings settings; - settings.beginGroup("QGC_MAINWINDOW"); - settings.setValue(QString("TOOL_PARENT_") + tool->objectName(),currentView); - settings.endGroup(); + tool->resize(100, 100); + _createDockWidget(title, objectName, Qt::BottomDockWidgetArea, tool); + + _mapName2DockWidget[objectName]->setVisible(true); } -void MainWindow::loadCustomWidget() +void MainWindow::_loadCustomWidgetFromFile(void) { QString widgetFileExtension(".qgw"); QString fileName = QGCFileDialog::getOpenFileName(this, tr("Specify Widget File Name"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension)); - if (fileName != "") loadCustomWidget(fileName); -} -void MainWindow::loadCustomWidget(const QString& fileName, int view) -{ - QGCToolWidget* tool = new QGCToolWidget("", "", this); - if (tool->loadSettings(fileName, true)) - { - qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); - switch ((VIEW_SECTIONS)view) - { - case VIEW_ENGINEER: - createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - default: // Flight view is the default. - case VIEW_FLIGHT: - createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - case VIEW_SIMULATION: - createDockWidget(simView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - case VIEW_MISSION: - createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - } - } - else - { - return; - } -} - -void MainWindow::loadCustomWidget(const QString& fileName, bool singleinstance) -{ - QGCToolWidget* tool = new QGCToolWidget("", "", this); - if (tool->loadSettings(fileName, true) || !singleinstance) - { - qDebug() << "Loading custom tool:" << tool->getTitle() << tool->objectName(); - QSettings settings; - settings.beginGroup("QGC_MAINWINDOW"); - - int view = settings.value(QString("TOOL_PARENT_") + tool->objectName(),-1).toInt(); - switch (view) - { - case VIEW_ENGINEER: - createDockWidget(engineeringView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - default: // Flight view is the default. - case VIEW_FLIGHT: - createDockWidget(pilotView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - case VIEW_SIMULATION: - createDockWidget(simView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - case VIEW_MISSION: - createDockWidget(plannerView,tool,tool->getTitle(),tool->objectName()+"DOCK",(VIEW_SECTIONS)view,Qt::LeftDockWidgetArea); - break; - } - - - settings.endGroup(); - } - else - { - return; - } -} - -void MainWindow::loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType) -{ - QString defaultsDir = qApp->applicationDirPath() + "/files/" + autopilotType.toLower() + "/widgets/"; - QString platformDir = qApp->applicationDirPath() + "/files/" + autopilotType.toLower() + "/" + systemType.toLower() + "/widgets/"; - - QDir widgets(defaultsDir); - QStringList files = widgets.entryList(); - QDir platformWidgets(platformDir); - files.append(platformWidgets.entryList()); - - if (files.count() == 0) - { - qDebug() << "No default custom widgets for system " << systemType << "autopilot" << autopilotType << " found"; - qDebug() << "Tried with path: " << defaultsDir; - } - - // Load all custom widgets found in the AP folder - for(int i = 0; i < files.count(); ++i) - { - QString file = files[i]; - if (file.endsWith(".qgw")) - { - // Will only be loaded if not already a custom widget with - // the same name is present - loadCustomWidget(defaultsDir+"/"+file, true); + if (fileName != "") { + QGCToolWidget* tool = new QGCToolWidget("", "", this); + if (tool->loadSettings(fileName, true)) { + QString objectName = tool->objectName() + "DOCK"; + + _createDockWidget(tool->getTitle(), objectName, Qt::LeftDockWidgetArea, tool); + _mapName2DockWidget[objectName]->widget()->setVisible(true); } } } @@ -943,10 +786,7 @@ void MainWindow::loadSettings() settings.beginGroup("QGC_MAINWINDOW"); autoReconnect = settings.value("AUTO_RECONNECT", autoReconnect).toBool(); lowPowerMode = settings.value("LOW_POWER_MODE", lowPowerMode).toBool(); - bool dockWidgetTitleBarEnabled = settings.value("DOCK_WIDGET_TITLEBARS",menuActionHelper->dockWidgetTitleBarsEnabled()).toBool(); settings.endGroup(); - - enableDockWidgetTitleBars(dockWidgetTitleBarEnabled); } void MainWindow::storeSettings() @@ -963,13 +803,13 @@ void MainWindow::storeSettings() settings.setValue(getWindowGeometryKey(), saveGeometry()); // Save the last current view in any case - settings.setValue("CURRENT_VIEW", currentView); + settings.setValue("CURRENT_VIEW", _currentView); // Save the current window state, but only if a system is connected (else no real number of widgets would be present)) if (UASManager::instance()->getUASList().length() > 0) settings.setValue(getWindowStateKey(), saveState()); // Save the current UAS view if a UAS is connected - if (UASManager::instance()->getUASList().length() > 0) settings.setValue("CURRENT_VIEW_WITH_UAS_CONNECTED", currentView); + if (UASManager::instance()->getUASList().length() > 0) settings.setValue("CURRENT_VIEW_WITH_UAS_CONNECTED", _currentView); // And save any custom weidgets QGCToolWidget::storeWidgetsToSettings(settings); @@ -1030,14 +870,6 @@ void MainWindow::saveScreen() window.save(screenFileName, format.toLatin1()); } } -void MainWindow::enableDockWidgetTitleBars(bool enabled) -{ - menuActionHelper->setDockWidgetTitleBarsEnabled(enabled); - QSettings settings; - settings.beginGroup("QGC_MAINWINDOW"); - settings.setValue("DOCK_WIDGET_TITLEBARS",enabled); - settings.endGroup(); -} void MainWindow::enableAutoReconnect(bool enabled) { @@ -1071,42 +903,42 @@ void MainWindow::connectCommonActions() #endif // Mark the right one as selected - if (currentView == VIEW_ENGINEER) + if (_currentView == VIEW_ENGINEER) { ui.actionEngineersView->setChecked(true); ui.actionEngineersView->activate(QAction::Trigger); } - if (currentView == VIEW_FLIGHT) + if (_currentView == VIEW_FLIGHT) { ui.actionFlightView->setChecked(true); ui.actionFlightView->activate(QAction::Trigger); } - if (currentView == VIEW_SIMULATION) + if (_currentView == VIEW_SIMULATION) { ui.actionSimulationView->setChecked(true); ui.actionSimulationView->activate(QAction::Trigger); } - if (currentView == VIEW_MISSION) + if (_currentView == VIEW_MISSION) { ui.actionMissionView->setChecked(true); ui.actionMissionView->activate(QAction::Trigger); } - if (currentView == VIEW_SETUP) + if (_currentView == VIEW_SETUP) { ui.actionSetup->setChecked(true); ui.actionSetup->activate(QAction::Trigger); } - if (currentView == VIEW_TERMINAL) + if (_currentView == VIEW_TERMINAL) { ui.actionTerminalView->setChecked(true); ui.actionTerminalView->activate(QAction::Trigger); } - if (currentView == VIEW_GOOGLEEARTH) + if (_currentView == VIEW_GOOGLEEARTH) { ui.actionGoogleEarthView->setChecked(true); ui.actionGoogleEarthView->activate(QAction::Trigger); } - if (currentView == VIEW_LOCAL3D) + if (_currentView == VIEW_LOCAL3D) { ui.actionLocal3DView->setChecked(true); ui.actionLocal3DView->activate(QAction::Trigger); @@ -1121,8 +953,6 @@ void MainWindow::connectCommonActions() // Connect actions from ui connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink())); - ui.actionAdvanced_Mode->setChecked(menuActionHelper->isAdvancedMode()); - connect(ui.actionAdvanced_Mode,SIGNAL(toggled(bool)),this,SLOT(setAdvancedMode(bool))); // Connect internal actions connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*))); @@ -1151,8 +981,8 @@ void MainWindow::connectCommonActions() connect(ui.actionProject_Roadmap, SIGNAL(triggered()), this, SLOT(showRoadMap())); // Custom widget actions - connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget())); - connect(ui.actionLoadCustomWidgetFile, SIGNAL(triggered()), this, SLOT(loadCustomWidget())); + connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(_createNewCustomWidget())); + connect(ui.actionLoadCustomWidgetFile, SIGNAL(triggered()), this, SLOT(_loadCustomWidgetFromFile())); // Audio output ui.actionMuteAudioOutput->setChecked(GAudioOutput::instance()->isMuted()); @@ -1302,8 +1132,7 @@ void MainWindow::setActiveUAS(UASInterface* uas) Q_UNUSED(uas); if (settings.contains(getWindowStateKey())) { - SubMainWindow *win = qobject_cast(centerStack->currentWidget()); - win->restoreState(settings.value(getWindowStateKey()).toByteArray()); + restoreState(settings.value(getWindowStateKey()).toByteArray()); } } @@ -1316,10 +1145,6 @@ void MainWindow::UASSpecsChanged(int uas) void MainWindow::UASCreated(UASInterface* uas) { - // The pilot, operator and engineer views were not available on startup, enable them now - ui.actionFlightView->setEnabled(true); - ui.actionMissionView->setEnabled(true); - ui.actionEngineersView->setEnabled(true); // The UAS actions are not enabled without connection to system ui.actionLiftoff->setEnabled(true); ui.actionLand->setEnabled(true); @@ -1390,31 +1215,27 @@ void MainWindow::UASCreated(UASInterface* uas) break; } - connect(uas, SIGNAL(systemSpecsChanged(int)), this, SLOT(UASSpecsChanged(int))); connect(uas, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); connect(uas, SIGNAL(misconfigurationDetected(UASInterface*)), this, SLOT(handleMisconfiguration(UASInterface*))); // HIL - showHILConfigurationWidget(uas); + _showHILConfigurationWidgets(); if (!linechartWidget) { linechartWidget = new Linecharts(this); + linechartWidget->setVisible(false); } linechartWidget->addSource(mavlinkDecoder); - if (engineeringView->centralWidget() != linechartWidget) + if (_engineeringView != linechartWidget) { - engineeringView->setCentralWidget(linechartWidget); - linechartWidget->show(); + _engineeringView = linechartWidget; } - // Load default custom widgets for this autopilot type - loadCustomWidgetsFromDefaults(uas->getSystemTypeName(), uas->getAutopilotTypeName()); - // Reload view state in case new widgets were added - loadViewState(); + _loadCurrentViewState(); } void MainWindow::UASDeleted(UASInterface* uas) @@ -1423,104 +1244,146 @@ void MainWindow::UASDeleted(UASInterface* uas) // TODO: Update the UI when a UAS is deleted } -/** - * Stores the current view state - */ -void MainWindow::storeViewState() +/// Stores the state of the toolbar, status bar and widgets associated with the current view +void MainWindow::_storeCurrentViewState(void) { - // Save current state - SubMainWindow *win = qobject_cast(centerStack->currentWidget()); - QList widgets = win->findChildren(); - QString widgetnames = ""; - for (int i=0;iobjectName() + ","; + // HIL dock widgets are dynamic and are not part of the saved state + _hideAllHilDockWidgets(); + + // Save list of visible widgets + + bool firstWidget = true; + QString widgetNames = ""; + foreach(QDockWidget* dockWidget, _mapName2DockWidget) { + if (dockWidget->isVisible()) { + if (!firstWidget) { + widgetNames += ","; + } + widgetNames += dockWidget->objectName(); + firstWidget = false; + } } - widgetnames = widgetnames.mid(0,widgetnames.length()-1); - - settings.setValue(getWindowStateKey() + "WIDGETS",widgetnames); - settings.setValue(getWindowStateKey(), win->saveState()); - settings.setValue(getWindowStateKey()+"CENTER_WIDGET", centerStack->currentIndex()); - // Although we want save the state of the window, we do not want to change the top-leve state (minimized, maximized, etc) - // therefore this state is stored here and restored after applying the rest of the settings in the new - // perspective. - windowStateVal = this->windowState(); + + settings.setValue(getWindowStateKey() + "WIDGETS", widgetNames); + settings.setValue(getWindowStateKey(), saveState()); settings.setValue(getWindowGeometryKey(), saveGeometry()); } -void MainWindow::loadViewState() +/// Restores the state of the toolbar, status bar and widgets associated with the current view +void MainWindow::_loadCurrentViewState(void) { - // Restore center stack state - int index = settings.value(getWindowStateKey()+"CENTER_WIDGET", -1).toInt(); - - if (index != -1) - { - centerStack->setCurrentIndex(index); - } - else - { - // Hide custom widgets - if (detectionDockWidget) detectionDockWidget->hide(); - if (watchdogControlDockWidget) watchdogControlDockWidget->hide(); - - // Load defaults - switch (currentView) - { + QWidget* centerView; + QString defaultWidgets; + + switch (_currentView) { case VIEW_SETUP: - centerStack->setCurrentWidget(setupView); + _buildSetupView(); + centerView = _setupView; break; + case VIEW_ENGINEER: - centerStack->setCurrentWidget(engineeringView); + _buildEngineeringView(); + centerView = _engineeringView; + defaultWidgets = "MAVLINK_INSPECTOR_DOCKWIDGET,PARAMETER_INTERFACE_DOCKWIDGET,FILE_VIEW_DOCKWIDGET,HEAD_UP_DISPLAY_DOCKWIDGET"; break; - default: // Default to the flight view + case VIEW_FLIGHT: - centerStack->setCurrentWidget(pilotView); + _buildPilotView(); + centerView = _pilotView; + defaultWidgets = "COMMUNICATION_CONSOLE_DOCKWIDGET,UAS_INFO_INFOVIEW_DOCKWIDGET"; break; + case VIEW_MISSION: - centerStack->setCurrentWidget(plannerView); + _buildPlannerView(); + centerView = _plannerView; + defaultWidgets = "UNMANNED_SYSTEM_LIST_DOCKWIDGET,WAYPOINT_LIST_DOCKWIDGET"; break; + case VIEW_SIMULATION: - centerStack->setCurrentWidget(simView); + _buildSimView(); + centerView = _simView; + defaultWidgets = "UNMANNED_SYSTEM_CONTROL_DOCKWIDGET,WAYPOINT_LIST_DOCKWIDGET,PARAMETER_INTERFACE_DOCKWIDGET,PRIMARY_FLIGHT_DISPLAY_DOCKWIDGET"; break; + case VIEW_TERMINAL: - centerStack->setCurrentWidget(terminalView); + _buildTerminalView(); + centerView = _terminalView; break; + case VIEW_GOOGLEEARTH: - centerStack->setCurrentWidget(googleEarthView); + _buildGoogleEarthView(); + centerView = _googleEarthView; break; + case VIEW_LOCAL3D: - centerStack->setCurrentWidget(local3DView); + _buildLocal3DView(); + centerView = _local3DView; break; + } + + // Remove old view + if (_currentViewWidget) { + _currentViewWidget->setVisible(false); + Q_ASSERT(_centralLayout->count() == 1); + QLayoutItem *child = _centralLayout->takeAt(0); + Q_ASSERT(child); + delete child; + } + + // Add the new one + Q_ASSERT(centerView); + Q_ASSERT(_centralLayout->count() == 0); + _currentViewWidget = centerView; + _centralLayout->addWidget(_currentViewWidget); + _currentViewWidget->setVisible(true); + + // Hide all widgets from previous view + _hideAllDockWidgets(); + + // Restore the widgets for the new view + QString widgetNames = settings.value(getWindowStateKey() + "WIDGETS", defaultWidgets).toString(); + if (!widgetNames.isEmpty()) { + QStringList split = widgetNames.split(","); + foreach (QString widgetName, split) { + Q_ASSERT(!widgetName.isEmpty()); + _showDockWidget(widgetName, true); } } - // Restore the widget positions and size - if (settings.contains(getWindowStateKey() + "WIDGETS")) - { - QString widgetstr = settings.value(getWindowStateKey() + "WIDGETS").toString(); - QStringList split = widgetstr.split(","); - foreach (QString widgetname,split) - { - if (widgetname != "") - { - //qDebug() << "Loading widget:" << widgetname; - loadDockWidget(widgetname); - } - } + if (settings.contains(getWindowStateKey())) { + restoreState(settings.value(getWindowStateKey()).toByteArray()); } - if (settings.contains(getWindowStateKey())) - { - SubMainWindow *win = qobject_cast(centerStack->currentWidget()); - win->restoreState(settings.value(getWindowStateKey()).toByteArray()); + + // HIL dock widget are dynamic and don't take part in the saved window state, so this + // need to happen after we restore state + _showHILConfigurationWidgets(); +} + +void MainWindow::_hideAllHilDockWidgets(void) +{ + foreach(QDockWidget* dockWidget, _mapUasId2HilDockWidget) { + dockWidget->setVisible(false); + } +} + +void MainWindow::_hideAllDockWidgets(void) +{ + foreach(QDockWidget* dockWidget, _mapName2DockWidget) { + dockWidget->setVisible(false); } + + _hideAllHilDockWidgets(); } -void MainWindow::setAdvancedMode(bool isAdvancedMode) + +void MainWindow::_showDockWidgetAction(bool show) { - menuActionHelper->setAdvancedMode(isAdvancedMode); - ui.actionAdvanced_Mode->setChecked(isAdvancedMode); - settings.setValue("ADVANCED_MODE",isAdvancedMode); + QAction* action = dynamic_cast(QObject::sender()); + Q_ASSERT(action); + + _showDockWidget(action->data().toString(), show); } + void MainWindow::handleMisconfiguration(UASInterface* uas) { static QTime lastTime; @@ -1551,88 +1414,88 @@ void MainWindow::handleMisconfiguration(UASInterface* uas) void MainWindow::loadEngineerView() { - if (currentView != VIEW_ENGINEER) + if (_currentView != VIEW_ENGINEER) { - storeViewState(); - currentView = VIEW_ENGINEER; + _storeCurrentViewState(); + _currentView = VIEW_ENGINEER; ui.actionEngineersView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadOperatorView() { - if (currentView != VIEW_MISSION) + if (_currentView != VIEW_MISSION) { - storeViewState(); - currentView = VIEW_MISSION; + _storeCurrentViewState(); + _currentView = VIEW_MISSION; ui.actionMissionView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadSetupView() { - if (currentView != VIEW_SETUP) + if (_currentView != VIEW_SETUP) { - storeViewState(); - currentView = VIEW_SETUP; + _storeCurrentViewState(); + _currentView = VIEW_SETUP; ui.actionSetup->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadTerminalView() { - if (currentView != VIEW_TERMINAL) + if (_currentView != VIEW_TERMINAL) { - storeViewState(); - currentView = VIEW_TERMINAL; + _storeCurrentViewState(); + _currentView = VIEW_TERMINAL; ui.actionTerminalView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadGoogleEarthView() { - if (currentView != VIEW_GOOGLEEARTH) + if (_currentView != VIEW_GOOGLEEARTH) { - storeViewState(); - currentView = VIEW_GOOGLEEARTH; + _storeCurrentViewState(); + _currentView = VIEW_GOOGLEEARTH; ui.actionGoogleEarthView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadLocal3DView() { - if (currentView != VIEW_LOCAL3D) + if (_currentView != VIEW_LOCAL3D) { - storeViewState(); - currentView = VIEW_LOCAL3D; + _storeCurrentViewState(); + _currentView = VIEW_LOCAL3D; ui.actionLocal3DView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadPilotView() { - if (currentView != VIEW_FLIGHT) + if (_currentView != VIEW_FLIGHT) { - storeViewState(); - currentView = VIEW_FLIGHT; + _storeCurrentViewState(); + _currentView = VIEW_FLIGHT; ui.actionFlightView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } void MainWindow::loadSimulationView() { - if (currentView != VIEW_SIMULATION) + if (_currentView != VIEW_SIMULATION) { - storeViewState(); - currentView = VIEW_SIMULATION; + _storeCurrentViewState(); + _currentView = VIEW_SIMULATION; ui.actionSimulationView->setChecked(true); - loadViewState(); + _loadCurrentViewState(); } } @@ -1641,11 +1504,6 @@ QList MainWindow::listLinkMenuActions() return ui.menuNetwork->actions(); } -bool MainWindow::dockWidgetTitleBarsEnabled() const -{ - return menuActionHelper->dockWidgetTitleBarsEnabled(); -} - /// @brief Hides the spash screen if it is currently being shown void MainWindow::hideSplashScreen(void) { diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 0d8a185bb..4662964ab 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -47,7 +47,6 @@ This file is part of the QGROUNDCONTROL project #include "CameraView.h" #include "UASListWidget.h" #include "MAVLinkSimulationLink.h" -#include "submainwindow.h" #include "input/JoystickInput.h" #if (defined QGC_MOUSE_ENABLED_WIN) | (defined QGC_MOUSE_ENABLED_LINUX) #include "Mouse6dofInput.h" @@ -68,6 +67,7 @@ This file is part of the QGROUNDCONTROL project #include "MAVLinkDecoder.h" #include "QGCUASFileViewMulti.h" #include "QGCFlightGearLink.h" +#include "QGCToolWidget.h" class QGCMapTool; class QGCMAVLinkMessageSender; @@ -118,9 +118,6 @@ public: return autoReconnect; } - /** @brief Get title bar mode setting */ - bool dockWidgetTitleBarsEnabled() const; - /** @brief Get low power mode setting */ bool lowPowerModeEnabled() const { @@ -165,8 +162,6 @@ public slots: void stopVideoCapture(); void saveScreen(); - /** @brief Sets advanced mode, allowing for editing of tool widget locations */ - void setAdvancedMode(bool isAdvancedMode); void handleMisconfiguration(UASInterface* uas); /** @brief Load configuration views */ void loadSetupView(); @@ -192,48 +187,20 @@ public slots: /** @brief Show the project roadmap */ void showRoadMap(); - /** @breif Enable title bars on dock widgets when no in advanced mode */ - void enableDockWidgetTitleBars(bool enabled); /** @brief Automatically reconnect last link */ void enableAutoReconnect(bool enabled); /** @brief Save power by reducing update rates */ void enableLowPowerMode(bool enabled) { lowPowerMode = enabled; } - /** @brief Add a custom tool widget */ - void createCustomWidget(); - - /** @brief Load a custom tool widget from a file chosen by user (QGCFileDialog) */ - void loadCustomWidget(); - - /** @brief Load a custom tool widget from a file */ - void loadCustomWidget(const QString& fileName, bool singleinstance=false); - void loadCustomWidget(const QString& fileName, int view); - - /** @brief Load custom widgets from default file */ - void loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType); - - /** @brief Loads and shows the HIL Configuration Widget for the given UAS*/ - void showHILConfigurationWidget(UASInterface *uas); - void closeEvent(QCloseEvent* event); - /** - * @brief Shows a Widget from the center stack based on the action sender - * - * This slot is written to be used in conjunction with the addCentralWidget() function - * It shows the Widget based on the action sender - * - */ - void showCentralWidget(); - /** @brief Update the window name */ void configureWindowName(); void commsWidgetDestroyed(QObject *obj); protected slots: - void showDockWidget(const QString &name, bool show); /** * @brief Unchecks the normalActionItem. * Used as a triggered() callback by the fullScreenAction to make sure only one of it or the @@ -271,54 +238,15 @@ protected: VIEW_MISSION, // Mission/Map/Plan view mode. Used for setting mission waypoints and high-level system commands. VIEW_FLIGHT, // Flight/Fly/Operate view mode. Used for 1st-person observation of the vehicle. VIEW_SIMULATION, // HIL Simulation view. Useful overview of the entire system when doing hardware-in-the-loop simulations. - UNUSED1, // Unused spacer for backwards compatibility with older settings files. VIEW_SETUP, // Setup view. Used for initializing the system for operation. Includes UI for calibration, firmware updating/checking, and parameter modifcation. - UNUSED2, // Unused spacer for backwards compatibility with older settings files. VIEW_TERMINAL, // Terminal interface. Used for communicating with the remote system, usually in a special configuration input mode. VIEW_LOCAL3D, // A local 3D view. Provides a local 3D view that makes visualizing 3D attitude/orientation/pose easy while in operation. VIEW_GOOGLEEARTH // 3D Google Earth view. A 3D terrain view, though the vehicle is still 2D. } VIEW_SECTIONS; - /** - * @brief Adds an already instantiated QDockedWidget to the Tools Menu - * - * This function does all the hosekeeping to have a QDockedWidget added to the - * tools menu and connects the QMenuAction to a slot that shows the widget and - * checks/unchecks the tools menu item - * - * @param widget The QDockWidget being added - * @param title The entry that will appear in the Menu and in the QDockedWidget title bar - * @param location The default location for the QDockedWidget in case there is no previous key in the settings - */ - void addTool(SubMainWindow *parent,VIEW_SECTIONS view,QDockWidget* widget, const QString& title, Qt::DockWidgetArea area); - void loadDockWidget(const QString &name); - - QDockWidget* createDockWidget(QWidget *subMainWindowParent,QWidget *child,const QString& title,const QString& objectname,VIEW_SECTIONS view,Qt::DockWidgetArea area,const QSize& minSize = QSize()); - /** - * @brief Adds an already instantiated QWidget to the center stack - * - * This function does all the hosekeeping to have a QWidget added to the tools menu - * tools menu and connects the QMenuAction to a slot that shows the widget and - * checks/unchecks the tools menu item. This is used for all the central widgets (those in - * the center stack. - * - * @param widget The QWidget being added - * @param title The entry that will appear in the Menu - */ - void addToCentralStackedWidget(QWidget* widget, VIEW_SECTIONS viewSection, const QString& title); - /** @brief Catch window resize events */ void resizeEvent(QResizeEvent * event); - /** @brief Keeps track of the current view */ - VIEW_SECTIONS currentView; - - void storeViewState(); - void loadViewState(); - - void buildCustomWidget(); - void buildCommonWidgets(); - void connectCommonWidgets(); void connectCommonActions(); void loadSettings(); @@ -328,20 +256,8 @@ protected: LinkInterface* udpLink; QSettings settings; - QStackedWidget *centerStack; QActionGroup* centerStackActionGroup; - // Center widgets - QPointer plannerView; - QPointer pilotView; - QPointer setupView; - QPointer softwareConfigView; - QPointer engineeringView; - QPointer simView; - QPointer terminalView; - QPointer googleEarthView; - QPointer local3DView; - // Center widgets QPointer linechartWidget; #ifdef QGC_OSG_ENABLED @@ -352,38 +268,12 @@ protected: #endif QPointer firmwareUpdateWidget; - // Dock widgets - QPointer controlDockWidget; - QPointer controlParameterWidget; - QPointer infoDockWidget; - QPointer cameraDockWidget; - QPointer listDockWidget; - QPointer waypointsDockWidget; - QPointer detectionDockWidget; - QPointer debugConsoleDockWidget; - QPointer parametersDockWidget; - QPointer headDown1DockWidget; - QPointer headDown2DockWidget; - QPointer watchdogControlDockWidget; - - QPointer headUpDockWidget; - QPointer video1DockWidget; - QPointer video2DockWidget; - QPointer rgbd1DockWidget; - QPointer rgbd2DockWidget; - QPointer logPlayerDockWidget; - - QPointer hsiDockWidget; - QPointer rcViewDockWidget; - QPointer hudDockWidget; - QPointer toolBar; QPointer mavlinkInspectorWidget; QPointer mavlinkDecoder; QPointer mavlinkSenderWidget; QGCMAVLinkLogPlayer* logPlayer; - QMap hilDocks; QPointer fileWidget; @@ -416,7 +306,6 @@ protected: QTimer* videoTimer; bool autoReconnect; MAVLinkSimulationLink* simulationLink; - Qt::WindowStates windowStateVal; bool lowPowerMode; ///< If enabled, QGC reduces the update rates of all widgets QGCFlightGearLink* fgLink; QTimer windowNameUpdateTimer; @@ -424,6 +313,9 @@ protected: private slots: void _addLinkMenu(LinkInterface* link); + void _showDockWidgetAction(bool show); + void _loadCustomWidgetFromFile(void); + void _createNewCustomWidget(void); private: /// Constructor is private since all creation should be through MainWindow::_create @@ -431,16 +323,69 @@ private: void _openUrl(const QString& url, const QString& errorMessage); + // Center widgets + QPointer _plannerView; + QPointer _pilotView; + QPointer _setupView; + QPointer _engineeringView; + QPointer _simView; + QPointer _terminalView; + QPointer _googleEarthView; + QPointer _local3DView; + + VIEW_SECTIONS _currentView; ///< Currently displayed view + QWidget* _currentViewWidget; ///< Currently displayed view widget + + // Dock widget names + static const char* _uasControlDockWidgetName; + static const char* _uasListDockWidgetName; + static const char* _waypointsDockWidgetName; + static const char* _mavlinkDockWidgetName; + static const char* _parametersDockWidgetName; + static const char* _filesDockWidgetName; + static const char* _uasStatusDetailsDockWidgetName; + static const char* _mapViewDockWidgetName; + static const char* _hsiDockWidgetName; + static const char* _hdd1DockWidgetName; + static const char* _hdd2DockWidgetName; + static const char* _pfdDockWidgetName; + static const char* _hudDockWidgetName; + static const char* _uasInfoViewDockWidgetName; + static const char* _debugConsoleDockWidgetName; + + QMap _mapName2DockWidget; + QMap _mapUasId2HilDockWidget; + QMap _mapDockWidget2Action; + + void _buildPlannerView(void); + void _buildPilotView(void); + void _buildSetupView(void); + void _buildEngineeringView(void); + void _buildSimView(void); + void _buildTerminalView(void); + void _buildGoogleEarthView(void); + void _buildLocal3DView(void); + + void _storeCurrentViewState(void); + void _loadCurrentViewState(void); + + void _createDockWidget(const QString& title, const QString& name, Qt::DockWidgetArea area, QWidget* innerWidget); + void _createInnerDockWidget(const QString& widgetName); + void _buildCustomWidgets(void); + void _buildCommonWidgets(void); + void _hideAllHilDockWidgets(void); + void _hideAllDockWidgets(void); + void _showDockWidget(const QString &name, bool show); + void _showHILConfigurationWidgets(void); + + QList _customWidgets; + + QVBoxLayout* _centralLayout; + QList commsWidgetList; - QMap customWidgetNameToFilenameMap; MenuActionHelper *menuActionHelper; Ui::MainWindow ui; - /** @brief Set the appropriate titlebar for a given dock widget. - * Relies on the isAdvancedMode and dockWidgetTitleBarEnabled member variables. - */ - void setDockWidgetTitleBar(QDockWidget* widget); - QString getWindowStateKey(); QString getWindowGeometryKey(); diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 4be510fc5..3435f990c 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -62,7 +62,6 @@ - diff --git a/src/ui/menuactionhelper.cpp b/src/ui/menuactionhelper.cpp deleted file mode 100644 index cba136a87..000000000 --- a/src/ui/menuactionhelper.cpp +++ /dev/null @@ -1,178 +0,0 @@ -#include "menuactionhelper.h" - -MenuActionHelper::MenuActionHelper(QObject *parent) : QObject(parent), - m_isAdvancedMode(false), - m_dockWidgetTitleBarsEnabled(true), - m_addedCustomSeperator(false) -{ -} - -QAction *MenuActionHelper::createToolAction(const QString &title, const QString &name) -{ - QAction *action = m_menuToDockNameMap.key(name); //For sanity, check that the action is not NULL - if(action) { - qWarning() << "createToolAction was called for action" << name << "which already exists in the menu"; - return action; - } - - action = new QAction(title, NULL); - action->setCheckable(true); - connect(action,SIGNAL(triggered(bool)),this,SLOT(showTool(bool))); - m_menuToDockNameMap[action] = name; - m_menu->addAction(action); - return action; -} - -void MenuActionHelper::removeDockWidget() -{ - // Do not dynamic cast or de-reference QObject, since object is either in destructor or may have already - // been destroyed. - - QObject *dockWidget = QObject::sender(); - Q_ASSERT(dockWidget); - - //qDebug() << "Dockwidget:" << dockWidget->objectName() << "of type" << dockWidget->metaObject()->className(); - - QAction *action = m_menuToDockNameMap.key(dockWidget->objectName()); - if(action) { - m_menuToDockNameMap.remove(action); - action->deleteLater(); - } - QMap >::iterator it; - for (it = m_centralWidgetToDockWidgetsMap.begin(); it != m_centralWidgetToDockWidgetsMap.end(); ++it) { - QMap::iterator it2 = it.value().begin(); - while( it2 != it.value().end()) { - if(it2.value() == dockWidget) - it2 = it.value().erase(it2); - else - ++it2; - } - } - //Don't delete the dockWidget because this could have been called from the dockWidget destructor - m_dockWidgets.removeAll(static_cast(dockWidget)); -} - -QAction *MenuActionHelper::createToolActionForCustomDockWidget(const QString &title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view) { - bool found = false; - QAction *action = NULL; - foreach(QAction *act, m_menuToDockNameMap.keys()) { - if(act->text() == title) { - found = true; - action = act; - } - } - - if(!found) - action = createToolAction(title, name); - else - m_menuToDockNameMap[action] = name; - - m_centralWidgetToDockWidgetsMap[view][name] = dockWidget; - connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget()),Qt::UniqueConnection); //Use UniqueConnection since we might have already created this connection in createDockWidget - connect(dockWidget, SIGNAL(visibilityChanged(bool)), action, SLOT(setChecked(bool))); - action->setChecked(dockWidget->isVisible()); - return action; -} - -QDockWidget* MenuActionHelper::createDockWidget(const QString& title,const QString& name) -{ - QDockWidget *dockWidget = new QDockWidget(title); - m_dockWidgets.append(dockWidget); - setDockWidgetTitleBar(dockWidget); - dockWidget->setObjectName(name); - connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget())); - - return dockWidget; -} - -bool MenuActionHelper::containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { - - return m_centralWidgetToDockWidgetsMap.contains(view) && m_centralWidgetToDockWidgetsMap[view].contains(name); -} - -QDockWidget *MenuActionHelper::getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const { - if(!m_centralWidgetToDockWidgetsMap.contains(view)) - return NULL; - return m_centralWidgetToDockWidgetsMap[view].value(name); -} - -void MenuActionHelper::showTool(bool show) { - //Called when a menu item is clicked on, regardless of view. - QAction* act = qobject_cast(sender()); - Q_ASSERT(act); - if (m_menuToDockNameMap.contains(act)) { - QString name = m_menuToDockNameMap[act]; - emit needToShowDockWidget(name, show); - } -} - -void MenuActionHelper::setDockWidgetTitleBarsEnabled(bool enabled) -{ - m_dockWidgetTitleBarsEnabled = enabled; - for (int i = 0; i < m_dockWidgets.size(); i++) - setDockWidgetTitleBar(m_dockWidgets[i]); -} - - -void MenuActionHelper::setAdvancedMode(bool advancedMode) -{ - m_isAdvancedMode = advancedMode; - for (int i = 0; i < m_dockWidgets.size(); i++) - setDockWidgetTitleBar(m_dockWidgets[i]); -} - -void MenuActionHelper::setDockWidgetTitleBar(QDockWidget* widget) -{ - Q_ASSERT(widget); - QWidget* oldTitleBar = widget->titleBarWidget(); - - // In advanced mode, we use the default titlebar provided by Qt. - if (m_isAdvancedMode) - { - widget->setTitleBarWidget(0); - } - // Otherwise, if just a textlabel should be shown, make that the titlebar. - else if (m_dockWidgetTitleBarsEnabled) - { - QLabel* label = new QLabel(widget); - label->setText(widget->windowTitle()); - label->installEventFilter(this); //Ignore mouse clicks - widget->installEventFilter(this); //Update label if window title changes. See eventFilter below - widget->setTitleBarWidget(label); - } - // And if nothing should be shown, use an empty widget. - else - { - QWidget* newTitleBar = new QWidget(widget); - widget->setTitleBarWidget(newTitleBar); - } - - // Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(), - // it doesn't delete the old titlebar object. - delete oldTitleBar; -} - -bool MenuActionHelper::eventFilter(QObject *object,QEvent *event) -{ - if (event->type() == QEvent::WindowTitleChange) - { - QDockWidget *dock = qobject_cast(object); - if(dock) { - // Update the dock title bar label - QLabel *label = dynamic_cast(dock->titleBarWidget()); - if(label) - label->setText(dock->windowTitle()); - // Now update the action label - QString oldObjectName = dock->objectName(); - QAction *action = m_menuToDockNameMap.key(oldObjectName); - if(action) - action->setText(dock->windowTitle()); - //Now modify the object name - it is a strange naming scheme.. - } - } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) - { - if(qobject_cast(object)) - return true; - } - return QObject::eventFilter(object,event); -} diff --git a/src/ui/menuactionhelper.h b/src/ui/menuactionhelper.h deleted file mode 100644 index 26c6c5a9e..000000000 --- a/src/ui/menuactionhelper.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef MENUACTIONHELPER_H -#define MENUACTIONHELPER_H - -#include "MainWindow.h" -#include - -class MenuActionHelper : public QObject -{ - Q_OBJECT -public: - MenuActionHelper(QObject *parent = NULL); - ~MenuActionHelper() {} - - /** @brief Get title bar mode setting */ - bool dockWidgetTitleBarsEnabled() const { return m_dockWidgetTitleBarsEnabled; } - void setDockWidgetTitleBarsEnabled(bool enabled); - bool isAdvancedMode() const { return m_isAdvancedMode; } - void setAdvancedMode(bool advancedMode); - QAction *createToolAction(const QString &title, const QString &name = QString()); - QAction *createToolActionForCustomDockWidget(const QString& title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view); - QDockWidget *createDockWidget(const QString& title, const QString& name); - bool containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; - QDockWidget *getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const; - - /** QMenu to add QActions to */ - void setMenu(QMenu *menu) { m_menu = menu; } - -protected: - virtual bool eventFilter(QObject *object,QEvent *event); - -private slots: - void removeDockWidget(); - /** @brief Shows a Docked Widget based on the action sender */ - void showTool(bool show); - -signals: - void needToShowDockWidget(const QString& name, bool show); -private: - QMap m_menuToDockNameMap; - QList m_dockWidgets; - QMap > m_centralWidgetToDockWidgetsMap; - bool m_isAdvancedMode; ///< If enabled dock widgets can be moved and floated. - bool m_dockWidgetTitleBarsEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode. - QMenu *m_menu; ///< \see setMenu() - bool m_addedCustomSeperator; ///< Whether we have added a seperator between the actions and the custom actions - - void setDockWidgetTitleBar(QDockWidget* widget); - -}; - -#endif // MENUACTIONHELPER_H diff --git a/src/ui/submainwindow.cpp b/src/ui/submainwindow.cpp deleted file mode 100644 index 7705cff16..000000000 --- a/src/ui/submainwindow.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "submainwindow.h" - -SubMainWindow::SubMainWindow(QWidget *parent) : QMainWindow(parent) -{ - -} diff --git a/src/ui/submainwindow.h b/src/ui/submainwindow.h deleted file mode 100644 index 510acf473..000000000 --- a/src/ui/submainwindow.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef SUBMAINWINDOW_H -#define SUBMAINWINDOW_H - -#include - -class SubMainWindow : public QMainWindow -{ - Q_OBJECT -public: - explicit SubMainWindow(QWidget *parent = 0); -signals: - -public slots: - -}; - -#endif // SUBMAINWINDOW_H -- 2.22.0