diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc deleted file mode 100644 index 6dc0e56f9521c91ba66d1e2f54aa96ce59d8a40f..0000000000000000000000000000000000000000 --- a/src/ui/MainWindow.cc +++ /dev/null @@ -1,518 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2016 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -/** - * @file - * @brief Implementation of class MainWindow - * @author Lorenz Meier - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "QGC.h" -#include "MAVLinkProtocol.h" -#include "MainWindow.h" -#include "AudioOutput.h" -#ifndef __mobile__ -#include "QGCMAVLinkLogPlayer.h" -#endif -#include "MAVLinkDecoder.h" -#include "QGCApplication.h" -#include "MultiVehicleManager.h" -#include "LogCompressor.h" -#include "UAS.h" -#include "QGCImageProvider.h" -#include "QGCCorePlugin.h" - -#ifndef __mobile__ -#include "Linecharts.h" -#include "QGCUASFileViewMulti.h" -#include "CustomCommandWidget.h" -#include "QGCDockWidget.h" -#include "HILDockWidget.h" -#include "AppMessages.h" -#endif - -#ifndef NO_SERIAL_LINK -#include "SerialLink.h" -#endif - -#ifdef UNITTEST_BUILD -#include "QmlControls/QmlTestWidget.h" -#endif - -/// The key under which the Main Window settings are saved -const char* MAIN_SETTINGS_GROUP = "QGC_MAINWINDOW"; - -#ifndef __mobile__ -enum DockWidgetTypes { - MAVLINK_INSPECTOR, - CUSTOM_COMMAND, - ONBOARD_FILES, - HIL_CONFIG, - ANALYZE -}; - -static const char *rgDockWidgetNames[] = { - "MAVLink Inspector", - "Custom Command", - "Onboard Files", - "HIL Config", - "Analyze" -}; - -#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0])) - -static const char* _visibleWidgetsKey = "VisibleWidgets"; -#endif - -static MainWindow* _instance = nullptr; ///< @brief MainWindow singleton - -MainWindow* MainWindow::_create() -{ - new MainWindow(); - return _instance; -} - -MainWindow* MainWindow::instance(void) -{ - return _instance; -} - -void MainWindow::deleteInstance(void) -{ - delete this; -} - -/// @brief Private constructor for MainWindow. MainWindow singleton is only ever created -/// by MainWindow::_create method. Hence no other code should have access to -/// constructor. -MainWindow::MainWindow() - : _mavlinkDecoder (nullptr) - , _lowPowerMode (false) - , _showStatusBar (false) - , _mainQmlWidgetHolder (nullptr) - , _forceClose (false) -{ - _instance = this; - - //-- Load fonts - if(QFontDatabase::addApplicationFont(":/fonts/opensans") < 0) { - qWarning() << "Could not load /fonts/opensans font"; - } - if(QFontDatabase::addApplicationFont(":/fonts/opensans-demibold") < 0) { - qWarning() << "Could not load /fonts/opensans-demibold font"; - } - - // Qt 4/5 on Ubuntu does place the native menubar correctly so on Linux we revert back to in-window menu bar. -#ifdef Q_OS_LINUX - menuBar()->setNativeMenuBar(false); -#endif - // Setup user interface - loadSettings(); - emit initStatusChanged(tr("Setting up user interface"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - - _ui.setupUi(this); - configureWindowName(); - - // Setup central widget with a layout to hold the views - _centralLayout = new QVBoxLayout(); - _centralLayout->setContentsMargins(0, 0, 0, 0); - centralWidget()->setLayout(_centralLayout); - - //-- Allow plugin to initialize main QML Widget - _mainQmlWidgetHolder = qgcApp()->toolbox()->corePlugin()->createMainQmlWidgetHolder(_centralLayout, this); - - // Image provider - QQuickImageProvider* pImgProvider = dynamic_cast(qgcApp()->toolbox()->imageProvider()); - _mainQmlWidgetHolder->getEngine()->addImageProvider(QStringLiteral("QGCImages"), pImgProvider); - - // Set dock options - setDockOptions(nullptr); - // Setup corners - setCorner(Qt::BottomRightCorner, Qt::BottomDockWidgetArea); - - // On Mobile devices, we don't want any main menus at all. -#ifdef __mobile__ - menuBar()->setNativeMenuBar(false); -#endif - -#ifdef UNITTEST_BUILD - QAction* qmlTestAction = new QAction("Test QML palette and controls", nullptr); - connect(qmlTestAction, &QAction::triggered, this, &MainWindow::_showQmlTestWidget); - _ui.menuWidgets->addAction(qmlTestAction); -#endif - - connect(qgcApp()->toolbox()->corePlugin(), &QGCCorePlugin::showAdvancedUIChanged, this, &MainWindow::_showAdvancedUIChanged); - _showAdvancedUIChanged(qgcApp()->toolbox()->corePlugin()->showAdvancedUI()); - - // Status Bar - setStatusBar(new QStatusBar(this)); - statusBar()->setSizeGripEnabled(true); - -#ifndef __mobile__ - emit initStatusChanged(tr("Building common widgets."), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - _buildCommonWidgets(); - emit initStatusChanged(tr("Building common actions"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); -#endif - - // Create actions - connectCommonActions(); - - // Set low power mode - enableLowPowerMode(_lowPowerMode); - emit initStatusChanged(tr("Restoring last view state"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - -#ifndef __mobile__ - - // Restore the window position and size - emit initStatusChanged(tr("Restoring last window size"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - if (settings.contains(_getWindowGeometryKey())) - { - restoreGeometry(settings.value(_getWindowGeometryKey()).toByteArray()); - } - else - { - // Adjust the size - QScreen* scr = QApplication::primaryScreen(); - QSize scrSize = scr->availableSize(); - if (scrSize.width() <= 1280) - { - resize(scrSize.width(), scrSize.height()); - } - else - { - int w = scrSize.width() > 1600 ? 1600 : scrSize.width(); - int h = scrSize.height() > 800 ? 800 : scrSize.height(); - resize(w, h); - move((scrSize.width() - w) / 2, (scrSize.height() - h) / 2); - } - } -#endif - - connect(_ui.actionStatusBar, &QAction::triggered, this, &MainWindow::showStatusBarCallback); - - connect(&windowNameUpdateTimer, &QTimer::timeout, this, &MainWindow::configureWindowName); - windowNameUpdateTimer.start(15000); - emit initStatusChanged(tr("Done"), Qt::AlignLeft | Qt::AlignBottom, QColor(62, 93, 141)); - - if (!qgcApp()->runningUnitTests()) { - _ui.actionStatusBar->setChecked(_showStatusBar); - showStatusBarCallback(_showStatusBar); -#ifdef __mobile__ - menuBar()->hide(); -#endif - show(); - } - -#ifndef __mobile__ - _loadVisibleWidgetsSettings(); -#endif - //-- Enable message handler display of messages in main window - UASMessageHandler* msgHandler = qgcApp()->toolbox()->uasMessageHandler(); - if(msgHandler) { - msgHandler->showErrorsInToolbar(); - } -} - -MainWindow::~MainWindow() -{ - if (_mavlinkDecoder) { - // Enforce thread-safe shutdown of the mavlink decoder - _mavlinkDecoder->finish(); - _mavlinkDecoder->wait(1000); - _mavlinkDecoder->deleteLater(); - _mavlinkDecoder = nullptr; - } - - // This needs to happen before we get into the QWidget dtor - // otherwise the QML engine reads freed data and tries to - // destroy MainWindow a second time. - delete _mainQmlWidgetHolder; - _instance = nullptr; -} - -QString MainWindow::_getWindowGeometryKey() -{ - return "_geometry"; -} - -#ifndef __mobile__ -MAVLinkDecoder* MainWindow::_mavLinkDecoderInstance(void) -{ - if (!_mavlinkDecoder) { - _mavlinkDecoder = new MAVLinkDecoder(qgcApp()->toolbox()->mavlinkProtocol()); - connect(_mavlinkDecoder, &MAVLinkDecoder::valueChanged, this, &MainWindow::valueChanged); - } - - return _mavlinkDecoder; -} - -void MainWindow::_buildCommonWidgets(void) -{ - // Log player - // TODO: Make this optional with a preferences setting or under a "View" menu - logPlayer = new QGCMAVLinkLogPlayer(statusBar()); - statusBar()->addPermanentWidget(logPlayer, 1); - - // Populate widget menu - for (int i = 0, end = ARRAY_SIZE(rgDockWidgetNames); i < end; i++) { - - const char* pDockWidgetName = rgDockWidgetNames[i]; - - // Add to menu - QAction* action = new QAction(pDockWidgetName, this); - action->setCheckable(true); - action->setData(i); - connect(action, &QAction::triggered, this, &MainWindow::_showDockWidgetAction); - _ui.menuWidgets->addAction(action); - _mapName2Action[pDockWidgetName] = action; - } -} - -/// Shows or hides the specified dock widget, creating if necessary -void MainWindow::_showDockWidget(const QString& name, bool show) -{ - // Create the inner widget if we need to - if (!_mapName2DockWidget.contains(name)) { - if(!_createInnerDockWidget(name)) { - qWarning() << "Trying to load non existent widget:" << name; - return; - } - } - Q_ASSERT(_mapName2DockWidget.contains(name)); - QGCDockWidget* dockWidget = _mapName2DockWidget[name]; - Q_ASSERT(dockWidget); - dockWidget->setVisible(show); - Q_ASSERT(_mapName2Action.contains(name)); - _mapName2Action[name]->setChecked(show); -} - -/// Creates the specified inner dock widget and adds to the QDockWidget -bool MainWindow::_createInnerDockWidget(const QString& widgetName) -{ - QGCDockWidget* widget = nullptr; - QAction *action = _mapName2Action[widgetName]; - if(action) { - switch(action->data().toInt()) { - case MAVLINK_INSPECTOR: - widget = new QGCMAVLinkInspector(widgetName, action, qgcApp()->toolbox()->mavlinkProtocol(),this); - break; - case CUSTOM_COMMAND: - widget = new CustomCommandWidget(widgetName, action, this); - break; - case ONBOARD_FILES: - widget = new QGCUASFileViewMulti(widgetName, action, this); - break; - case HIL_CONFIG: - widget = new HILDockWidget(widgetName, action, this); - break; - case ANALYZE: - widget = new Linecharts(widgetName, action, _mavLinkDecoderInstance(), this); - break; - } - if(widget) { - _mapName2DockWidget[widgetName] = widget; - } - } - return widget != nullptr; -} - -void MainWindow::_hideAllDockWidgets(void) -{ - for(QGCDockWidget* dockWidget: _mapName2DockWidget) { - dockWidget->setVisible(false); - } -} - -void MainWindow::_showDockWidgetAction(bool show) -{ - QAction* action = qobject_cast(QObject::sender()); - Q_ASSERT(action); - _showDockWidget(rgDockWidgetNames[action->data().toInt()], show); -} -#endif - -void MainWindow::showStatusBarCallback(bool checked) -{ - _showStatusBar = checked; - checked ? statusBar()->show() : statusBar()->hide(); -} - -void MainWindow::_reallyClose(void) -{ - _forceClose = true; - close(); -} - -void MainWindow::closeEvent(QCloseEvent *event) -{ - if (!_forceClose) { - // Attempt close from within the root Qml item - qgcApp()->qmlAttemptWindowClose(); - event->ignore(); - return; - } - - // Should not be any active connections - if (qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()) { - qWarning() << "All links should be disconnected by now"; - } - - _storeCurrentViewState(); - storeSettings(); - - emit mainWindowClosed(); -} - -void MainWindow::loadSettings() -{ - // Why the screaming? - QSettings settings; - settings.beginGroup(MAIN_SETTINGS_GROUP); - _lowPowerMode = settings.value("LOW_POWER_MODE", _lowPowerMode).toBool(); - _showStatusBar = settings.value("SHOW_STATUSBAR", _showStatusBar).toBool(); - settings.endGroup(); -} - -void MainWindow::storeSettings() -{ - QSettings settings; - settings.beginGroup(MAIN_SETTINGS_GROUP); - settings.setValue("LOW_POWER_MODE", _lowPowerMode); - settings.setValue("SHOW_STATUSBAR", _showStatusBar); - settings.endGroup(); - settings.setValue(_getWindowGeometryKey(), saveGeometry()); - -#ifndef __mobile__ - _storeVisibleWidgetsSettings(); -#endif -} - -void MainWindow::configureWindowName() -{ - setWindowTitle(qApp->applicationName() + " " + qApp->applicationVersion()); -} - -/** -* @brief Create all actions associated to the main window -* -**/ -void MainWindow::connectCommonActions() -{ - // Connect internal actions - connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &MainWindow::_vehicleAdded); - connect(this, &MainWindow::reallyClose, this, &MainWindow::_reallyClose, Qt::QueuedConnection); // Queued to allow closeEvent to fully unwind before _reallyClose is called -} - -void MainWindow::_openUrl(const QString& url, const QString& errorMessage) -{ - if(!QDesktopServices::openUrl(QUrl(url))) { - qgcApp()->showMessage(QString("Could not open information in browser: %1").arg(errorMessage)); - } -} - -void MainWindow::_vehicleAdded(Vehicle* vehicle) -{ - connect(vehicle->uas(), &UAS::valueChanged, this, &MainWindow::valueChanged); -} - -/// Stores the state of the toolbar, status bar and widgets associated with the current view -void MainWindow::_storeCurrentViewState(void) -{ -#ifndef __mobile__ - for(QGCDockWidget* dockWidget: _mapName2DockWidget) { - dockWidget->saveSettings(); - } -#endif - - settings.setValue(_getWindowGeometryKey(), saveGeometry()); -} - -/// @brief Saves the last used connection -void MainWindow::saveLastUsedConnection(const QString connection) -{ - QSettings settings; - QString key(MAIN_SETTINGS_GROUP); - key += "/LAST_CONNECTION"; - settings.setValue(key, connection); -} - -#ifdef UNITTEST_BUILD -void MainWindow::_showQmlTestWidget(void) -{ - new QmlTestWidget(); -} -#endif - -#ifndef __mobile__ -void MainWindow::_loadVisibleWidgetsSettings(void) -{ - QSettings settings; - - QString widgets = settings.value(_visibleWidgetsKey).toString(); - - if (!widgets.isEmpty()) { - QStringList nameList = widgets.split(","); - - for (const QString &name: nameList) { - _showDockWidget(name, true); - } - } -} - -void MainWindow::_storeVisibleWidgetsSettings(void) -{ - QString widgetNames; - bool firstWidget = true; - - for (const QString &name: _mapName2DockWidget.keys()) { - if (_mapName2DockWidget[name]->isVisible()) { - if (!firstWidget) { - widgetNames += ","; - } else { - firstWidget = false; - } - - widgetNames += name; - } - } - - QSettings settings; - - settings.setValue(_visibleWidgetsKey, widgetNames); -} -#endif - -QObject* MainWindow::rootQmlObject(void) -{ - return _mainQmlWidgetHolder ? _mainQmlWidgetHolder->getRootObject() : nullptr; -} - -void MainWindow::_showAdvancedUIChanged(bool advanced) -{ - if (advanced) { - menuBar()->addMenu(_ui.menuFile); - menuBar()->addMenu(_ui.menuWidgets); - } else { - menuBar()->clear(); - } -}