Commit 4d40f298 authored by Don Gagne's avatar Don Gagne

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
parent 78507bfe
......@@ -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
......
......@@ -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"
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#include "QGCDockWidget.h"
#include <QCloseEvent>
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);
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
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 <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef QGCDockWidget_h
#define QGCDockWidget_h
#include <QDockWidget>
/// @file
/// @brief Subclass of QDockWidget so we can intercept the closeEvent.
///
/// @author Don Gagne <don@thegagnes.com>
class QGCDockWidget : public QDockWidget {
Q_OBJECT
public:
QGCDockWidget(const QString& title, QWidget *parent = 0, Qt::WindowFlags flags = 0);
void closeEvent(QCloseEvent* event);
};
#endif
......@@ -28,7 +28,6 @@ This file is part of the QGROUNDCONTROL project
*/
#include <QSettings>
#include <QDockWidget>
#include <QNetworkInterface>
#include <QDebug>
#include <QTimer>
......@@ -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<QDockWidget*>(*i);
if (dockWidget)
{
// Remove dock widget from main window
// removeDockWidget(dockWidget);
// delete dockWidget->widget();
delete dockWidget;
dockWidget = NULL;
}
else if (dynamic_cast<QWidget*>(*i))
{
delete dynamic_cast<QWidget*>(*i);
*i = NULL;
}
}
// Delete all UAS objects
delete menuActionHelper;
for (int i=0;i<commsWidgetList.size();i++)
{
commsWidgetList[i]->deleteLater();
......@@ -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<QGCToolWidget*> 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<QDockWidget*>(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; i<cDockWidgetInfo; i++) {
const struct DockWidgetInfo* pDockInfo = &rgDockWidgetInfo[i];
_createDockWidget(pDockInfo->title, 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<SubMainWindow*>(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*>(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<QAction *>(sender());
QWidget* widget = act->data().value<QWidget *>();
centerStack->setCurrentWidget(widget);
ui.actionNormal->setChecked(false);
}
void MainWindow::showHILConfigurationWidget(UASInterface* uas)
void MainWindow::normalActionItemCallback()
{
// Add simulation configuration widget
UAS* mav = dynamic_cast<UAS*>(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<SubMainWindow*>(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<SubMainWindow*>(centerStack->currentWidget());
QList<QDockWidget*> widgets = win->findChildren<QDockWidget*>();
QString widgetnames = "";
for (int i=0;i<widgets.size();i++)
{
widgetnames += widgets[i]->objectName() + ",";
// 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<SubMainWindow*>(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<QAction*>(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<QAction*> 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)
{
......
......@@ -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<SubMainWindow> plannerView;
QPointer<SubMainWindow> pilotView;
QPointer<SubMainWindow> setupView;
QPointer<SubMainWindow> softwareConfigView;
QPointer<SubMainWindow> engineeringView;
QPointer<SubMainWindow> simView;
QPointer<SubMainWindow> terminalView;
QPointer<SubMainWindow> googleEarthView;
QPointer<SubMainWindow> local3DView;
// Center widgets
QPointer<Linecharts> linechartWidget;
#ifdef QGC_OSG_ENABLED
......@@ -352,38 +268,12 @@ protected:
#endif
QPointer<QGCFirmwareUpdate> firmwareUpdateWidget;
// Dock widgets
QPointer<QDockWidget> controlDockWidget;
QPointer<QDockWidget> controlParameterWidget;
QPointer<QDockWidget> infoDockWidget;
QPointer<QDockWidget> cameraDockWidget;
QPointer<QDockWidget> listDockWidget;
QPointer<QDockWidget> waypointsDockWidget;
QPointer<QDockWidget> detectionDockWidget;
QPointer<QDockWidget> debugConsoleDockWidget;
QPointer<QDockWidget> parametersDockWidget;
QPointer<QDockWidget> headDown1DockWidget;
QPointer<QDockWidget> headDown2DockWidget;
QPointer<QDockWidget> watchdogControlDockWidget;
QPointer<QDockWidget> headUpDockWidget;
QPointer<QDockWidget> video1DockWidget;
QPointer<QDockWidget> video2DockWidget;
QPointer<QDockWidget> rgbd1DockWidget;
QPointer<QDockWidget> rgbd2DockWidget;
QPointer<QDockWidget> logPlayerDockWidget;
QPointer<QDockWidget> hsiDockWidget;
QPointer<QDockWidget> rcViewDockWidget;
QPointer<QDockWidget> hudDockWidget;
QPointer<QGCToolBar> toolBar;
QPointer<QDockWidget> mavlinkInspectorWidget;
QPointer<MAVLinkDecoder> mavlinkDecoder;
QPointer<QDockWidget> mavlinkSenderWidget;
QGCMAVLinkLogPlayer* logPlayer;
QMap<int, QDockWidget*> hilDocks;
QPointer<QGCUASFileViewMulti> 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<QWidget> _plannerView;
QPointer<QWidget> _pilotView;
QPointer<QWidget> _setupView;
QPointer<QWidget> _engineeringView;
QPointer<QWidget> _simView;
QPointer<QWidget> _terminalView;
QPointer<QWidget> _googleEarthView;
QPointer<QWidget> _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<QString, QDockWidget*> _mapName2DockWidget;
QMap<int, QDockWidget*> _mapUasId2HilDockWidget;
QMap<QDockWidget*, QAction*> _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<QGCToolWidget*> _customWidgets;
QVBoxLayout* _centralLayout;
QList<QObject*> commsWidgetList;
QMap<QString,QString> 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();
......
......@@ -62,7 +62,6 @@
<addaction name="separator"/>
<addaction name="actionMuteAudioOutput"/>
<addaction name="actionSettings"/>
<addaction name="actionAdvanced_Mode"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
......
#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<MainWindow::VIEW_SECTIONS,QMap<QString,QDockWidget*> >::iterator it;
for (it = m_centralWidgetToDockWidgetsMap.begin(); it != m_centralWidgetToDockWidgetsMap.end(); ++it) {
QMap<QString,QDockWidget*>::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<QDockWidget*>(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<QAction *>(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<QDockWidget *>(object);
if(dock) {
// Update the dock title bar label
QLabel *label = dynamic_cast<QLabel *>(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<QLabel *>(object))
return true;
}
return QObject::eventFilter(object,event);
}
#ifndef MENUACTIONHELPER_H
#define MENUACTIONHELPER_H
#include "MainWindow.h"
#include <QDockWidget>
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<QAction*,QString > m_menuToDockNameMap;
QList<QDockWidget*> m_dockWidgets;
QMap<MainWindow::VIEW_SECTIONS,QMap<QString,QDockWidget*> > 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
#include "submainwindow.h"
SubMainWindow::SubMainWindow(QWidget *parent) : QMainWindow(parent)
{
}
#ifndef SUBMAINWINDOW_H
#define SUBMAINWINDOW_H
#include <QMainWindow>
class SubMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SubMainWindow(QWidget *parent = 0);
signals:
public slots:
};
#endif // SUBMAINWINDOW_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment