Commit c51a1a6e authored by Nate Weibley's avatar Nate Weibley

Add optional qml-based console to view debugging messages. For #3121

parent e6648c06
......@@ -94,7 +94,10 @@ QT += \
# testlib is needed even in release flavor for QSignalSpy support
QT += testlib
ReleaseBuild {
# We don't need the testlib console in release mode
QT.testlib.CONFIG -= console
}
#
# OS Specific settings
#
......@@ -295,6 +298,7 @@ HEADERS += \
src/QmlControls/QGCImageProvider.h \
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.h \
src/QtLocationPlugin/QMLControl/QGCMapEngineManager.h \
src/ViewWidgets/AppMessagesDialog.h
DebugBuild {
HEADERS += \
......@@ -434,6 +438,7 @@ SOURCES += \
src/QmlControls/QGCImageProvider.cc \
src/AutoPilotPlugins/APM/APMRemoteParamsDownloader.cc \
src/QtLocationPlugin/QMLControl/QGCMapEngineManager.cc \
src/ViewWidgets/AppMessagesDialog.cc
DebugBuild {
SOURCES += \
......
......@@ -12,6 +12,7 @@
<file alias="APMAirframeComponentSummary.qml">src/AutoPilotPlugins/APM/APMAirframeComponentSummary.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="LogDownload.qml">src/ViewWidgets/LogDownload.qml</file>
<file alias="AppMessagesDialog.qml">src/ViewWidgets/AppMessagesDialog.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="PX4FlightModes.qml">src/AutoPilotPlugins/PX4/PX4FlightModes.qml</file>
......
......@@ -47,6 +47,8 @@ void QGCDockWidget::closeEvent(QCloseEvent* event)
saveSettings();
event->ignore();
_action->trigger();
} else {
QWidget::closeEvent(event);
}
}
......
......@@ -41,7 +41,7 @@ public:
protected:
QString _title;
QAction* _action;
QPointer<QAction> _action;
static const char* _settingsGroup;
};
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
import QtQuick 2.5
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
import QtQuick.Dialogs 1.2
import QGroundControl.Palette 1.0
import QGroundControl.Controls 1.0
import QGroundControl.Controllers 1.0
import QGroundControl.ScreenTools 1.0
QGCView {
viewPanel: panel
id: logwindow
property bool loaded: false
QGCPalette { id: qgcPal }
Connections {
target: debugMessageModel
onDataChanged: {
// Keep the view in sync if the button is checked
if (loaded) {
if (followTail.checked) {
listview.positionViewAtEnd();
}
}
}
}
Component {
id: delegateItem
Rectangle {
color: index % 2 == 0 ? qgcPal.window : qgcPal.windowShade
height: Math.round(ScreenTools.defaultFontPixelHeight * 0.5 + field.height)
width: listview.width
Text {
anchors.verticalCenter: parent.verticalCenter
id: field
text: display
color: qgcPal.text
width: parent.width
wrapMode: Text.Wrap
}
}
}
QGCViewPanel {
id: panel
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: qgcPal.window
}
ListView {
Component.onCompleted: {
loaded = true
}
anchors.margins: ScreenTools.defaultFontPixelHeight
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: followTail.top
id: listview
model: debugMessageModel
delegate: delegateItem
}
Button {
id: followTail
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: ScreenTools.defaultFontPixelWidth
text: "Show Latest"
checkable: true
checked: true
onCheckedChanged: {
if (checked && loaded) {
listview.positionViewAtEnd();
}
}
}
}
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "AppMessagesDialog.h"
#include <QStringListModel>
#include <iostream>
static QtMessageHandler old_handler;
static QStringListModel debug_strings;
static void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const char symbols[] = { 'D', 'E', '!', 'X', 'I' };
QString output = QString("[%1] at %2:%3 - \"%4\"").arg(symbols[type]).arg(context.file).arg(context.line).arg(msg);
// Avoid recursion
if (!QString(context.category).startsWith("qt.quick")) {
const int line = debug_strings.rowCount();
debug_strings.insertRows(line, 1);
debug_strings.setData(debug_strings.index(line), output, Qt::DisplayRole);
}
if (old_handler != nullptr) {
old_handler(type, context, msg);
}
if( type == QtFatalMsg ) abort();
}
AppMessagesDialog::AppMessagesDialog(const QString &title, QAction *action, QWidget *parent) :
QGCQmlWidgetHolder(title, action, parent)
{
resize(800, 600);
setContextPropertyObject("debugMessageModel", &debug_strings);
setSource(QUrl::fromUserInput("qrc:/qml/AppMessagesDialog.qml"));
loadSettings();
}
void AppMessagesDialog::installHandler()
{
old_handler = qInstallMessageHandler(msgHandler);
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#pragma once
#include "QGCQmlWidgetHolder.h"
class QStringListModel;
class AppMessagesDialog : public QGCQmlWidgetHolder
{
Q_OBJECT
public:
AppMessagesDialog(const QString& title, QAction* action, QWidget *parent = 0);
static void installHandler();
};
......@@ -35,7 +35,8 @@ This file is part of the QGROUNDCONTROL project
#include <QHostAddress>
#include <QUdpSocket>
#include <QtPlugin>
#include <QStringListModel>
#include "AppMessagesDialog.h"
#include "QGCApplication.h"
#define SINGLE_INSTANCE_PORT 14499
......@@ -71,17 +72,6 @@ This file is part of the QGROUNDCONTROL project
#endif
#ifdef Q_OS_WIN
/// @brief Message handler which is installed using qInstallMsgHandler so you do not need
/// the MSFT debug tools installed to see qDebug(), qWarning(), qCritical and qAbort
void msgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
const char symbols[] = { 'I', 'E', '!', 'X' };
QString output = QString("[%1] at %2:%3 - \"%4\"").arg(symbols[type]).arg(context.file).arg(context.line).arg(msg);
std::cerr << output.toStdString() << std::endl;
if( type == QtFatalMsg ) abort();
}
/// @brief CRT Report Hook installed using _CrtSetReportHook. We install this hook when
/// we don't want asserts to pop a dialog on windows.
int WindowsCrtReportHook(int reportType, char* message, int* returnValue)
......@@ -143,10 +133,9 @@ int main(int argc, char *argv[])
#endif
#endif
#ifdef Q_OS_WIN
// install the message handler
qInstallMessageHandler(msgHandler);
AppMessagesDialog::installHandler();
#ifdef Q_OS_WIN
// Set our own OpenGL buglist
qputenv("QT_OPENGL_BUGLIST", ":/opengl/resources/opengl/buglist.json");
......
......@@ -66,6 +66,7 @@ This file is part of the QGROUNDCONTROL project
#include "UASInfoWidget.h"
#include "HILDockWidget.h"
#include "LogDownload.h"
#include "AppMessagesDialog.h"
#endif
#ifndef __ios__
......@@ -88,7 +89,8 @@ enum DockWidgetTypes {
INFO_VIEW,
HIL_CONFIG,
ANALYZE,
LOG_DOWNLOAD
LOG_DOWNLOAD,
DEBUG_MESSAGES
};
static const char *rgDockWidgetNames[] = {
......@@ -99,7 +101,8 @@ static const char *rgDockWidgetNames[] = {
"Info View",
"HIL Config",
"Analyze",
"Log Download"
"Log Download",
"Debug Messages"
};
#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY) / sizeof(ARRAY[0]))
......@@ -306,7 +309,7 @@ void MainWindow::_buildCommonWidgets(void)
const char* pDockWidgetName = rgDockWidgetNames[i];
// Add to menu
QAction* action = new QAction(tr(pDockWidgetName), NULL);
QAction* action = new QAction(tr(pDockWidgetName), this);
action->setCheckable(true);
action->setData(i);
connect(action, &QAction::triggered, this, &MainWindow::_showDockWidgetAction);
......@@ -352,6 +355,9 @@ bool MainWindow::_createInnerDockWidget(const QString& widgetName)
case LOG_DOWNLOAD:
widget = new LogDownload(widgetName, action, this);
break;
case DEBUG_MESSAGES:
widget = new AppMessagesDialog(widgetName, action, this);
break;
case STATUS_DETAILS:
widget = new UASInfoWidget(widgetName, action, this);
break;
......@@ -419,10 +425,6 @@ void MainWindow::closeEvent(QCloseEvent *event)
_storeCurrentViewState();
storeSettings();
//-- TODO: This effectively causes the QGCApplication destructor to not being able
// to access the pointer it is trying to delete.
_instance = NULL;
emit mainWindowClosed();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment