mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-05-05 01:35:45 +08:00
refs #240, own text message component for GUI
* own component * some minor enhancements, e.g. tooltip with real name for message tab
This commit is contained in:
441
src/blackgui/textmessagecomponent.cpp
Normal file
441
src/blackgui/textmessagecomponent.cpp
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
#include "textmessagecomponent.h"
|
||||||
|
#include "blackmisc/nwuser.h"
|
||||||
|
#include "blackmisc/notificationsounds.h"
|
||||||
|
#include "ui_textmessagecomponent.h"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
using namespace BlackCore;
|
||||||
|
using namespace BlackMisc;
|
||||||
|
using namespace BlackGui;
|
||||||
|
using namespace BlackMisc::Network;
|
||||||
|
using namespace BlackMisc::Aviation;
|
||||||
|
using namespace BlackMisc::PhysicalQuantities;
|
||||||
|
using namespace BlackMisc::Settings;
|
||||||
|
|
||||||
|
namespace BlackGui
|
||||||
|
{
|
||||||
|
|
||||||
|
CTextMessageComponent::CTextMessageComponent(QWidget *parent) :
|
||||||
|
QTabWidget(parent), CRuntimeBasedComponent(nullptr, false), ui(new Ui::CTextMessageComponent), m_selcalCallback(nullptr), m_clearTextEditAction(nullptr), m_currentTextEdit(nullptr)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
this->m_clearTextEditAction = new QAction("Clear", this);
|
||||||
|
connect(this->m_clearTextEditAction, &QAction::triggered, this, &CTextMessageComponent::clearTextEdit);
|
||||||
|
|
||||||
|
ui->te_TextMessagesAll->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(ui->te_TextMessagesAll, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
|
||||||
|
|
||||||
|
ui->te_TextMessagesUnicom->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(ui->te_TextMessagesUnicom, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
|
||||||
|
|
||||||
|
ui->te_TextMessagesCOM1->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(ui->te_TextMessagesCOM1, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
|
||||||
|
|
||||||
|
ui->te_TextMessagesCOM2->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(ui->te_TextMessagesCOM2, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
|
||||||
|
}
|
||||||
|
|
||||||
|
CTextMessageComponent::~CTextMessageComponent()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextMessageComponent::setToolTip(const QString &tooltipText, CTextMessageComponent::Tab tab)
|
||||||
|
{
|
||||||
|
this->getTab(tab)->setToolTip(tooltipText);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *CTextMessageComponent::getTab(CTextMessageComponent::Tab tab)
|
||||||
|
{
|
||||||
|
switch (tab)
|
||||||
|
{
|
||||||
|
case TextMessagesAll:
|
||||||
|
return this->ui->tb_TextMessagesAll;
|
||||||
|
case TextMessagesCom1:
|
||||||
|
return this->ui->tb_TextMessagesCOM1;
|
||||||
|
case TextMessagesCom2:
|
||||||
|
return this->ui->tb_TextMessagesCOM2;
|
||||||
|
case TextMessagesUnicom:
|
||||||
|
return this->ui->tb_TextMessagesUnicom;
|
||||||
|
default:
|
||||||
|
qFatal("Wrong index");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text messages received or send, append to GUI
|
||||||
|
*/
|
||||||
|
void CTextMessageComponent::appendTextMessagesToGui(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->displayOverlayInfo(CStatusMessage::getInfoMessage("SELCAL received", CStatusMessage::TypeGui));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue; // not displayed
|
||||||
|
}
|
||||||
|
|
||||||
|
bool relevantForMe = false;
|
||||||
|
QString m = message.asString(true, false, "\t");
|
||||||
|
|
||||||
|
if (message.isSendToUnicom())
|
||||||
|
{
|
||||||
|
this->ui->te_TextMessagesUnicom->append(m);
|
||||||
|
relevantForMe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check message
|
||||||
|
if (message.isRadioMessage())
|
||||||
|
{
|
||||||
|
// check for own COM frequencies
|
||||||
|
if (message.isSendToFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive()))
|
||||||
|
{
|
||||||
|
this->ui->te_TextMessagesCOM1->append(m);
|
||||||
|
relevantForMe = true;
|
||||||
|
}
|
||||||
|
if (message.isSendToFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive()))
|
||||||
|
{
|
||||||
|
this->ui->te_TextMessagesCOM2->append(m);
|
||||||
|
relevantForMe = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (message.isPrivateMessage() && !message.isServerMessage())
|
||||||
|
{
|
||||||
|
// private message
|
||||||
|
this->addPrivateChannelTextMessage(message, sending);
|
||||||
|
relevantForMe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// message for me? right frequency? otherwise quit
|
||||||
|
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->displayOverlayInfo(message.asStatusMessage(true, true, "\t"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is the tab of the message's receiver selected?
|
||||||
|
*/
|
||||||
|
bool CTextMessageComponent::isCorrespondingTextMessageTabSelected(CTextMessage textMessage) const
|
||||||
|
{
|
||||||
|
if (!this->isVisible()) return false;
|
||||||
|
if (!textMessage.hasValidRecipient()) return false;
|
||||||
|
if (textMessage.isEmpty()) return false; // ignore empty message
|
||||||
|
if (textMessage.isPrivateMessage())
|
||||||
|
{
|
||||||
|
// private message
|
||||||
|
CCallsign cs = textMessage.getSenderCallsign();
|
||||||
|
if (cs.isEmpty()) return false;
|
||||||
|
QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet());
|
||||||
|
if (!tab) return false;
|
||||||
|
return this->currentWidget() == tab;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// frequency message
|
||||||
|
if (this->currentWidget() == this->ui->tb_TextMessagesAll) return true;
|
||||||
|
if (textMessage.isSendToFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive()))
|
||||||
|
return this->currentWidget() == this->ui->tb_TextMessagesCOM1;
|
||||||
|
if (textMessage.isSendToFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive()))
|
||||||
|
return this->currentWidget() == this->ui->tb_TextMessagesCOM2;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add new text message tab
|
||||||
|
*/
|
||||||
|
QWidget *CTextMessageComponent::addNewTextMessageTab(const QString &tabName)
|
||||||
|
{
|
||||||
|
QWidget *newTab = new QWidget(this);
|
||||||
|
QPushButton *closeButton = new QPushButton("Close", newTab);
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(newTab);
|
||||||
|
QTextEdit *textEdit = new QTextEdit(newTab);
|
||||||
|
int marginLeft, marginRight, marginTop, marginBottom;
|
||||||
|
this->ui->tb_TextMessagesAll->layout()->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom);
|
||||||
|
newTab->layout()->setContentsMargins(marginLeft, marginTop, marginRight, 2);
|
||||||
|
textEdit->setReadOnly(true);
|
||||||
|
textEdit->setWordWrapMode(QTextOption::NoWrap);
|
||||||
|
layout->addWidget(textEdit);
|
||||||
|
layout->addWidget(closeButton);
|
||||||
|
newTab->setLayout(layout);
|
||||||
|
textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(textEdit, &QTextEdit::customContextMenuRequested, this, &CTextMessageComponent::showContextMenuForTextEdit);
|
||||||
|
int index = this->addTab(newTab, tabName);
|
||||||
|
this->connect(closeButton, &QPushButton::released, this, &CTextMessageComponent::closeTextMessageTab);
|
||||||
|
this->setCurrentIndex(index);
|
||||||
|
|
||||||
|
if (this->getIContextNetwork())
|
||||||
|
{
|
||||||
|
QString realName = this->getIContextNetwork()->getUserForCallsign(CCallsign(tabName)).getRealName();
|
||||||
|
if (!realName.isEmpty()) this->setTabToolTip(index, realName);
|
||||||
|
}
|
||||||
|
return newTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a private channel text message
|
||||||
|
*/
|
||||||
|
void CTextMessageComponent::addPrivateChannelTextMessage(const CTextMessage &textMessage, bool sending)
|
||||||
|
{
|
||||||
|
if (!textMessage.isPrivateMessage()) return;
|
||||||
|
CCallsign cs = sending ? textMessage.getRecipientCallsign() : textMessage.getSenderCallsign();
|
||||||
|
if (cs.isEmpty()) return;
|
||||||
|
QWidget *tab = this->findTextMessageTabByName(cs.getStringAsSet());
|
||||||
|
if (tab == nullptr) tab = this->findTextMessageTabByName(cs.asString());
|
||||||
|
if (tab == nullptr) tab = this->addNewTextMessageTab(cs.getStringAsSet());
|
||||||
|
Q_ASSERT(tab != nullptr);
|
||||||
|
QTextEdit *textEdit = tab->findChild<QTextEdit *>();
|
||||||
|
Q_ASSERT(textEdit != nullptr);
|
||||||
|
if (textEdit == nullptr) return; // do not crash, though this situation could not happen
|
||||||
|
textEdit->append(textMessage.asString(true, false, "\t"));
|
||||||
|
|
||||||
|
// sound
|
||||||
|
if (this->getIContextAudio())
|
||||||
|
this->getIContextAudio()->playNotification(BlackSound::CNotificationSounds::NotificationTextMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message tab by name
|
||||||
|
*/
|
||||||
|
QWidget *CTextMessageComponent::findTextMessageTabByName(const QString &name) const
|
||||||
|
{
|
||||||
|
if (name.isEmpty()) return nullptr;
|
||||||
|
QString n = name.trimmed();
|
||||||
|
for (int index = 0; index < this->count(); index++)
|
||||||
|
{
|
||||||
|
QString tabName = this->tabText(index);
|
||||||
|
if (tabName.indexOf(n, 0, Qt::CaseInsensitive) < 0) continue;
|
||||||
|
QWidget *tab = this->widget(index);
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text message stub (sender/receiver) for current channel
|
||||||
|
*/
|
||||||
|
CTextMessage CTextMessageComponent::getTextMessageStubForChannel()
|
||||||
|
{
|
||||||
|
CTextMessage tm;
|
||||||
|
int index = this->currentIndex();
|
||||||
|
if (index < 0) return tm;
|
||||||
|
if (index == this->indexOf(this->ui->tb_TextMessagesAll)) return tm;
|
||||||
|
|
||||||
|
// from
|
||||||
|
tm.setSenderCallsign(this->getOwnAircraft().getCallsign());
|
||||||
|
|
||||||
|
// frequency text message?
|
||||||
|
if (index == this->indexOf(this->ui->tb_TextMessagesCOM1))
|
||||||
|
{
|
||||||
|
tm.setFrequency(this->getOwnAircraft().getCom1System().getFrequencyActive());
|
||||||
|
}
|
||||||
|
else if (index == this->indexOf(this->ui->tb_TextMessagesCOM2))
|
||||||
|
{
|
||||||
|
tm.setFrequency(this->getOwnAircraft().getCom2System().getFrequencyActive());
|
||||||
|
}
|
||||||
|
else if (index == this->indexOf(this->ui->tb_TextMessagesUnicom))
|
||||||
|
{
|
||||||
|
tm.setFrequency(CPhysicalQuantitiesConstants::FrequencyUnicom());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not a standard channel
|
||||||
|
QString selectedTabText = this->tabText(index);
|
||||||
|
bool isNumber;
|
||||||
|
double frequency = selectedTabText.toDouble(&isNumber);
|
||||||
|
if (isNumber)
|
||||||
|
{
|
||||||
|
CFrequency radioFrequency = CFrequency(frequency, CFrequencyUnit::MHz());
|
||||||
|
if (CComSystem::isValidCivilAviationFrequency(radioFrequency))
|
||||||
|
{
|
||||||
|
tm.setFrequency(radioFrequency);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CCallsign toCallsign(selectedTabText);
|
||||||
|
tm.setRecipientCallsign(toCallsign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CCallsign toCallsign(selectedTabText);
|
||||||
|
tm.setRecipientCallsign(toCallsign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tm; // now valid message stub with receiver
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close message tab
|
||||||
|
*/
|
||||||
|
void CTextMessageComponent::closeTextMessageTab()
|
||||||
|
{
|
||||||
|
QObject *sender = QObject::sender();
|
||||||
|
QWidget *parentWidget = qobject_cast<QWidget *>(sender->parent());
|
||||||
|
Q_ASSERT(parentWidget);
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
while (index < 0 && parentWidget)
|
||||||
|
{
|
||||||
|
index = this->indexOf(parentWidget);
|
||||||
|
parentWidget = parentWidget->parentWidget();
|
||||||
|
}
|
||||||
|
if (index >= 0) this->removeTab(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextMessageComponent::showContextMenuForTextEdit(const QPoint &pt)
|
||||||
|
{
|
||||||
|
QObject *sender = QObject::sender();
|
||||||
|
this->m_currentTextEdit = qobject_cast<QTextEdit *>(sender);
|
||||||
|
Q_ASSERT(this->m_currentTextEdit);
|
||||||
|
|
||||||
|
QMenu *menu = this->m_currentTextEdit->createStandardContextMenu();
|
||||||
|
menu->setParent(this->m_currentTextEdit);
|
||||||
|
menu->setObjectName(this->m_currentTextEdit->objectName().append("_contextMenu"));
|
||||||
|
menu->addSeparator();
|
||||||
|
menu->addAction(this->m_clearTextEditAction);
|
||||||
|
menu->exec(this->m_currentTextEdit->mapToGlobal(pt));
|
||||||
|
delete menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTextMessageComponent::clearTextEdit()
|
||||||
|
{
|
||||||
|
if (!this->m_currentTextEdit) return;
|
||||||
|
this->m_currentTextEdit->clear();
|
||||||
|
this->m_currentTextEdit = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Command entered
|
||||||
|
*/
|
||||||
|
void CTextMessageComponent::commandEntered()
|
||||||
|
{
|
||||||
|
// 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")
|
||||||
|
{
|
||||||
|
if (!this->getIContextNetwork() || !this->getIContextNetwork()->isConnected())
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parts.length() < 3)
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect message"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString p = parts[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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QWidget *tab = this->findTextMessageTabByName(p.trimmed());
|
||||||
|
if (tab == nullptr) tab = this->addNewTextMessageTab(p.trimmed().toUpper());
|
||||||
|
this->setCurrentWidget(tab);
|
||||||
|
}
|
||||||
|
CTextMessage tm = this->getTextMessageStubForChannel();
|
||||||
|
int index = cmdLine.indexOf(tm.getRecipientCallsign().getStringAsSet(), 0, Qt::CaseInsensitive);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(
|
||||||
|
CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError,
|
||||||
|
"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
|
||||||
|
{
|
||||||
|
// single line, no command
|
||||||
|
// line is considered to be a message to the selected channel, send
|
||||||
|
if (!this->isNetworkConnected())
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "network needs to be connected"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->isVisible())
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeTrafficNetwork, CStatusMessage::SeverityError, "text messages can only be sent from corresponding page"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = this->currentIndex();
|
||||||
|
if (index < 0 || index == this->indexOf(this->ui->tb_TextMessagesAll))
|
||||||
|
{
|
||||||
|
this->sendStatusMessage(CStatusMessage(CStatusMessage::TypeValidation, CStatusMessage::SeverityError, "incorrect channel"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CTextMessage tm = this->getTextMessageStubForChannel();
|
||||||
|
tm.setMessage(cmdLine);
|
||||||
|
if (tm.isEmpty()) return;
|
||||||
|
if (!this->getIContextNetwork()) return;
|
||||||
|
CTextMessageList textMessageList(tm);
|
||||||
|
this->getIContextNetwork()->sendTextMessages(textMessageList);
|
||||||
|
this->appendTextMessagesToGui(textMessageList, true);
|
||||||
|
lineEdit->setText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
110
src/blackgui/textmessagecomponent.h
Normal file
110
src/blackgui/textmessagecomponent.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#ifndef BLACKGUI_TEXTMESSAGECOMPONENT_H
|
||||||
|
#define BLACKGUI_TEXTMESSAGECOMPONENT_H
|
||||||
|
|
||||||
|
#include "blackgui/runtimebasedcomponent.h"
|
||||||
|
#include "blackgui/timerbasedcomponent.h"
|
||||||
|
#include "blackmisc/nwtextmessage.h"
|
||||||
|
#include "blackmisc/avaircraft.h"
|
||||||
|
|
||||||
|
#include <QTabWidget>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QTextEdit>
|
||||||
|
|
||||||
|
namespace Ui { class CTextMessageComponent; }
|
||||||
|
namespace BlackGui
|
||||||
|
{
|
||||||
|
//! Text message widget
|
||||||
|
class CTextMessageComponent : public QTabWidget, public CRuntimeBasedComponent
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
//! Tabs
|
||||||
|
enum Tab
|
||||||
|
{
|
||||||
|
TextMessagesAll,
|
||||||
|
TextMessagesUnicom,
|
||||||
|
TextMessagesCom1,
|
||||||
|
TextMessagesCom2
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
explicit CTextMessageComponent(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
//! Destructor
|
||||||
|
~CTextMessageComponent();
|
||||||
|
|
||||||
|
//! Set tooltip
|
||||||
|
void setToolTip(const QString &tooltipText, Tab tab);
|
||||||
|
|
||||||
|
//! SELCAL callback, SELCAL is obtained by that
|
||||||
|
void setSelcalCallback(const std::function<const QString(void)> &selcalCallback) { this->m_selcalCallback = selcalCallback; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
//! Invisible text message
|
||||||
|
void displayOverlayInfo(const BlackMisc::CStatusMessage &message) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
//! Command entered
|
||||||
|
void commandEntered();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Append text messages (received, to be sent) to GUI
|
||||||
|
* \param messages
|
||||||
|
* \param sending
|
||||||
|
*/
|
||||||
|
void appendTextMessagesToGui(const BlackMisc::Network::CTextMessageList &messages, bool sending = false);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Add new text message tab
|
||||||
|
* \param tabName name of the new tab, usually the channel name
|
||||||
|
* \return
|
||||||
|
*/
|
||||||
|
QWidget *addNewTextMessageTab(const QString &tabName);
|
||||||
|
|
||||||
|
//! Find text message tab by its name
|
||||||
|
QWidget *findTextMessageTabByName(const QString &name) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Private channel text message
|
||||||
|
* \param textMessage
|
||||||
|
* \param sending sending or receiving
|
||||||
|
*/
|
||||||
|
void addPrivateChannelTextMessage(const BlackMisc::Network::CTextMessage &textMessage, bool sending = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Stub for sending a text message (eihter radio or private message).
|
||||||
|
* Sets sender / receiver depending on frequency / channel situation.
|
||||||
|
*/
|
||||||
|
BlackMisc::Network::CTextMessage getTextMessageStubForChannel();
|
||||||
|
|
||||||
|
//! own aircraft
|
||||||
|
const BlackMisc::Aviation::CAircraft getOwnAircraft() const { Q_ASSERT(this->getIContextNetwork()); return this->getIContextNetwork()->getOwnAircraft(); }
|
||||||
|
|
||||||
|
//! For this text message's recepient, is the current tab selected?
|
||||||
|
bool isCorrespondingTextMessageTabSelected(BlackMisc::Network::CTextMessage textMessage) const;
|
||||||
|
|
||||||
|
//! Network connected?
|
||||||
|
bool isNetworkConnected() const { return this->getIContextNetwork() && this->getIContextNetwork()->isConnected() ; }
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
//! Close text message tab
|
||||||
|
void closeTextMessageTab();
|
||||||
|
|
||||||
|
//! Context menu for text edit including clear
|
||||||
|
void showContextMenuForTextEdit(const QPoint &pt);
|
||||||
|
|
||||||
|
//! Clear text edit
|
||||||
|
void clearTextEdit();
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // guard
|
||||||
162
src/blackgui/textmessagecomponent.ui
Normal file
162
src/blackgui/textmessagecomponent.ui
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CTextMessageComponent</class>
|
||||||
|
<widget class="QTabWidget" name="CTextMessageComponent">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>580</width>
|
||||||
|
<height>375</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>TabWidget</string>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tb_TextMessagesAll">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>All</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vl_TextMessagesAll">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="te_TextMessagesAll">
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabStopWidth">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tb_TextMessagesUnicom">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>UNICOM</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vl_TextMessagesUnicom">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="te_TextMessagesUnicom">
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabStopWidth">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tb_TextMessagesCOM1">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>COM1</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vl_TextMessagesCOM1">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="te_TextMessagesCOM1">
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabStopWidth">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tb_TextMessagesCOM2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>COM2</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="vl_TextMessagesCOM2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="te_TextMessagesCOM2">
|
||||||
|
<property name="lineWrapMode">
|
||||||
|
<enum>QTextEdit::NoWrap</enum>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="tabStopWidth">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user