11 changed files with 533 additions and 154 deletions
@ -0,0 +1,156 @@
@@ -0,0 +1,156 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2011 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/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
/*!
|
||||
* @file |
||||
* @brief Message Handler |
||||
* @author Gus Grubba <mavlink@grubba.com> |
||||
*/ |
||||
|
||||
#include "QGCApplication.h" |
||||
#include "QGCMessageHandler.h" |
||||
#include "UASManager.h" |
||||
|
||||
QGCUasMessage::QGCUasMessage(int componentid, int severity, QString text) |
||||
{ |
||||
_compId = componentid; |
||||
_severity = severity; |
||||
_text = text; |
||||
} |
||||
|
||||
IMPLEMENT_QGC_SINGLETON(QGCMessageHandler, QGCMessageHandler) |
||||
|
||||
QGCMessageHandler::QGCMessageHandler(QObject *parent) |
||||
: QGCSingleton(parent) |
||||
, _activeUAS(NULL) |
||||
{ |
||||
connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); |
||||
emit textMessageReceived(NULL); |
||||
} |
||||
|
||||
QGCMessageHandler::~QGCMessageHandler() |
||||
{ |
||||
_clearMessages(); |
||||
} |
||||
|
||||
void QGCMessageHandler::_clearMessages() |
||||
{ |
||||
_mutex.lock(); |
||||
while(_messages.count()) { |
||||
delete _messages.last(); |
||||
_messages.pop_back(); |
||||
} |
||||
_mutex.unlock(); |
||||
} |
||||
|
||||
void QGCMessageHandler::setActiveUAS(UASInterface* uas) |
||||
{ |
||||
// If we were already attached to an autopilot, disconnect it.
|
||||
if (_activeUAS && _activeUAS != uas) |
||||
{ |
||||
disconnect(_activeUAS, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); |
||||
_activeUAS = NULL; |
||||
_clearMessages(); |
||||
emit textMessageReceived(NULL); |
||||
} |
||||
// And now if there's an autopilot to follow, set up the UI.
|
||||
if (uas) |
||||
{ |
||||
// Connect to the new UAS.
|
||||
_clearMessages(); |
||||
_activeUAS = uas; |
||||
connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); |
||||
} |
||||
} |
||||
|
||||
void QGCMessageHandler::handleTextMessage(int uasid, int compId, int severity, QString text) |
||||
{ |
||||
Q_UNUSED(uasid); |
||||
|
||||
// Color the output depending on the message severity. We have 3 distinct cases:
|
||||
// 1: If we have an ERROR or worse, make it bigger, bolder, and highlight it red.
|
||||
// 2: If we have a warning or notice, just make it bold and color it orange.
|
||||
// 3: Otherwise color it the standard color, white.
|
||||
|
||||
// So first determine the styling based on the severity.
|
||||
QString style; |
||||
switch (severity) |
||||
{ |
||||
case MAV_SEVERITY_EMERGENCY: |
||||
case MAV_SEVERITY_ALERT: |
||||
case MAV_SEVERITY_CRITICAL: |
||||
case MAV_SEVERITY_ERROR: |
||||
//Use set RGB values from given color from QGC
|
||||
style = QString("color: rgb(%1, %2, %3); font-weight:bold").arg(QGC::colorRed.red()).arg(QGC::colorRed.green()).arg(QGC::colorRed.blue()); |
||||
break; |
||||
case MAV_SEVERITY_NOTICE: |
||||
case MAV_SEVERITY_WARNING: |
||||
style = QString("color: rgb(%1, %2, %3); font-weight:bold").arg(QGC::colorOrange.red()).arg(QGC::colorOrange.green()).arg(QGC::colorOrange.blue()); |
||||
break; |
||||
default: |
||||
style = QString("color:white; font-weight:bold"); |
||||
break; |
||||
} |
||||
|
||||
// And determine the text for the severitie
|
||||
QString severityText(""); |
||||
switch (severity) |
||||
{ |
||||
case MAV_SEVERITY_EMERGENCY: |
||||
severityText = QString(tr(" EMERGENCY:")); |
||||
break; |
||||
case MAV_SEVERITY_ALERT: |
||||
severityText = QString(tr(" ALERT:")); |
||||
break; |
||||
case MAV_SEVERITY_CRITICAL: |
||||
severityText = QString(tr(" Critical:")); |
||||
break; |
||||
case MAV_SEVERITY_ERROR: |
||||
severityText = QString(tr(" Error:")); |
||||
break; |
||||
case MAV_SEVERITY_WARNING: |
||||
severityText = QString(tr(" Warning:")); |
||||
break; |
||||
case MAV_SEVERITY_NOTICE: |
||||
severityText = QString(tr(" Notice:")); |
||||
break; |
||||
case MAV_SEVERITY_INFO: |
||||
severityText = QString(tr(" Info:")); |
||||
break; |
||||
case MAV_SEVERITY_DEBUG: |
||||
severityText = QString(tr(" Debug:")); |
||||
break; |
||||
default: |
||||
severityText = QString(tr("")); |
||||
break; |
||||
} |
||||
|
||||
// Finally preppend the properly-styled text with a timestamp.
|
||||
QString dateString = QDateTime::currentDateTime().toString("hh:mm:ss.zzz"); |
||||
QGCUasMessage* message = new QGCUasMessage(compId, severity, text); |
||||
message->_setFormatedText(QString("<p style=\"color:#CCCCCC\">[%2 - COMP:%3]<font style=\"%1\">%4 %5</font></p>").arg(style).arg(dateString).arg(compId).arg(severityText).arg(text)); |
||||
_mutex.lock(); |
||||
_messages.append(message); |
||||
_mutex.unlock(); |
||||
emit textMessageReceived(message); |
||||
} |
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2011 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/>.
|
||||
|
||||
======================================================================*/ |
||||
|
||||
/*!
|
||||
* @file |
||||
* @brief Message Handler |
||||
* @author Gus Grubba <mavlink@grubba.com> |
||||
*/ |
||||
|
||||
#ifndef QGCMESSAGEHANDLER_H |
||||
#define QGCMESSAGEHANDLER_H |
||||
|
||||
#include <QObject> |
||||
#include <QVector> |
||||
#include <QMutex> |
||||
|
||||
#include "QGCSingleton.h" |
||||
|
||||
class UASInterface; |
||||
class QGCMessageHandler; |
||||
|
||||
/*!
|
||||
* @class QGCUasMessage |
||||
* @brief Message element |
||||
*/ |
||||
class QGCUasMessage |
||||
{ |
||||
friend class QGCMessageHandler; |
||||
public: |
||||
/**
|
||||
* @brief Get message source component ID |
||||
*/ |
||||
int getComponentID() { return _compId; } |
||||
/**
|
||||
* @brief Get message severity (from MAV_SEVERITY_XXX enum) |
||||
*/ |
||||
int getSeverity() { return _severity; } |
||||
/**
|
||||
* @brief Get message text (e.g. "[pm] sending list") |
||||
*/ |
||||
QString getText() { return _text; } |
||||
/**
|
||||
* @brief Get (html) formatted text (in the form: "[11:44:21.137 - COMP:50] Info: [pm] sending list") |
||||
*/ |
||||
QString getFormatedText() { return _formatedText; } |
||||
private: |
||||
QGCUasMessage(int componentid, int severity, QString text); |
||||
void _setFormatedText(const QString formatedText) { _formatedText = formatedText; } |
||||
int _compId; |
||||
int _severity; |
||||
QString _text; |
||||
QString _formatedText; |
||||
}; |
||||
|
||||
class QGCMessageHandler : public QGCSingleton |
||||
{ |
||||
Q_OBJECT |
||||
DECLARE_QGC_SINGLETON(QGCMessageHandler, QGCMessageHandler) |
||||
public: |
||||
explicit QGCMessageHandler(QObject *parent = 0); |
||||
~QGCMessageHandler(); |
||||
/**
|
||||
* @brief Locks access to the message list |
||||
*/ |
||||
void lockAccess() {_mutex.lock(); } |
||||
/**
|
||||
* @brief Unlocks access to the message list |
||||
*/ |
||||
void unlockAccess() {_mutex.unlock(); } |
||||
/**
|
||||
* @brief Access to the message list |
||||
*/ |
||||
const QVector<QGCUasMessage*>& messages() { return _messages; } |
||||
public slots: |
||||
/**
|
||||
* @brief Set currently active UAS |
||||
* @param uas The current active UAS |
||||
*/ |
||||
void setActiveUAS(UASInterface* uas); |
||||
/**
|
||||
* @brief Handle text message from current active UAS |
||||
* @param uasid UAS Id |
||||
* @param componentid Component Id |
||||
* @param severity Message severity |
||||
* @param text Message Text |
||||
*/ |
||||
void handleTextMessage(int uasid, int componentid, int severity, QString text); |
||||
signals: |
||||
/**
|
||||
* @brief Sent out when new message arrives |
||||
* @param message A pointer to the message. NULL if resetting (new UAS assigned) |
||||
*/ |
||||
void textMessageReceived(QGCUasMessage* message); |
||||
private: |
||||
void _clearMessages(); |
||||
// Stores the UAS that we're currently receiving messages from.
|
||||
UASInterface* _activeUAS; |
||||
QVector<QGCUasMessage*> _messages; |
||||
QMutex _mutex; |
||||
}; |
||||
|
||||
#endif // QGCMESSAGEHANDLER_H
|
@ -1,152 +1,158 @@
@@ -1,152 +1,158 @@
|
||||
/*=====================================================================
|
||||
|
||||
QGroundControl Open Source Ground Control Station |
||||
|
||||
(c) 2009 - 2011 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 <QMenu> |
||||
#include <QScrollBar> |
||||
|
||||
#include "QGCToolBar.h" |
||||
#include "QGCMessageView.h" |
||||
#include "GAudioOutput.h" |
||||
#include "QGCUnconnectedInfoWidget.h" |
||||
#include "UASManager.h" |
||||
#include "QGCMessageHandler.h" |
||||
#include "ui_QGCMessageView.h" |
||||
|
||||
/*-------------------------------------------------------------------------------------
|
||||
QGCMessageView |
||||
-------------------------------------------------------------------------------------*/ |
||||
|
||||
QGCMessageView::QGCMessageView(QWidget *parent) : |
||||
QWidget(parent), |
||||
activeUAS(NULL), |
||||
ui(new Ui::QGCMessageView) |
||||
_ui(new Ui::QGCMessageView) |
||||
{ |
||||
setObjectName("QUICKVIEW_MESSAGE_CONSOLE") ; |
||||
_ui->setupUi(this); |
||||
} |
||||
|
||||
ui->setupUi(this); |
||||
setStyleSheet("QPlainTextEdit { border: 0px }"); |
||||
QGCMessageView::~QGCMessageView() |
||||
{ |
||||
delete _ui; |
||||
} |
||||
|
||||
// Construct initial widget
|
||||
connectWidget = new QGCUnconnectedInfoWidget(this); |
||||
ui->horizontalLayout->addWidget(connectWidget); |
||||
ui->plainTextEdit->hide(); |
||||
/*-------------------------------------------------------------------------------------
|
||||
QGCMessageViewWidget |
||||
-------------------------------------------------------------------------------------*/ |
||||
|
||||
QGCMessageViewWidget::QGCMessageViewWidget(QWidget *parent) |
||||
: QGCMessageView(parent) |
||||
, _unconnectedWidget(NULL) |
||||
{ |
||||
setStyleSheet("QPlainTextEdit { border: 0px }"); |
||||
// Construct initial widget
|
||||
_unconnectedWidget = new QGCUnconnectedInfoWidget(this); |
||||
ui()->horizontalLayout->addWidget(_unconnectedWidget); |
||||
ui()->plainTextEdit->hide(); |
||||
// Enable the right-click menu for the text editor. This works because the plainTextEdit
|
||||
// widget has its context menu policy set to its actions list. So any actions we add
|
||||
// to this widget's action list will be automatically displayed.
|
||||
// We only have the clear action right now.
|
||||
QAction* clearAction = new QAction(tr("Clear Text"), this); |
||||
connect(clearAction, SIGNAL(triggered()), ui->plainTextEdit, SLOT(clear())); |
||||
ui->plainTextEdit->addAction(clearAction); |
||||
|
||||
// Connect to the currently active UAS.
|
||||
setActiveUAS(UASManager::instance()->getActiveUAS()); |
||||
connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*))); |
||||
connect(clearAction, SIGNAL(triggered()), ui()->plainTextEdit, SLOT(clear())); |
||||
ui()->plainTextEdit->addAction(clearAction); |
||||
// Connect message handler
|
||||
connect(QGCMessageHandler::instance(), SIGNAL(textMessageReceived(QGCUasMessage*)), this, SLOT(handleTextMessage(QGCUasMessage*))); |
||||
} |
||||
|
||||
QGCMessageView::~QGCMessageView() |
||||
QGCMessageViewWidget::~QGCMessageViewWidget() |
||||
{ |
||||
// The only thing we need to delete is the ui because it's the only thing not cleaned up automatically
|
||||
// by the deletion of its parent.
|
||||
delete ui; |
||||
} |
||||
|
||||
void QGCMessageView::setActiveUAS(UASInterface* uas) |
||||
{ |
||||
// If we were already attached to an autopilot, disconnect it, restoring
|
||||
// the widget to its initial state as needed.
|
||||
if (activeUAS) |
||||
{ |
||||
disconnect(activeUAS, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); |
||||
ui->plainTextEdit->clear(); |
||||
activeUAS = NULL; |
||||
} |
||||
|
||||
// And now if there's an autopilot to follow, set up the UI.
|
||||
if (uas) |
||||
void QGCMessageViewWidget::handleTextMessage(QGCUasMessage *message) |
||||
{ |
||||
// Reset
|
||||
if(!message) { |
||||
ui()->plainTextEdit->clear(); |
||||
_unconnectedWidget->show(); |
||||
ui()->plainTextEdit->hide(); |
||||
} else { |
||||
// Make sure the UI is configured for showing messages.
|
||||
// Note that this call is NOT equivalent to `connectWidget->isVisible()`.
|
||||
if (!connectWidget->isHidden()) |
||||
// Note that this call is NOT equivalent to `_unconnectedWidget->isVisible()`.
|
||||
if (!_unconnectedWidget->isHidden()) |
||||
{ |
||||
connectWidget->hide(); |
||||
ui->plainTextEdit->show(); |
||||
_unconnectedWidget->hide(); |
||||
ui()->plainTextEdit->show(); |
||||
} |
||||
|
||||
// And connect to the new UAS.
|
||||
connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)), this, SLOT(handleTextMessage(int,int,int,QString))); |
||||
activeUAS = uas; |
||||
} |
||||
// But if there's no new autopilot, restore the connect button.
|
||||
else |
||||
{ |
||||
connectWidget->show(); |
||||
ui->plainTextEdit->hide(); |
||||
} |
||||
} |
||||
|
||||
void QGCMessageView::handleTextMessage(int uasid, int compId, int severity, QString text) |
||||
{ |
||||
QPlainTextEdit *msgWidget = ui->plainTextEdit; |
||||
(void)uasid; // Unused variable voided.
|
||||
QPlainTextEdit *msgWidget = ui()->plainTextEdit; |
||||
// Turn off updates while we're appending content to avoid breaking the autoscroll behavior
|
||||
msgWidget->setUpdatesEnabled(false); |
||||
QScrollBar *scroller = msgWidget->verticalScrollBar(); |
||||
msgWidget->appendHtml(message->getFormatedText()); |
||||
// Ensure text area scrolls correctly
|
||||
scroller->setValue(scroller->maximum()); |
||||
msgWidget->setUpdatesEnabled(true); |
||||
} |
||||
} |
||||
|
||||
// Color the output depending on the message severity. We have 3 distinct cases:
|
||||
// 1: If we have an ERROR or worse, make it bigger, bolder, and highlight it red.
|
||||
// 2: If we have a warning or notice, just make it bold and color it orange.
|
||||
// 3: Otherwise color it the standard color, white.
|
||||
/*-------------------------------------------------------------------------------------
|
||||
QGCMessageViewRollDown |
||||
-------------------------------------------------------------------------------------*/ |
||||
|
||||
// So first deteremine the styling based on the severity.
|
||||
QString style; |
||||
switch (severity) |
||||
QGCMessageViewRollDown::QGCMessageViewRollDown(QWidget *parent, QGCToolBar *toolBar) |
||||
: QGCMessageView(parent) |
||||
{ |
||||
case MAV_SEVERITY_EMERGENCY: |
||||
case MAV_SEVERITY_ALERT: |
||||
case MAV_SEVERITY_CRITICAL: |
||||
case MAV_SEVERITY_ERROR: |
||||
//Use set RGB values from given color from QGC
|
||||
style = QString("color: rgb(%1, %2, %3); font-weight:bold").arg(QGC::colorRed.red()).arg(QGC::colorRed.green()).arg(QGC::colorRed.blue()); |
||||
break; |
||||
case MAV_SEVERITY_NOTICE: |
||||
case MAV_SEVERITY_WARNING: |
||||
style = QString("color: rgb(%1, %2, %3); font-weight:bold").arg(QGC::colorOrange.red()).arg(QGC::colorOrange.green()).arg(QGC::colorOrange.blue()); |
||||
break; |
||||
default: |
||||
style = QString("color:white; font-weight:bold"); |
||||
break; |
||||
_toolBar = toolBar; |
||||
setStyleSheet("QPlainTextEdit { border: 1px }"); |
||||
QPlainTextEdit *msgWidget = ui()->plainTextEdit; |
||||
QAction* clearAction = new QAction(tr("Clear Text"), this); |
||||
connect(clearAction, SIGNAL(triggered()), msgWidget, SLOT(clear())); |
||||
msgWidget->addAction(clearAction); |
||||
// Init Messages
|
||||
QGCMessageHandler::instance()->lockAccess(); |
||||
msgWidget->setUpdatesEnabled(false); |
||||
QVector<QGCUasMessage*> messages = QGCMessageHandler::instance()->messages(); |
||||
for(int i = 0; i < messages.count(); i++) { |
||||
msgWidget->appendHtml(messages.at(i)->getFormatedText()); |
||||
} |
||||
QScrollBar *scroller = msgWidget->verticalScrollBar(); |
||||
scroller->setValue(scroller->maximum()); |
||||
msgWidget->setUpdatesEnabled(true); |
||||
connect(QGCMessageHandler::instance(), SIGNAL(textMessageReceived(QGCUasMessage*)), this, SLOT(handleTextMessage(QGCUasMessage*))); |
||||
QGCMessageHandler::instance()->unlockAccess(); |
||||
} |
||||
|
||||
// And determine the text for the severitie
|
||||
QString severityText(""); |
||||
switch (severity) |
||||
QGCMessageViewRollDown::~QGCMessageViewRollDown() |
||||
{ |
||||
case MAV_SEVERITY_EMERGENCY: |
||||
severityText = QString(tr(" EMERGENCY:")); |
||||
break; |
||||
case MAV_SEVERITY_ALERT: |
||||
severityText = QString(tr(" ALERT:")); |
||||
break; |
||||
case MAV_SEVERITY_CRITICAL: |
||||
severityText = QString(tr(" Critical:")); |
||||
break; |
||||
case MAV_SEVERITY_ERROR: |
||||
severityText = QString(tr(" Error:")); |
||||
break; |
||||
case MAV_SEVERITY_WARNING: |
||||
severityText = QString(tr(" Warning:")); |
||||
break; |
||||
case MAV_SEVERITY_NOTICE: |
||||
severityText = QString(tr(" Notice:")); |
||||
break; |
||||
case MAV_SEVERITY_INFO: |
||||
severityText = QString(tr(" Info:")); |
||||
break; |
||||
case MAV_SEVERITY_DEBUG: |
||||
severityText = QString(tr(" Debug:")); |
||||
break; |
||||
default: |
||||
severityText = QString(tr("")); |
||||
break; |
||||
} |
||||
|
||||
// Finally append the properly-styled text with a timestamp.
|
||||
QString dateString = QDateTime::currentDateTime().toString("hh:mm:ss.zzz"); |
||||
msgWidget->appendHtml(QString("<p style=\"color:#CCCCCC\">[%2 - COMP:%3]<font style=\"%1\">%4 %5</font></p>").arg(style).arg(dateString).arg(compId).arg(severityText).arg(text)); |
||||
} |
||||
|
||||
void QGCMessageViewRollDown::handleTextMessage(QGCUasMessage *message) |
||||
{ |
||||
// Reset
|
||||
if(message) { |
||||
ui()->plainTextEdit->clear(); |
||||
} else { |
||||
QPlainTextEdit *msgWidget = ui()->plainTextEdit; |
||||
// Turn off updates while we're appending content to avoid breaking the autoscroll behavior
|
||||
msgWidget->setUpdatesEnabled(false); |
||||
QScrollBar *scroller = msgWidget->verticalScrollBar(); |
||||
msgWidget->appendHtml(message->getFormatedText()); |
||||
// Ensure text area scrolls correctly
|
||||
scroller->setValue(scroller->maximum()); |
||||
msgWidget->setUpdatesEnabled(true); |
||||
} |
||||
} |
||||
|
||||
void QGCMessageViewRollDown::leaveEvent(QEvent * event) |
||||
{ |
||||
Q_UNUSED(event); |
||||
_toolBar->leaveMessageView(); |
||||
close(); |
||||
} |
||||
|
Loading…
Reference in new issue