diff --git a/files/pixhawk/hexarotor/widgets/mavconn.qgw b/files/pixhawk/hexarotor/widgets/mavconn.qgw deleted file mode 100644 index ff33f37..0000000 --- a/files/pixhawk/hexarotor/widgets/mavconn.qgw +++ /dev/null @@ -1,62 +0,0 @@ -[MAVCONN%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_DESCRIPTION=DO: Control Video -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_BUTTONTEXT=CAPTURE -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_COMMANDID=200 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM4=2 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_DESCRIPTION=DO: Control Video -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_BUTTONTEXT=STOP -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_COMMANDID=200 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_DESCRIPTION=PREFLIGHT: Calibration -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_BUTTONTEXT=CALIBRATE -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\4\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_DESCRIPTION=Setpoint ON<->OFF -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_PARAMID= -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_COMPONENTID=0 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MIN=1 -QGC_TOOL_WIDGET_ITEMS\4\QGC_PARAM_SLIDER_MAX=0 -QGC_TOOL_WIDGET_ITEMS\5\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_DESCRIPTION=Glob. Loc ON<->OFF -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_PARAMID= -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_COMPONENTID=0 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MIN=1 -QGC_TOOL_WIDGET_ITEMS\5\QGC_PARAM_SLIDER_MAX=0 -QGC_TOOL_WIDGET_ITEMS\6\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_DESCRIPTION=GPS ENU HL<->ASL -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_PARAMID= -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_COMPONENTID=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\6\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\7\TYPE=SLIDER -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_DESCRIPTION=Yaw PX<->ASL -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_PARAMID= -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_COMPONENTID=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MIN=0 -QGC_TOOL_WIDGET_ITEMS\7\QGC_PARAM_SLIDER_MAX=1 -QGC_TOOL_WIDGET_ITEMS\size=7 diff --git a/files/pixhawk/quadrotor/parameter_tooltips/tooltips.txt b/files/pixhawk/quadrotor/parameter_tooltips/tooltips.txt deleted file mode 100644 index 6108736..0000000 --- a/files/pixhawk/quadrotor/parameter_tooltips/tooltips.txt +++ /dev/null @@ -1,3 +0,0 @@ -EEPROM,variable name,Min,Max,Default,Multiplier,Enabled (0 = no, 1 = yes),Comment -HDNG2RLL_P, 0, 5, 0.7, 1, 1, NAV_ROLL_P - Navigation control gains. Tuning values for the navigation control PID loops. The P term is the primary tuning value. This determines how the control deflection varies in proportion to the required correction. -SYS_TYPE, 0, 15, 1, 1, 1, System type (airframe) \ No newline at end of file diff --git a/files/pixhawk/quadrotor/widgets/mavconn.qgw b/files/pixhawk/quadrotor/widgets/mavconn.qgw deleted file mode 100644 index e7b6e64..0000000 --- a/files/pixhawk/quadrotor/widgets/mavconn.qgw +++ /dev/null @@ -1,38 +0,0 @@ -[MAVCONN%20Control] -QGC_TOOL_WIDGET_ITEMS\1\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_DESCRIPTION=START Recording -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_BUTTONTEXT=CAPTURE -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_COMMANDID=200 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM4=2 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\1\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\2\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_DESCRIPTION=STOP Recording -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_BUTTONTEXT=STOP -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_COMMANDID=200 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM1=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\2\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\3\TYPE=COMMANDBUTTON -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_DESCRIPTION=PREFLIGHT: Calibration -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_BUTTONTEXT=CALIBRATE -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_COMMANDID=241 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAMS_VISIBLE=false -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM1=1 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM2=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM3=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM4=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM5=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM6=0 -QGC_TOOL_WIDGET_ITEMS\3\QGC_COMMAND_BUTTON_PARAM7=0 -QGC_TOOL_WIDGET_ITEMS\size=3 diff --git a/files/px4/parameter_tooltips/tooltips.txt b/files/px4/parameter_tooltips/tooltips.txt deleted file mode 100644 index 854f5a0..0000000 --- a/files/px4/parameter_tooltips/tooltips.txt +++ /dev/null @@ -1,11 +0,0 @@ -^ Name ^ Min ^ Max ^ Default ^ Multiplier ^ Enabled ^ Comment ^ -| BAT_V_EMPTY | 0.9 | 100.0 | 3.2 | 1 | 1 | Voltage of an empty battery cell | -| BAT_V_FULL | 1.0 | 200.0 | 4.05 | 1 | 1 | Voltage of a full battery cell | -| BAT_N_CELLS | 1 | 100 | 3 | 1 | 1 | Number of SERIAL battery cells. Typically this ranges from 2S to 6S in small-scale UAVs | -| BAT_V_SCALING | 0.001 | 1.0 | 0.00838 | 1 | 1 | Conversion from ADC ticks to battery voltage. Depends on the connected board, calibrate with a multimeter. | -| MC_ATTRATE_P | 0.0 | 20.0 | 0.20 | 1 | 1 | Multirotor attitude rate control P gain. This gain controls how much of the motor thrust should be used to control angular velocity. A larger number will increase the control response, but will make the system also more twitchy. | -| MC_ATTRATE_D | 0.0 | 20.0 | 0.05 | 1 | 1 | Multirotor attitude rate control D gain. A large value will allow to damp oscillations due to a high P gain, but will make the system response suspectible to noise.| -| MC_ATT_P | 0.0 | 20.0 | 0.20 | 1 | 1 | Multirotor attitude control proportional (P) gain. This defines how strong the response of the system will be to an attitude error| -| MC_ATT_D | 0.0 | 20.0 | 0.05 | 1 | 1 | Multirotor attitude control D gain. A large value will allow to damp oscillations due to a high P gain, but will make the system response suspectible to noise.| -| FW_ROLLRATE_P | 0.0 | 20.0 | 0.30 | 1 | 1 | Fixed wing roll rate control P gain. This gain controls how strong the ailerons or rudder should be actuated in order to achieve a certain roll rate. A larger number will increase the control response, but will make the system also more twitchy. | -| FW_HEADING_P | 0.0 | 20.0 | 4.00 | 1 | 1 | Fixed wing heading error to bank angle gain | \ No newline at end of file diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index cb4e270..9c43027 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -452,7 +452,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 \ @@ -481,7 +480,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 \ @@ -497,7 +495,8 @@ HEADERS += \ src/QGCPalette.h \ src/QGCQmlWidgetHolder.h \ src/ui/QGCParamTreeWidget.h \ - src/ui/QGCMapRCToParamDialog.h + src/ui/QGCMapRCToParamDialog.h \ + src/QGCDockWidget.h \ SOURCES += \ src/main.cc \ @@ -598,7 +597,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 \ @@ -627,7 +625,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 \ @@ -640,7 +637,8 @@ SOURCES += \ src/QGCPalette.cc \ src/QGCQmlWidgetHolder.cpp \ src/ui/QGCParamTreeWidget.cpp \ - src/ui/QGCMapRCToParamDialog.cpp + src/ui/QGCMapRCToParamDialog.cpp \ + src/QGCDockWidget.cc \ # # Unit Test specific configuration goes here diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index 7c1a602..cdc054d 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -476,15 +476,12 @@ void QGCApplication::criticalMessageBoxOnMainThread(const QString& title, const void QGCApplication::saveTempFlightDataLogOnMainThread(QString tempLogfile) { - QString defaultSuffix("mavlink"); QString saveFilename = QGCFileDialog::getSaveFileName( MainWindow::instance(), - tr("Select file to save Flight Data Log"), + tr("Save Flight Data Log"), qgcApp()->mavlinkLogFilesLocation(), tr("Flight Data Log (*.mavlink)"), - 0,0, - &defaultSuffix, - true); + "mavlink"); if (!saveFilename.isEmpty()) { QFile::copy(tempLogfile, saveFilename); } diff --git a/src/QGCConfig.h b/src/QGCConfig.h index fad5b72..a119bc8 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 0000000..b087abb --- /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 0000000..ffc2fb1 --- /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/QGCFileDialog.cc b/src/QGCFileDialog.cc index 285cf5e..3f48704 100644 --- a/src/QGCFileDialog.cc +++ b/src/QGCFileDialog.cc @@ -35,7 +35,7 @@ QString QGCFileDialog::getExistingDirectory( const QString& dir, Options options) { - _validate(NULL, options); + _validate(options); #ifdef QT_DEBUG if (qgcApp()->runningUnitTests()) { @@ -52,18 +52,17 @@ QString QGCFileDialog::getOpenFileName( const QString& caption, const QString& dir, const QString& filter, - QString* selectedFilter, Options options) { - _validate(selectedFilter, options); + _validate(options); #ifdef QT_DEBUG if (qgcApp()->runningUnitTests()) { - return UnitTest::_getOpenFileName(parent, caption, dir, filter, selectedFilter, options); + return UnitTest::_getOpenFileName(parent, caption, dir, filter, options); } else #endif { - return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); + return QFileDialog::getOpenFileName(parent, caption, dir, filter, NULL, options); } } @@ -72,49 +71,49 @@ QStringList QGCFileDialog::getOpenFileNames( const QString& caption, const QString& dir, const QString& filter, - QString* selectedFilter, Options options) { - _validate(selectedFilter, options); + _validate(options); #ifdef QT_DEBUG if (qgcApp()->runningUnitTests()) { - return UnitTest::_getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); + return UnitTest::_getOpenFileNames(parent, caption, dir, filter, options); } else #endif { - return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); + return QFileDialog::getOpenFileNames(parent, caption, dir, filter, NULL, options); } } -QString QGCFileDialog::getSaveFileName(QWidget* parent, +QString QGCFileDialog::getSaveFileName( + QWidget* parent, const QString& caption, const QString& dir, const QString& filter, - QString* selectedFilter, - Options options, - QString* defaultSuffix, - bool strict) + const QString& defaultSuffix, + bool strict, + Options options) { - _validate(selectedFilter, options); + _validate(options); #ifdef QT_DEBUG if (qgcApp()->runningUnitTests()) { - return UnitTest::_getSaveFileName(parent, caption, dir, filter, selectedFilter, options, defaultSuffix); + return UnitTest::_getSaveFileName(parent, caption, dir, filter, defaultSuffix, options); } else #endif { + QString defaultSuffixCopy(defaultSuffix); QFileDialog dlg(parent, caption, dir, filter); dlg.setAcceptMode(QFileDialog::AcceptSave); if (options) { dlg.setOptions(options); } - if (defaultSuffix) { + if (!defaultSuffixCopy.isEmpty()) { //-- Make sure dot is not present - if (defaultSuffix->startsWith(".")) { - defaultSuffix->remove(0,1); + if (defaultSuffixCopy.startsWith(".")) { + defaultSuffixCopy.remove(0,1); } - dlg.setDefaultSuffix(*defaultSuffix); + dlg.setDefaultSuffix(defaultSuffixCopy); } while (true) { if (dlg.exec()) { @@ -131,16 +130,15 @@ QString QGCFileDialog::getSaveFileName(QWidget* parent, return result; } //-- Do we have a default extension? - QString localDefaultSuffix; - if (!defaultSuffix) { + if (defaultSuffixCopy.isEmpty()) { //-- We don't, so get the first one in the filter - localDefaultSuffix = _getFirstExtensionInFilter(filter); - defaultSuffix = &localDefaultSuffix; + defaultSuffixCopy = _getFirstExtensionInFilter(filter); } - Q_ASSERT(defaultSuffix->isEmpty() == false); + //-- If this is set to strict, we have to have a default extension + Q_ASSERT(defaultSuffixCopy.isEmpty() == false); //-- Forcefully append our desired extension result += "."; - result += *defaultSuffix; + result += defaultSuffixCopy; //-- Check and see if this new file already exists fi.setFile(result); if (fi.exists()) { @@ -203,17 +201,13 @@ QString QGCFileDialog::_getFirstExtensionInFilter(const QString& filter) { } /// @brief Validates and updates the parameters for the file dialog calls -void QGCFileDialog::_validate(QString* selectedFilter, Options& options) +void QGCFileDialog::_validate(Options& options) { // You can't use QGCFileDialog if QGCApplication is not created yet. Q_ASSERT(qgcApp()); Q_ASSERT_X(QThread::currentThread() == qgcApp()->thread(), "Threading issue", "QGCFileDialog can only be called from main thread"); - // Support for selectedFilter is not yet implemented through the unit test framework - Q_UNUSED(selectedFilter); - Q_ASSERT(selectedFilter == NULL); - // On OSX native dialog can hang so we always use Qt dialogs options |= DontUseNativeDialog; diff --git a/src/QGCFileDialog.h b/src/QGCFileDialog.h index a55c923..b88cf16 100644 --- a/src/QGCFileDialog.h +++ b/src/QGCFileDialog.h @@ -31,10 +31,21 @@ /// @author Don Gagne /*! - Subclass of QFileDialog which re-implements the static public functions. The reason for this - is that the QFileDialog implementations of these use the native os dialogs. On OSX these - these can intermittently hang. So instead here we use the native dialogs. It also allows - use to catch these dialogs for unit testing. + Subclass of QFileDialog which re-implements the static public functions. The reason for this + is that the QFileDialog implementations of these use the native os dialogs. On OSX these + these can intermittently hang. So instead here we use the native dialogs. It also allows + use to catch these dialogs for unit testing. + @remark If you need to know what type of file was returned by these functions, you can use something like: + @code{.cpp} + QString filename = QGCFileDialog::getSaveFileName(this, tr("Save File"), "~/", "Foo files (*.foo);;All Files (*.*)", "foo"); + if (!filename.isEmpty()) { + QFileInfo fi(filename); + QString fileExtension(fi.suffix()); + if (fileExtension == QString("foo")) { + // do something + } + } + @endcode */ class QGCFileDialog : public QFileDialog { @@ -62,7 +73,6 @@ public: @param[in] caption The caption displayed at the top of the dialog. @param[in] dir The initial directory shown to the user. @param[in] filter The filter used for selecting the file type. - @param[out] selectedFilter **NOT IMPLEMENTED - Set to NULL** Returns the filter that the user selected in the file dialog. @param[in] options Set the various options that affect the look and feel of the dialog. @return The full path and filename to be opened or \c QString("") if none. @sa QFileDialog::getOpenFileName() @@ -72,7 +82,6 @@ public: const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), - QString* selectedFilter = 0, Options options = 0); //! Static helper that invokes a File Open dialog where the user can select one or more files to be opened. @@ -81,7 +90,6 @@ public: @param[in] caption The caption displayed at the top of the dialog. @param[in] dir The initial directory shown to the user. @param[in] filter The filter used for selecting the file type. - @param[out] selectedFilter **NOT IMPLEMENTED - Set to NULL** Returns the filter that the user selected in the file dialog. @param[in] options Set the various options that affect the look and feel of the dialog. @return A QStringList object containing zero or more files to be opened. @sa QFileDialog::getOpenFileNames() @@ -91,7 +99,6 @@ public: const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), - QString* selectedFilter = 0, Options options = 0); //! Static helper that invokes a File Save dialog where the user can select a directory and enter a filename to be saved. @@ -100,10 +107,9 @@ public: @param[in] caption The caption displayed at the top of the dialog. @param[in] dir The initial directory shown to the user. @param[in] filter The filter used for selecting the file type. - @param[out] selectedFilter **NOT IMPLEMENTED - Set to NULL** Returns the filter that the user selected in the file dialog. - @param[in] options Set the various options that affect the look and feel of the dialog. @param[in] defaultSuffix Specifies a string that will be added to the filename if it has no suffix already. The suffix is typically used to indicate the file type (e.g. "txt" indicates a text file). @param[in] strict Makes the default suffix mandatory. Only files with those extensions will be allowed. + @param[in] options Set the various options that affect the look and feel of the dialog. @return The full path and filename to be used to save the file or \c QString("") if none. @sa QFileDialog::getSaveFileName() @remark If a default suffix is given, it will be appended to the filename if the user does not enter one themselves. That is, if the user simply enters \e foo and the default suffix is set to \e bar, @@ -114,18 +120,17 @@ public: const QString& caption = QString(), const QString& dir = QString(), const QString& filter = QString(), - QString* selectedFilter = 0, - Options options = 0, - QString* defaultSuffix = 0, - bool strict = false); - + const QString& defaultSuffix = QString(), + bool strict = false, + Options options = 0); + private slots: - /// @brief The exec slot is private becasue when only want QGCFileDialog users to use the static methods. Otherwise it will break - /// unit testing. + /// @brief The exec slot is private because we only want QGCFileDialog users to use the static methods. Otherwise it will break + /// unit testing. int exec(void) { return QGCFileDialog::exec(); } private: - static void _validate(QString* selectedFilter, Options& options); + static void _validate(Options& options); static bool _validateExtension(const QString& filter, const QString& extension); static QString _getFirstExtensionInFilter(const QString& filter); }; diff --git a/src/VehicleSetup/SetupView.cc b/src/VehicleSetup/SetupView.cc index c1ec110..d48af88 100644 --- a/src/VehicleSetup/SetupView.cc +++ b/src/VehicleSetup/SetupView.cc @@ -51,7 +51,7 @@ SetupView::SetupView(QWidget* parent) : setResizeMode(SizeRootObjectToView); - _setActiveUAS(NULL); + _setActiveUAS(UASManager::instance()->getActiveUAS()); } SetupView::~SetupView() @@ -120,7 +120,7 @@ void SetupView::_setConnectedView(void) void SetupView::_firmwareButtonClicked(void) { - if (_uasCurrent->isArmed()) { + if (_uasCurrent && _uasCurrent->isArmed()) { QGCMessageBox::warning("Setup", "Firmware Update cannot be performed while vehicle is armed."); return; } diff --git a/src/qgcunittest/UnitTest.cc b/src/qgcunittest/UnitTest.cc index eaa1646..4a403c1 100644 --- a/src/qgcunittest/UnitTest.cc +++ b/src/qgcunittest/UnitTest.cc @@ -273,10 +273,11 @@ QString UnitTest::_fileDialogResponseSingle(enum FileDialogType type) return retFile; } -QString UnitTest::_getExistingDirectory(QWidget* parent, - const QString& caption, - const QString& dir, - QFileDialog::Options options) +QString UnitTest::_getExistingDirectory( + QWidget* parent, + const QString& caption, + const QString& dir, + QFileDialog::Options options) { Q_UNUSED(parent); Q_UNUSED(caption); @@ -286,12 +287,12 @@ QString UnitTest::_getExistingDirectory(QWidget* parent, return _fileDialogResponseSingle(getExistingDirectory); } -QString UnitTest::_getOpenFileName(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options) +QString UnitTest::_getOpenFileName( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + QFileDialog::Options options) { Q_UNUSED(parent); Q_UNUSED(caption); @@ -299,18 +300,15 @@ QString UnitTest::_getOpenFileName(QWidget* parent, Q_UNUSED(filter); Q_UNUSED(options); - // Support for selectedFilter is not yet implemented - Q_ASSERT(selectedFilter == NULL); - return _fileDialogResponseSingle(getOpenFileName); } -QStringList UnitTest::_getOpenFileNames(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options) +QStringList UnitTest::_getOpenFileNames( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + QFileDialog::Options options) { Q_UNUSED(parent); Q_UNUSED(caption); @@ -318,9 +316,6 @@ QStringList UnitTest::_getOpenFileNames(QWidget* parent, Q_UNUSED(filter); Q_UNUSED(options); - // Support for selectedFilter is not yet implemented - Q_ASSERT(selectedFilter == NULL); - QStringList retFiles; if (!_fileDialogResponseSet || _fileDialogExpectedType != getOpenFileNames) { @@ -340,13 +335,13 @@ QStringList UnitTest::_getOpenFileNames(QWidget* parent, return retFiles; } -QString UnitTest::_getSaveFileName(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options, - QString* defaultSuffix) +QString UnitTest::_getSaveFileName( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + const QString& defaultSuffix, + QFileDialog::Options options) { Q_UNUSED(parent); Q_UNUSED(caption); @@ -354,11 +349,9 @@ QString UnitTest::_getSaveFileName(QWidget* parent, Q_UNUSED(filter); Q_UNUSED(options); - if(defaultSuffix) - Q_ASSERT(defaultSuffix->startsWith(".") == false); - - // Support for selectedFilter is not yet implemented - Q_ASSERT(selectedFilter == NULL); + if(!defaultSuffix.isEmpty()) { + Q_ASSERT(defaultSuffix.startsWith(".") == false); + } return _fileDialogResponseSingle(getSaveFileName); } diff --git a/src/qgcunittest/UnitTest.h b/src/qgcunittest/UnitTest.h index 44e39ea..bbc78ac 100644 --- a/src/qgcunittest/UnitTest.h +++ b/src/qgcunittest/UnitTest.h @@ -118,33 +118,34 @@ private: // When the app is running in unit test mode the QGCFileDialog methods are re-routed here. - static QString _getExistingDirectory(QWidget* parent, - const QString& caption, - const QString& dir, - QFileDialog::Options options); - - static QString _getOpenFileName(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options); - - static QStringList _getOpenFileNames(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options); - - static QString _getSaveFileName(QWidget* parent, - const QString& caption, - const QString& dir, - const QString& filter, - QString* selectedFilter, - QFileDialog::Options options, - QString* defaultSuffix); - + static QString _getExistingDirectory( + QWidget* parent, + const QString& caption, + const QString& dir, + QFileDialog::Options options); + + static QString _getOpenFileName( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + QFileDialog::Options options); + + static QStringList _getOpenFileNames( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + QFileDialog::Options options); + + static QString _getSaveFileName( + QWidget* parent, + const QString& caption, + const QString& dir, + const QString& filter, + const QString& defaultSuffix, + QFileDialog::Options options); + static QString _fileDialogResponseSingle(enum FileDialogType type); // This allows the private calls to the file dialog methods diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index ce0f311..53f9aa3 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) @@ -106,12 +121,12 @@ void MainWindow::deleteInstance(void) /// by MainWindow::_create method. Hence no other code should have access to /// constructor. MainWindow::MainWindow(QSplashScreen* splashScreen) : - currentView(VIEW_FLIGHT), centerStackActionGroup(new QActionGroup(this)), autoReconnect(false), simulationLink(NULL), lowPowerMode(false), - menuActionHelper(new MenuActionHelper()), + _currentView(VIEW_FLIGHT), + _currentViewWidget(NULL), _splashScreen(splashScreen) { Q_ASSERT(_instance == NULL); @@ -121,52 +136,42 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) : 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); @@ -185,10 +190,6 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) : // Setup UI state machines centerStackActionGroup->setExclusive(true); - centerStack = new QStackedWidget(this); - setCentralWidget(centerStack); - - // Load Toolbar toolBar = new QGCToolBar(this); this->addToolBar(toolBar); @@ -214,8 +215,7 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) : 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)); @@ -266,13 +266,10 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) : // 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 @@ -362,31 +359,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(); @@ -404,10 +377,10 @@ QString MainWindow::getWindowStateKey() { if (UASManager::instance()->getActiveUAS()) { - return QString::number(currentView)+"_windowstate_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName(); + return QString::number(_currentView)+"_windowstate_" + UASManager::instance()->getActiveUAS()->getAutopilotTypeName(); } else - return QString::number(currentView)+"_windowstate_"; + return QString::number(_currentView)+"_windowstate_"; } QString MainWindow::getWindowGeometryKey() @@ -415,64 +388,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); @@ -483,274 +453,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) @@ -789,25 +731,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()) { @@ -825,112 +755,27 @@ 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(); -} - -void MainWindow::loadCustomWidget() -{ - 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; - } + tool->resize(100, 100); + _createDockWidget(title, objectName, Qt::BottomDockWidgetArea, tool); + + _mapName2DockWidget[objectName]->setVisible(true); } -void MainWindow::loadCustomWidgetsFromDefaults(const QString& systemType, const QString& autopilotType) +void MainWindow::_loadCustomWidgetFromFile(void) { - 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); + QString fileName = QGCFileDialog::getOpenFileName( + this, tr("Load Widget File"), + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + tr("QGroundControl Widget (*.qgw);;All Files (*)")); + if (!fileName.isEmpty()) { + 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); } } + // TODO Add error dialog if widget could not be loaded } void MainWindow::loadSettings() @@ -940,10 +785,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() @@ -958,13 +800,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); @@ -996,16 +838,16 @@ void MainWindow::configureWindowName() void MainWindow::startVideoCapture() { + // TODO: What is this? What kind of "Video" is saved to bmp? QString format("bmp"); QString initialPath = QDir::currentPath() + tr("/untitled.") + format; QString screenFileName = QGCFileDialog::getSaveFileName( - this, tr("Save As"), + this, tr("Save Video Capture"), initialPath, tr("%1 Files (*.%2);;All Files (*)") .arg(format.toUpper()) .arg(format), - 0,0, - &format); + format); delete videoTimer; videoTimer = new QTimer(this); } @@ -1027,14 +869,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) { @@ -1068,42 +902,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); @@ -1118,8 +952,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*))); @@ -1148,8 +980,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()); @@ -1299,8 +1131,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()); } } @@ -1313,10 +1144,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); @@ -1387,31 +1214,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) @@ -1420,104 +1243,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 = NULL; + 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; @@ -1548,88 +1413,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(); } } @@ -1638,11 +1503,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 e11b300..b10ea3f 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; @@ -110,9 +110,6 @@ public: return autoReconnect; } - /** @brief Get title bar mode setting */ - bool dockWidgetTitleBarsEnabled() const; - /** @brief Get low power mode setting */ bool lowPowerModeEnabled() const { @@ -144,8 +141,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(); @@ -171,48 +166,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 @@ -250,54 +217,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(); @@ -307,21 +235,9 @@ 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 QPointer q3DWidget; @@ -331,38 +247,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; @@ -395,13 +285,15 @@ 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; 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 @@ -409,16 +301,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 4be510f..3435f99 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -62,7 +62,6 @@ - diff --git a/src/ui/QGCBaseParamWidget.cc b/src/ui/QGCBaseParamWidget.cc index 2b89db9..76c4f2a 100644 --- a/src/ui/QGCBaseParamWidget.cc +++ b/src/ui/QGCBaseParamWidget.cc @@ -105,17 +105,11 @@ void QGCBaseParamWidget::saveParametersToFile() { if (!mav) return; - QString defaultSuffix("params"); QString fileName = QGCFileDialog::getSaveFileName( - this, - tr("Save Parameters"), - qgcApp()->savedParameterFilesLocation(), - tr("Parameter File (*.params)"), - 0, 0, - &defaultSuffix, - true); + this, tr("Save Parameters"), qgcApp()->savedParameterFilesLocation(), tr("Parameter File (*.params)"), "params", true); if (!fileName.isEmpty()) { QFile file(fileName); + // TODO Display error message to the user if the file can't be created if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return; } @@ -130,15 +124,15 @@ void QGCBaseParamWidget::loadParametersFromFile() { if (!mav) return; - - QString fileName = QGCFileDialog::getOpenFileName(this, tr("Load File"), qgcApp()->savedParameterFilesLocation(), tr("Parameter file (*.params)")); + QString fileName = QGCFileDialog::getOpenFileName( + this, tr("Load Parameters"), qgcApp()->savedParameterFilesLocation(), + tr("Parameter file (*.params);;All Files (*)")); QFile file(fileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) + // TODO Display error message to the user if the file can't be opened + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; - + } QTextStream in(&file); paramMgr->readPendingParamsFromStream(in); file.close(); } - - diff --git a/src/ui/QGCDataPlot2D.cc b/src/ui/QGCDataPlot2D.cc index 952fa0e..f443eef 100644 --- a/src/ui/QGCDataPlot2D.cc +++ b/src/ui/QGCDataPlot2D.cc @@ -100,13 +100,17 @@ void QGCDataPlot2D::loadFile() void QGCDataPlot2D::loadFile(QString file) { + // TODO This "filename" is a private/protected member variable. It should be named in such way + // it indicates so. This same name is used in several places within this file in local scopes. fileName = file; - if (QFileInfo(fileName).isReadable()) { - if (fileName.contains(".raw") || fileName.contains(".imu")) { + QFileInfo fi(fileName); + if (fi.isReadable()) { + if (fi.suffix() == QString("raw") || fi.suffix() == QString("imu")) { loadRawLog(fileName); - } else if (fileName.contains(".txt") || fileName.contains(".csv") || fileName.contains(".csv")) { + } else if (fi.suffix() == QString("txt") || fi.suffix() == QString("csv")) { loadCsvLog(fileName); } + // TODO Else, tell the user it doesn't know what to do with the file... } } @@ -115,12 +119,10 @@ void QGCDataPlot2D::loadFile(QString file) */ QString QGCDataPlot2D::getSavePlotFilename() { - QString defaultSuffix("pdf"); QString fileName = QGCFileDialog::getSaveFileName( - this, "Export File Name", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + this, "Save Plot File", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), "PDF Documents (*.pdf);;SVG Images (*.svg)", - 0,0, - &defaultSuffix); + "pdf"); return fileName; } @@ -133,11 +135,13 @@ void QGCDataPlot2D::savePlot() if (fileName.isEmpty()) return; + // TODO This will change once we add "strict" file types in file selection dialogs while(!(fileName.endsWith(".svg") || fileName.endsWith(".pdf"))) { - QMessageBox::StandardButton button = QGCMessageBox::critical(tr("Unsuitable file extension for PDF or SVG"), - tr("Please choose .pdf or .svg as file extension. Click OK to change the file extension, cancel to not save the file."), - QMessageBox::Ok | QMessageBox::Cancel, - QMessageBox::Ok); + QMessageBox::StandardButton button = QGCMessageBox::warning( + tr("Unsuitable file extension for Plot document type."), + tr("Please choose .pdf or .svg as file extension. Click OK to change the file extension, cancel to not save the file."), + QMessageBox::Ok | QMessageBox::Cancel, + QMessageBox::Ok); // Abort if cancelled if (button == QMessageBox::Cancel) { return; @@ -264,16 +268,16 @@ void QGCDataPlot2D::selectFile() // Open a file dialog prompting the user for the file to load. // Note the special case for the Pixhawk. if (ui->inputFileType->currentText().contains("pxIMU") || ui->inputFileType->currentText().contains("RAW")) { - fileName = QGCFileDialog::getOpenFileName(this, tr("Specify log file name"), QString(), "Logfile (*.imu *.raw)"); + fileName = QGCFileDialog::getOpenFileName(this, tr("Load Log File"), QString(), "Log files (*.imu *.raw)"); } else { - fileName = QGCFileDialog::getOpenFileName(this, tr("Specify log file name"), QString(), "Logfile (*.csv *.txt *.log)"); + fileName = QGCFileDialog::getOpenFileName(this, tr("Load Log File"), QString(), "Log files (*.csv *.txt *.log)"); } - // Check if the user hit cancel, which results in a Null string. + // Check if the user hit cancel, which results in an empty string. // If this is the case, we just stop. - if (fileName.isNull()) + if (fileName.isEmpty()) { return; } @@ -282,9 +286,11 @@ void QGCDataPlot2D::selectFile() QFileInfo fileInfo(fileName); if (!fileInfo.isReadable()) { - QGCMessageBox::critical(tr("Could not open file"), - tr("The file is owned by user %1. Is the file currently used by another program?").arg(fileInfo.owner())); - ui->filenameLabel->setText(tr("Could not open %1").arg(fileInfo.baseName()+"."+fileInfo.completeSuffix())); + // TODO This needs some TLC. File used by another program sounds like a Windows only issue. + QGCMessageBox::critical( + tr("Could not open file"), + tr("The file is owned by user %1. Is the file currently used by another program?").arg(fileInfo.owner())); + ui->filenameLabel->setText(tr("Could not open %1").arg(fileInfo.fileName())); } else { @@ -690,12 +696,10 @@ bool QGCDataPlot2D::linearRegression(double *x, double *y, int n, double *a, dou void QGCDataPlot2D::saveCsvLog() { - QString defaultSuffix("csv"); QString fileName = QGCFileDialog::getSaveFileName( - this, "Export CSV File Name", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + this, "Save CSV Log File", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), "CSV file (*.csv);;Text file (*.txt)", - 0,0, - &defaultSuffix); + "csv"); if (fileName.isEmpty()) return; //User cancelled diff --git a/src/ui/QGCMAVLinkLogPlayer.cc b/src/ui/QGCMAVLinkLogPlayer.cc index f26ee69..39a2960 100644 --- a/src/ui/QGCMAVLinkLogPlayer.cc +++ b/src/ui/QGCMAVLinkLogPlayer.cc @@ -262,11 +262,12 @@ void QGCMAVLinkLogPlayer::_selectLogFileForPlayback(void) return; } - QString logFile = QGCFileDialog::getOpenFileName(this, - tr("Specify MAVLink log file name to replay"), - qgcApp()->mavlinkLogFilesLocation(), - tr("MAVLink or Binary Logfile (*.mavlink *.bin *.log)")); - + QString logFile = QGCFileDialog::getOpenFileName( + this, + tr("Load MAVLink Log File"), + qgcApp()->mavlinkLogFilesLocation(), + tr("MAVLink or Binary Logfile (*.mavlink *.bin *.log);;All Files (*)")); + if (!logFile.isEmpty()) { loadLogFile(logFile); } diff --git a/src/ui/QGCUASFileView.ui b/src/ui/QGCUASFileView.ui index b7e4ce7..1ac6fd1 100644 --- a/src/ui/QGCUASFileView.ui +++ b/src/ui/QGCUASFileView.ui @@ -6,7 +6,7 @@ 0 0 - 414 + 200 518 diff --git a/src/ui/QGCUASFileViewMulti.ui b/src/ui/QGCUASFileViewMulti.ui index 169c00a..547cfd4 100644 --- a/src/ui/QGCUASFileViewMulti.ui +++ b/src/ui/QGCUASFileViewMulti.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 200 300 diff --git a/src/ui/SettingsDialog.cc b/src/ui/SettingsDialog.cc index baddd51..194bb90 100644 --- a/src/ui/SettingsDialog.cc +++ b/src/ui/SettingsDialog.cc @@ -70,10 +70,6 @@ _ui(new Ui::SettingsDialog) _ui->lowPowerCheckBox->setChecked(_mainWindow->lowPowerModeEnabled()); connect(_ui->lowPowerCheckBox, SIGNAL(clicked(bool)), _mainWindow, SLOT(enableLowPowerMode(bool))); - // Dock widget title bars - _ui->titleBarCheckBox->setChecked(_mainWindow->dockWidgetTitleBarsEnabled()); - connect(_ui->titleBarCheckBox,SIGNAL(clicked(bool)),_mainWindow,SLOT(enableDockWidgetTitleBars(bool))); - connect(_ui->deleteSettings, &QAbstractButton::toggled, this, &SettingsDialog::_deleteSettingsToggled); // Application color style diff --git a/src/ui/SettingsDialog.ui b/src/ui/SettingsDialog.ui index 0aa80a3..fef2722 100644 --- a/src/ui/SettingsDialog.ui +++ b/src/ui/SettingsDialog.ui @@ -63,16 +63,6 @@ - - - Show Docked Widget title bars when NOT in advanced Mode. - - - false - - - - Prompt to save Flight Data Log after each flight diff --git a/src/ui/WaypointList.cc b/src/ui/WaypointList.cc index f962a69..8632ecc 100644 --- a/src/ui/WaypointList.cc +++ b/src/ui/WaypointList.cc @@ -217,14 +217,15 @@ void WaypointList::setUAS(UASInterface* uas) void WaypointList::saveWaypoints() { - QString defaultSuffix("waypoints"); - QString fileName = QGCFileDialog::getSaveFileName(this, tr("Save File"), "./unnamed.waypoints", tr("Waypoint File (*.waypoints)"), 0, 0, &defaultSuffix); + // TODO Need better default directory + QString fileName = QGCFileDialog::getSaveFileName(this, tr("Save Waypoint File"), "./untitled.waypoints", tr("Waypoint File (*.waypoints)"), "waypoints", true); WPM->saveWaypoints(fileName); } void WaypointList::loadWaypoints() { - QString fileName = QGCFileDialog::getOpenFileName(this, tr("Load File"), ".", tr("Waypoint File (*.waypoints)")); + // TODO Need better default directory + QString fileName = QGCFileDialog::getOpenFileName(this, tr("Load Waypoint File"), ".", tr("Waypoint File (*.waypoints);;All Files (*)")); WPM->loadWaypoints(fileName); } diff --git a/src/ui/designer/QGCToolWidget.cc b/src/ui/designer/QGCToolWidget.cc index 7cc942e..d81a20f 100644 --- a/src/ui/designer/QGCToolWidget.cc +++ b/src/ui/designer/QGCToolWidget.cc @@ -571,29 +571,29 @@ void QGCToolWidget::widgetRemoved() void QGCToolWidget::exportWidget() { - QString defaultSuffix("qgw"); - const QString widgetFileExtension(".qgw"); + //-- Get file to save QString fileName = QGCFileDialog::getSaveFileName( - this, tr("Specify File Name"), + this, tr("Save Widget File"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), - tr("QGroundControl Widget (*%1)").arg(widgetFileExtension), - 0,0, - &defaultSuffix, + tr("QGroundControl Widget (*.qgw)"), + "qgw", true); - //-- Note that if the user enters foo.bar, this will end up foo.bar.qgw - if (!fileName.endsWith(widgetFileExtension)) - { - fileName = fileName.append(widgetFileExtension); + //-- Save it if we have it + if (!fileName.isEmpty()) { + QSettings settings(fileName, QSettings::IniFormat); + storeSettings(settings); } - QSettings settings(fileName, QSettings::IniFormat); - storeSettings(settings); } void QGCToolWidget::importWidget() { - const QString widgetFileExtension(".qgw"); - QString fileName = QGCFileDialog::getOpenFileName(this, tr("Specify File Name"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr("QGroundControl Widget (*%1)").arg(widgetFileExtension)); - loadSettings(fileName); + QString fileName = QGCFileDialog::getOpenFileName( + this, tr("Load Widget File"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + tr("QGroundControl Widget (*.qgw);;All Files (*)")); + if (!fileName.isEmpty()) { + // TODO There is no error checking. If the load fails, there is nothing telling the user what happened. + loadSettings(fileName); + } } QString QGCToolWidget::getTitle() const diff --git a/src/ui/linechart/LinechartWidget.cc b/src/ui/linechart/LinechartWidget.cc index 02a5887..372e284 100644 --- a/src/ui/linechart/LinechartWidget.cc +++ b/src/ui/linechart/LinechartWidget.cc @@ -433,13 +433,11 @@ void LinechartWidget::refresh() QString LinechartWidget::getLogSaveFilename() { - QString defaultSuffix("log"); QString fileName = QGCFileDialog::getSaveFileName(this, - tr("Specify log file name"), + tr("Save Log File"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), - tr("Logfile (*.log)"), - 0,0, - &defaultSuffix, + tr("Log file (*.log)"), + "log", true); return fileName; } diff --git a/src/ui/map3D/Pixhawk3DWidget.cc b/src/ui/map3D/Pixhawk3DWidget.cc index 04e1070..d62377c 100644 --- a/src/ui/map3D/Pixhawk3DWidget.cc +++ b/src/ui/map3D/Pixhawk3DWidget.cc @@ -587,11 +587,12 @@ Pixhawk3DWidget::setBirdEyeView(void) void Pixhawk3DWidget::loadTerrainModel(void) { - QString filename = QGCFileDialog::getOpenFileName(this, "Load Terrain Model", - QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), - tr("Collada (*.dae)")); + QString filename = QGCFileDialog::getOpenFileName( + this, "Load Terrain Model", + QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), + tr("Collada (*.dae)")); - if (filename.isNull()) + if (filename.isEmpty()) { return; } diff --git a/src/ui/map3D/Q3DWidget.cc b/src/ui/map3D/Q3DWidget.cc index 82341f0..2d2c9e1 100644 --- a/src/ui/map3D/Q3DWidget.cc +++ b/src/ui/map3D/Q3DWidget.cc @@ -354,6 +354,7 @@ void Q3DWidget::redraw(void) { emit update(); + emit updateWidget(); #if (QGC_EVENTLOOP_DEBUG) qDebug() << "EVENTLOOP:" << __FILE__ << __LINE__; #endif diff --git a/src/ui/menuactionhelper.cpp b/src/ui/menuactionhelper.cpp deleted file mode 100644 index cba136a..0000000 --- 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 26c6c5a..0000000 --- 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/px4_configuration/PX4FirmwareUpgrade.cc b/src/ui/px4_configuration/PX4FirmwareUpgrade.cc index 1db5191..7a5726c 100644 --- a/src/ui/px4_configuration/PX4FirmwareUpgrade.cc +++ b/src/ui/px4_configuration/PX4FirmwareUpgrade.cc @@ -476,11 +476,11 @@ void PX4FirmwareUpgrade::_getFirmwareFile(void) _firmwareFilename = _ui->firmwareCombo->itemData(index).toString(); Q_ASSERT(!_firmwareFilename.isEmpty()); if (_firmwareFilename == "selectfile") { - _firmwareFilename = QGCFileDialog::getOpenFileName(this, - tr("Select Firmware File"), // Dialog title - QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory - tr("Firmware Files (*.px4 *.bin)")); // File filter - + _firmwareFilename = QGCFileDialog::getOpenFileName( + this, + tr("Load Firmware File"), // Dialog Caption + QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation), // Initial directory + tr("Firmware Files (*.px4 *.bin)")); // File filter } if (!_firmwareFilename.isEmpty()) { _downloadFirmware(); @@ -821,4 +821,4 @@ void PX4FirmwareUpgrade::_eraseProgressTick(void) { _eraseTickCount++; _ui->progressBar->setValue((_eraseTickCount*_eraseTickMsec*100) / _eraseTotalMsec); -} \ No newline at end of file +} diff --git a/src/ui/submainwindow.cpp b/src/ui/submainwindow.cpp deleted file mode 100644 index 7705cff..0000000 --- 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 510acf4..0000000 --- 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 diff --git a/src/ui/uas/UASView.cc b/src/ui/uas/UASView.cc index ab86b31..507272e 100644 --- a/src/ui/uas/UASView.cc +++ b/src/ui/uas/UASView.cc @@ -118,7 +118,6 @@ UASView::UASView(UASInterface* uas, QWidget *parent) : connect(removeAction, SIGNAL(triggered()), this, SLOT(triggerUASDeletion())); connect(renameAction, SIGNAL(triggered()), this, SLOT(rename())); connect(selectAction, SIGNAL(triggered()), uas, SLOT(setSelected())); - connect(hilAction, SIGNAL(triggered(bool)), this, SLOT(showHILUi())); connect(selectAirframeAction, SIGNAL(triggered()), this, SLOT(selectAirframe())); connect(setBatterySpecsAction, SIGNAL(triggered()), this, SLOT(setBatterySpecs())); @@ -553,11 +552,6 @@ void UASView::selectAirframe() } } -void UASView::showHILUi() -{ - MainWindow::instance()->showHILConfigurationWidget(uas); -} - void UASView::triggerUASDeletion() { refreshTimer->stop(); diff --git a/src/ui/uas/UASView.h b/src/ui/uas/UASView.h index c536d5b..4510aca 100644 --- a/src/ui/uas/UASView.h +++ b/src/ui/uas/UASView.h @@ -65,7 +65,6 @@ public slots: void updateMode(int sysId, QString status, QString description); void updateLoad(UASInterface* uas, double load); //void receiveValue(int uasid, QString id, double value, quint64 time); - void showHILUi(); /** * Request that the UASManager deletes this UAS. This doesn't delete this widget * yet, it waits for the approprait uasDeleted signal.