swift
textmessagetextedit.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QAction>
7 #include <QMenu>
8 #include <QScopedPointer>
9 #include <QStringBuilder>
10 #include <QTextDocument>
11 #include <QTextOption>
12 #include <Qt>
13 #include <QtGlobal>
14 
15 #include "gui/guiapplication.h"
16 #include "misc/aviation/callsign.h"
18 
19 using namespace swift::misc;
20 using namespace swift::misc::network;
21 
22 namespace swift::gui
23 {
24  CTextMessageTextEdit::CTextMessageTextEdit(QWidget *parent) : QTextEdit(parent)
25  {
26  this->setDocument(&m_textDocument);
27  this->setReadOnly(true);
28  this->setWordWrap(true);
29 
30  // menu
31  this->setContextMenuPolicy(Qt::CustomContextMenu);
32  m_actionClearTextEdit = new QAction(CIcon::iconByIndex(CIcons::StandardIconDelete16).toQIcon(), "Clear", this);
33  m_actionLast10 = new QAction("Keep last 10 messages", this);
34  m_actionLast25 = new QAction("Keep last 25 messages", this);
35  m_actionAll = new QAction("Keep all messages", this);
36  m_actionWithRecipient = new QAction("With recipient", this);
37  m_actionWithSender = new QAction("With sender", this);
38  m_actionWordWrap = new QAction("Word wrap", this);
39  m_actionWithRecipient->setCheckable(true);
40  m_actionWithSender->setCheckable(true);
41  m_actionWordWrap->setCheckable(true);
42 
43  connect(m_actionClearTextEdit, &QAction::triggered, this, &CTextMessageTextEdit::clear);
44  connect(m_actionAll, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
45  connect(m_actionLast10, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
46  connect(m_actionLast25, &QAction::triggered, this, &CTextMessageTextEdit::keepLastNMessages);
47  connect(m_actionWithSender, &QAction::triggered, this, &CTextMessageTextEdit::setVisibleFields);
48  connect(m_actionWithRecipient, &QAction::triggered, this, &CTextMessageTextEdit::setVisibleFields);
49  connect(m_actionWordWrap, &QAction::triggered, this, &CTextMessageTextEdit::setWordWrap);
50 
51  connect(this, &QTextEdit::customContextMenuRequested, this, &CTextMessageTextEdit::showContextMenuForTextEdit);
52  }
53 
55 
56  void CTextMessageTextEdit::insertTextMessage(const CTextMessage &textMessage, int maxMessages)
57  {
58  if (maxMessages < 0 && m_keepMaxMessages >= 0) { maxMessages = m_keepMaxMessages; }
59  if (maxMessages >= 0) { m_messages.push_backMaxElements(textMessage, maxMessages); }
60  else { m_messages.push_back(textMessage); }
61  this->redrawHtml();
62  }
63 
64  int CTextMessageTextEdit::count() const { return m_messages.size(); }
65 
67  {
68  m_messages.clear();
69  QTextEdit::clear();
70  }
71 
73  {
74  const QString html(
75  this->toHtml(m_latestFirst ? m_messages.reversed() : m_messages, m_withSender, m_withRecipient));
76  m_textDocument.setHtml(html);
77  this->moveCursor(m_latestFirst ? QTextCursor::Start : QTextCursor::End);
78  }
79 
80  void CTextMessageTextEdit::setStyleSheetForContent(const QString &styleSheet)
81  {
82  m_textDocument.setDefaultStyleSheet(styleSheet);
83  this->redrawHtml();
84  }
85 
86  QString CTextMessageTextEdit::toHtml(const CTextMessageList &messages, bool withFrom, bool withTo)
87  {
88  if (messages.isEmpty()) { return {}; }
89  QString html("<table>");
90  for (const CTextMessage &msg : messages) { html += CTextMessageTextEdit::toHtml(msg, withFrom, withTo); }
91  html += "</table>";
92  return html;
93  }
94 
95  QString CTextMessageTextEdit::toHtml(const CTextMessage &message, bool withFrom, bool withTo)
96  {
97  QString rowClass(message.wasSent() ? "sent" : "received");
98  if (message.isSupervisorMessage()) { rowClass += " supervisor"; }
99 
100  QString html(u"<tr class=\"" % rowClass.trimmed() % u"\"><td class=\"timestamp\">" %
101  message.getFormattedUtcTimestampHms() % u"</td>");
102 
103  if (withFrom) { html += u"<td class=\"sender\">" % message.getSenderCallsign().asString() % u"</td>"; }
104 
105  if (withTo) { html += u"<td class=\"recipient\">" % message.getRecipientCallsignOrFrequency() % u"</td>"; }
106 
107  html += u"<td class=\"message\">" % message.getHtmlEncodedMessage() % u"</td></tr>";
108  return html;
109  }
110 
111  void CTextMessageTextEdit::showContextMenuForTextEdit(const QPoint &pt)
112  {
113  m_actionWithRecipient->setChecked(m_withRecipient);
114  m_actionWithSender->setChecked(m_withSender);
115  m_actionWordWrap->setChecked(m_wordWrap);
116 
117  QScopedPointer<QMenu> menu(this->createStandardContextMenu());
118  menu->setObjectName(this->objectName().append("_contextMenu"));
119  menu->addSeparator();
120  menu->addAction(m_actionWordWrap);
121  QMenu *subMenu = menu->addMenu("Max.messages");
122  subMenu->addAction(m_actionLast10);
123  subMenu->addAction(m_actionLast25);
124  subMenu->addAction(m_actionAll);
125  subMenu = menu->addMenu("Fields");
126  subMenu->addAction(m_actionWithSender);
127  subMenu->addAction(m_actionWithRecipient);
128  menu->addAction(m_actionClearTextEdit);
129  menu->exec(this->mapToGlobal(pt));
130  }
131 
132  void CTextMessageTextEdit::keepLastNMessages()
133  {
134  QObject *sender = QObject::sender();
135  if (sender == m_actionAll) { m_keepMaxMessages = -1; }
136  else if (sender == m_actionLast10) { m_keepMaxMessages = 10; }
137  else if (sender == m_actionLast25) { m_keepMaxMessages = 25; }
138  }
139 
140  void CTextMessageTextEdit::setVisibleFields()
141  {
142  QObject *sender = QObject::sender();
143  if (sender == m_actionWithRecipient) { m_withRecipient = m_actionWithRecipient->isChecked(); }
144  else if (sender == m_actionWithSender) { m_withSender = m_actionWithSender->isChecked(); }
145  }
146 
147  void CTextMessageTextEdit::setWordWrap(bool wordWrap)
148  {
149  m_wordWrap = wordWrap;
150  if (m_wordWrap) { this->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); }
151  else { this->setWordWrapMode(QTextOption::NoWrap); }
152  }
153 } // namespace swift::gui
void insertTextMessage(const swift::misc::network::CTextMessage &textMessage, int maxMessages=-1)
Insert a message.
virtual ~CTextMessageTextEdit()
Destructor.
void setStyleSheetForContent(const QString &styleSheet)
Stylesheet for content.
int count() const
Number of displayed messages.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
void clear()
Removes all elements in the sequence.
Definition: sequence.h:288
Q_REQUIRED_RESULT CSequence reversed() const
Reversed order.
Definition: sequence.h:551
void push_backMaxElements(const T &value, int maxElements)
Insert as last element by keep maxElements.
Definition: sequence.h:322
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
QString getFormattedUtcTimestampHms() const
As hh:mm:ss.
const QString & asString() const
Get callsign (normalized)
Definition: callsign.h:96
Value object encapsulating information of a text message.
Definition: textmessage.h:31
QString getHtmlEncodedMessage() const
Get HTML escaped message.
QString getRecipientCallsignOrFrequency() const
Get recipient or frequency.
bool wasSent() const
Was sent?
Definition: textmessage.h:146
const aviation::CCallsign & getSenderCallsign() const
Get callsign (from)
Definition: textmessage.h:54
bool isSupervisorMessage() const
Supervisor message?
Definition: textmessage.cpp:58
Value object encapsulating a list of text messages.
GUI related classes.
Free functions in swift::misc.