refs #77, refs #335 text messages refactoring

* using QScopedPointer
* usings command line parser
* SELCAL handling via aircraft, synced with flight plan
This commit is contained in:
Klaus Basan
2014-10-29 01:30:55 +01:00
committed by Roland Winklmeier
parent cd69eebe8c
commit 28b99de1da
2 changed files with 131 additions and 137 deletions

View File

@@ -8,11 +8,12 @@
*/
#include "textmessagecomponent.h"
#include "ui_textmessagecomponent.h"
#include "blackcore/context_audio.h"
#include "blackmisc/nwuser.h"
#include "blackmisc/notificationsounds.h"
#include "blackmisc/logmessage.h"
#include "blackcore/context_audio.h"
#include "ui_textmessagecomponent.h"
#include "blackmisc/simplecommandparser.h"
#include <QPushButton>
#include <QMenu>
@@ -31,31 +32,31 @@ namespace BlackGui
{
CTextMessageComponent::CTextMessageComponent(QWidget *parent) :
QTabWidget(parent), CEnableForRuntime(nullptr, false), ui(new Ui::CTextMessageComponent), m_selcalCallback(nullptr), m_clearTextEditAction(nullptr), m_currentTextEdit(nullptr)
QTabWidget(parent),
CEnableForRuntime(nullptr, false),
ui(new Ui::CTextMessageComponent)
{
ui->setupUi(this);
this->m_clearTextEditAction = new QAction("Clear", this);
connect(this->m_clearTextEditAction, &QAction::triggered, this, &CTextMessageComponent::clearTextEdit);
connect(this->m_clearTextEditAction, &QAction::triggered, this, &CTextMessageComponent::ps_clearTextEdit);
ui->te_TextMessagesAll->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->te_TextMessagesAll, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
connect(ui->te_TextMessagesAll, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::ps_showContextMenuForTextEdit);
ui->te_TextMessagesUnicom->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->te_TextMessagesUnicom, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
connect(ui->te_TextMessagesUnicom, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::ps_showContextMenuForTextEdit);
ui->te_TextMessagesCOM1->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->te_TextMessagesCOM1, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
connect(ui->te_TextMessagesCOM1, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::ps_showContextMenuForTextEdit);
ui->te_TextMessagesCOM2->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->te_TextMessagesCOM2, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
connect(ui->te_TextMessagesCOM2, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::ps_showContextMenuForTextEdit);
}
CTextMessageComponent::~CTextMessageComponent()
{
delete ui;
}
{ }
QWidget *CTextMessageComponent::getTab(CTextMessageComponent::Tab tab)
QWidget *CTextMessageComponent::getTabWidget(CTextMessageComponent::Tab tab)
{
switch (tab)
{
@@ -77,32 +78,30 @@ namespace BlackGui
/*
* Text messages received or send, append to GUI
*/
void CTextMessageComponent::appendTextMessagesToGui(const CTextMessageList &messages, bool sending)
void CTextMessageComponent::textMessagesReceived(const CTextMessageList &messages, bool sending)
{
if (messages.isEmpty()) return;
foreach(CTextMessage message, messages)
{
const QString currentSelcal = this->m_selcalCallback ? this->m_selcalCallback() : "";
if (CSelcal::isValidCode(currentSelcal) && message.isSelcalMessageFor(currentSelcal))
{
if (this->getOwnAircraft().isActiveFrequencyWithin25kHzChannel(message.getFrequency()))
{
// this is SELCAL for me
if (this->getIContextAudio())
{
this->getIContextAudio()->playSelcalTone(currentSelcal);
}
else
{
emit this->displayInInfoWindow(CLogMessage(this).info("SELCAL received"), 3 * 1000);
}
}
continue; // not displayed
}
bool relevantForMe = false;
QString m = message.asString(true, false, "\t");
// SELCAL
if (message.isSelcalMessage() && getOwnAircraft().isSelcalSelected(message.getSelcalCode()))
{
// this is SELCAL for me
if (this->getIContextAudio())
{
this->getIContextAudio()->playSelcalTone(message.getSelcalCode());
}
else
{
emit this->displayInInfoWindow(CLogMessage(this).info("SELCAL received"), 3 * 1000);
}
continue;
}
// UNICOM
if (message.isSendToUnicom())
{
this->ui->te_TextMessagesUnicom->append(m);
@@ -132,27 +131,29 @@ namespace BlackGui
}
// message for me? right frequency? otherwise quit
if (relevantForMe || message.isServerMessage()) this->ui->te_TextMessagesAll->append(m);
if (!relevantForMe) return;
if (relevantForMe || message.isServerMessage()) { this->ui->te_TextMessagesAll->append(m); }
if (!relevantForMe) { return; }
// overlay message if this channel is not selected
if (!sending && !message.isSendToUnicom() && !message.isServerMessage())
{
// if the channel is selected, do nothing
if (!this->isCorrespondingTextMessageTabSelected(message))
{
emit this->displayInInfoWindow(message.toCVariant(), 5 * 1000);
}
}
}
}
void CTextMessageComponent::changedAircraftCockpit()
void CTextMessageComponent::ps_onChangedAircraftCockpit()
{
this->showCurrentFrequenciesFromCockpit();
}
void CTextMessageComponent::runtimeHasBeenSet()
{
connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CTextMessageComponent::changedAircraftCockpit);
connect(this->getIContextOwnAircraft(), &IContextOwnAircraft::changedAircraftCockpit, this, &CTextMessageComponent::ps_onChangedAircraftCockpit);
}
/*
@@ -217,9 +218,9 @@ namespace BlackGui
layout->addWidget(closeButton);
newTab->setLayout(layout);
textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::ps_showContextMenuForTextEdit);
int index = this->addTab(newTab, tabName);
this->connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab);
this->connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::ps_closeTextMessageTab);
this->setCurrentIndex(index);
if (this->getIContextNetwork())
@@ -276,8 +277,7 @@ namespace BlackGui
{
CTextMessage tm;
int index = this->currentIndex();
if (index < 0) return tm;
if (index == this->indexOf(this->ui->tb_TextMessagesAll)) return tm;
if (index < 0 || index == this->indexOf(this->ui->tb_TextMessagesAll)) { return tm; }
// from
tm.setSenderCallsign(this->getOwnAircraft().getCallsign());
@@ -326,7 +326,7 @@ namespace BlackGui
/*
* Close message tab
*/
void CTextMessageComponent::closeTextMessageTab()
void CTextMessageComponent::ps_closeTextMessageTab()
{
QObject *sender = QObject::sender();
QWidget *parentWidget = qobject_cast<QWidget *>(sender->parent());
@@ -341,7 +341,7 @@ namespace BlackGui
if (index >= 0) this->removeTab(index);
}
void CTextMessageComponent::showContextMenuForTextEdit(const QPoint &pt)
void CTextMessageComponent::ps_showContextMenuForTextEdit(const QPoint &pt)
{
QObject *sender = QObject::sender();
this->m_currentTextEdit = qobject_cast<QTextEdit *>(sender);
@@ -356,7 +356,7 @@ namespace BlackGui
delete menu;
}
void CTextMessageComponent::clearTextEdit()
void CTextMessageComponent::ps_clearTextEdit()
{
if (!this->m_currentTextEdit) return;
this->m_currentTextEdit->clear();
@@ -366,87 +366,76 @@ namespace BlackGui
/*
* Command entered
*/
void CTextMessageComponent::commandEntered()
bool CTextMessageComponent::parseCommandLine(const QString &commandLine)
{
// TODO: just a first draft of the command line parser
// needs to be refactored, as soon as a first version works
QLineEdit *lineEdit = qobject_cast<QLineEdit *>(QObject::sender());
Q_ASSERT(lineEdit);
QString cmdLine = lineEdit->text().simplified();
if (cmdLine.isEmpty()) return;
QList<QString> parts = cmdLine.toLower().split(' ');
if (parts.length() < 1) return;
QString cmd = parts[0].startsWith('.') ? parts[0].toLower() : "";
if (cmd == ".m" || cmd == ".msg")
static CSimpleCommandParser parser(
{
if (!this->getIContextNetwork() || !this->getIContextNetwork()->isConnected())
".msg", ".m"
});
if (commandLine.isEmpty()) { return false; }
parser.parse(commandLine);
if (parser.isKnownCommand())
{
if (parser.matchesCommand(".msg", ".m"))
{
CLogMessage(this).error("network needs to be connected");
return;
}
if (parts.length() < 3)
{
CLogMessage(this).error("incorrect message");
return;
}
QString p = parts[1].trimmed(); // receiver
if (!this->getIContextNetwork()->isConnected())
{
CLogMessage(this).error("network needs to be connected");
return false;
}
if (parser.countParts() < 3)
{
CLogMessage(this).error("incorrect message");
return false;
}
QString receiver = parser.part(1).trimmed(); // receiver
// select current tab by command
this->setVisible(true);
if (p == "c1" || p == "com1")
{
this->setCurrentWidget(this->ui->tb_TextMessagesCOM1);
}
else if (p == "c2" || p == "com2")
{
this->setCurrentWidget(this->ui->tb_TextMessagesCOM2);
}
else if (p == "u" || p == "unicom" || p == "uni")
{
this->setCurrentWidget(this->ui->tb_TextMessagesUnicom);
// select current tab by command
this->setVisible(true);
if (receiver == "c1" || receiver == "com1")
{
this->setCurrentWidget(this->ui->tb_TextMessagesCOM1);
}
else if (receiver == "c2" || receiver == "com2")
{
this->setCurrentWidget(this->ui->tb_TextMessagesCOM2);
}
else if (receiver == "u" || receiver == "unicom" || receiver == "uni")
{
this->setCurrentWidget(this->ui->tb_TextMessagesUnicom);
}
else
{
QWidget *tab = this->findTextMessageTabByName(receiver.trimmed());
if (tab == nullptr) tab = this->addNewTextMessageTab(receiver.trimmed().toUpper());
this->setCurrentWidget(tab);
}
CTextMessage tm = this->getTextMessageStubForChannel();
QString msg(parser.remainingStringAfter(2));
tm.setMessage(msg);
if (tm.isEmpty()) { return false; }
CTextMessageList tml(tm);
this->getIContextNetwork()->sendTextMessages(tml);
this->textMessagesReceived(tml, true);
return true;
}
else
{
QWidget *tab = this->findTextMessageTabByName(p.trimmed());
if (tab == nullptr) tab = this->addNewTextMessageTab(p.trimmed().toUpper());
this->setCurrentWidget(tab);
// no command
return false;
}
CTextMessage tm = this->getTextMessageStubForChannel();
int index = cmdLine.indexOf(tm.getRecipientCallsign().getStringAsSet(), 0, Qt::CaseInsensitive);
if (index < 0)
{
CLogMessage(this).error("incomplete message");
return;
}
QString msg(cmdLine.mid(index + tm.getRecipientCallsign().asString().length() + 1));
tm.setMessage(msg);
if (tm.isEmpty()) return;
if (!this->isNetworkConnected()) return;
CTextMessageList tml(tm);
this->getIContextNetwork()->sendTextMessages(tml);
this->appendTextMessagesToGui(tml, true);
lineEdit->setText("");
}
else if (cmd.startsWith("."))
{
// dump CMDs
}
else
{
// only if visible
if (this->isVisible()) { return false; }
// single line, no command
// line is considered to be a message to the selected channel, send
if (!this->isNetworkConnected())
{
CLogMessage(this).error("network needs to be connected");
return;
}
if (!this->isVisible())
{
CLogMessage(this).error("text messages can only be sent from corresponding page");
return;
return false;
}
int index = this->currentIndex();
@@ -457,16 +446,14 @@ namespace BlackGui
else
{
CTextMessage tm = this->getTextMessageStubForChannel();
tm.setMessage(cmdLine);
if (tm.isEmpty()) return;
if (!this->getIContextNetwork()) return;
tm.setMessage(commandLine.simplified().trimmed());
if (tm.isEmpty()) { return true; }
CTextMessageList textMessageList(tm);
this->getIContextNetwork()->sendTextMessages(textMessageList);
this->appendTextMessagesToGui(textMessageList, true);
lineEdit->setText("");
this->textMessagesReceived(textMessageList, true);
}
return true;
}
}
}
}
} // namespace
} // namespace

View File

@@ -21,6 +21,7 @@
#include <QTabWidget>
#include <QLineEdit>
#include <QTextEdit>
#include <QScopedPointer>
namespace Ui { class CTextMessageComponent; }
namespace BlackGui
@@ -50,37 +51,32 @@ namespace BlackGui
//! Destructor
~CTextMessageComponent();
//! SELCAL callback, SELCAL is obtained by that
void setSelcalCallback(const std::function<const QString(void)> &selcalCallback) { this->m_selcalCallback = selcalCallback; }
signals:
//! Message to be displayed in info window
void displayInInfoWindow(const BlackMisc::CVariant &message, int displayDurationMs) const;
public slots:
//! Command entered
void commandEntered();
//! \addtogroup commandline
//! @{
//! <pre>
//! .m .msg message text set transponder code CTextMessageComponent
//! </pre>
//! @}
//! \copydoc IContextOwnAircraft::parseCommandLine
bool parseCommandLine(const QString &commandLine);
/*!
* \brief Append text messages (received, to be sent) to GUI
* \param messages
* \param sending
*/
void appendTextMessagesToGui(const BlackMisc::Network::CTextMessageList &messages, bool sending = false);
//! Cockpit values changed, used to updated some components
void changedAircraftCockpit();
//! Text messages received
void onTextMessageReceived(const BlackMisc::Network::CTextMessageList &messages) { this->textMessagesReceived(messages); }
protected:
//! \copydoc CRuntimeBasedComponent::runtimeHasBeenSet
void runtimeHasBeenSet() override;
private:
Ui::CTextMessageComponent *ui;
QWidget *getTab(Tab tab); //!< enum to widget
std::function<const QString(void)> m_selcalCallback; //!< obtain SELCAL by that
QAction *m_clearTextEditAction;
QTextEdit *m_currentTextEdit;
QScopedPointer<Ui::CTextMessageComponent> ui;
QWidget *getTabWidget(Tab tab); //!< enum to widget
QAction *m_clearTextEditAction = nullptr;
QTextEdit *m_currentTextEdit = nullptr;
/*!
* \brief Add new text message tab
@@ -117,15 +113,26 @@ namespace BlackGui
//! Show current frequencies
void showCurrentFrequenciesFromCockpit();
/*!
* \brief Append text messages (received, to be sent) to GUI
* \param messages
* \param sending
*/
void textMessagesReceived(const BlackMisc::Network::CTextMessageList &messages, bool sending = false);
private slots:
//! Cockpit values changed, used to updated some components
void ps_onChangedAircraftCockpit();
//! Close text message tab
void closeTextMessageTab();
void ps_closeTextMessageTab();
//! Context menu for text edit including clear
void showContextMenuForTextEdit(const QPoint &pt);
void ps_showContextMenuForTextEdit(const QPoint &pt);
//! Clear text edit
void clearTextEdit();
void ps_clearTextEdit();
};
}
}