qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
groupchatform.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2014-2019 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "groupchatform.h"
21 
22 #include "tabcompleter.h"
23 #include "src/core/core.h"
24 #include "src/core/coreav.h"
25 #include "src/core/groupid.h"
26 #include "src/chatlog/chatwidget.h"
28 #include "src/model/friend.h"
29 #include "src/friendlist.h"
30 #include "src/model/group.h"
32 #include "src/widget/flowlayout.h"
34 #include "src/widget/groupwidget.h"
36 #include "src/widget/style.h"
38 #include "src/widget/translator.h"
40 
41 #include <QDragEnterEvent>
42 #include <QMimeData>
43 #include <QRegularExpression>
44 #include <QTimer>
45 #include <QToolButton>
46 #include <QPushButton>
47 
48 namespace
49 {
50 const auto LABEL_PEER_TYPE_OUR = QVariant(QStringLiteral("our"));
51 const auto LABEL_PEER_TYPE_MUTED = QVariant(QStringLiteral("muted"));
52 const auto LABEL_PEER_PLAYING_AUDIO = QVariant(QStringLiteral("true"));
53 const auto LABEL_PEER_NOT_PLAYING_AUDIO = QVariant(QStringLiteral("false"));
54 const auto PEER_LABEL_STYLE_SHEET_PATH = QStringLiteral("chatArea/chatHead.css");
55 }
56 
63 QString editName(const QString& name)
64 {
65  const int pos = name.indexOf(QRegularExpression(QStringLiteral("[\n\r]")));
66  if (pos == -1) {
67  return name;
68  }
69 
70  QString result = name;
71  const int len = result.length();
72  result.chop(len - pos);
73  result.append(QStringLiteral("…")); // \u2026 Unicode symbol, not just three separate dots
74  return result;
75 }
76 
85 GroupChatForm::GroupChatForm(Core& _core, Group* chatGroup, IChatLog& chatLog, IMessageDispatcher& messageDispatcher, IGroupSettings& _settings)
86  : GenericChatForm(_core, chatGroup, chatLog, messageDispatcher)
87  , core{_core}
88  , group(chatGroup)
89  , inCall(false)
90  , settings(_settings)
91 {
92  nusersLabel = new QLabel();
93 
94  tabber = new TabCompleter(msgEdit, group);
95 
96  fileButton->setEnabled(false);
97  fileButton->setProperty("state", "");
98  ChatFormHeader::Mode mode = ChatFormHeader::Mode::None;
99  if (group->isAvGroupchat()) {
100  mode = ChatFormHeader::Mode::Audio;
101  }
102 
103  headWidget->setMode(mode);
104  setName(group->getName());
105 
106  nusersLabel->setFont(Style::getFont(Style::Medium));
107  nusersLabel->setObjectName("statusLabel");
108  retranslateUi();
109 
110  const QSize& size = headWidget->getAvatarSize();
111  headWidget->setAvatar(Style::scaleSvgImage(":/img/group_dark.svg", size.width(), size.height()));
112 
113  msgEdit->setObjectName("group");
114 
115  namesListLayout = new FlowLayout(0, 5, 0);
116  headWidget->addWidget(nusersLabel);
117  headWidget->addLayout(namesListLayout);
118  headWidget->addStretch();
119 
120  //nameLabel->setMinimumHeight(12);
121  nusersLabel->setMinimumHeight(12);
122 
123  connect(msgEdit, &ChatTextEdit::tabPressed, tabber, &TabCompleter::complete);
124  connect(msgEdit, &ChatTextEdit::keyPressed, tabber, &TabCompleter::reset);
125  connect(headWidget, &ChatFormHeader::callTriggered, this, &GroupChatForm::onCallClicked);
128  connect(headWidget, &ChatFormHeader::nameChanged, chatGroup, &Group::setName);
129  connect(group, &Group::titleChanged, this, &GroupChatForm::onTitleChanged);
130  connect(group, &Group::userJoined, this, &GroupChatForm::onUserJoined);
131  connect(group, &Group::userLeft, this, &GroupChatForm::onUserLeft);
134  settings.connectTo_blackListChanged(this, [this](QStringList const&) { this->updateUserNames(); });
135 
136  updateUserNames();
137  setAcceptDrops(true);
139 }
140 
142 {
144 }
145 
146 void GroupChatForm::onTitleChanged(const QString& author, const QString& title)
147 {
148  if (author.isEmpty()) {
149  return;
150  }
151 
152  const QDateTime curTime = QDateTime::currentDateTime();
153  addSystemInfoMessage(curTime, SystemMessageType::titleChanged, {author, title});
154 }
155 
157 {
158  // Unsupported
159 }
160 
162 {
163  // Unsupported
164 }
165 
170 {
171  QLayoutItem* child;
172  while ((child = namesListLayout->takeAt(0))) {
173  child->widget()->hide();
174  delete child->widget();
175  delete child;
176  }
177 
178  peerLabels.clear();
179  const auto peers = group->getPeerList();
180 
181  // no need to do anything without any peers
182  if (peers.isEmpty()) {
183  return;
184  }
185 
186  /* we store the peer labels by their ToxPk, but the namelist layout
187  * needs it in alphabetical order, so we first create and store the labels
188  * and then sort them by their text and add them to the layout in that order */
189  const auto selfPk = core.getSelfPublicKey();
190  for (const auto& peerPk : peers.keys()) {
191  const QString peerName = peers.value(peerPk);
192  const QString editedName = editName(peerName);
193  QLabel* const label = new QLabel(editedName + QLatin1String(", "));
194  if (editedName != peerName) {
195  label->setToolTip(peerName + " (" + peerPk.toString() + ")");
196  } else if (peerName != peerPk.toString()) {
197  label->setToolTip(peerPk.toString());
198  } // else their name is just their Pk, no tooltip needed
199  label->setTextFormat(Qt::PlainText);
200  label->setContextMenuPolicy(Qt::CustomContextMenu);
201 
202  connect(label, &QLabel::customContextMenuRequested, this, &GroupChatForm::onLabelContextMenuRequested);
203 
204  if (peerPk == selfPk) {
205  label->setProperty("peerType", LABEL_PEER_TYPE_OUR);
206  } else if (settings.getBlackList().contains(peerPk.toString())) {
207  label->setProperty("peerType", LABEL_PEER_TYPE_MUTED);
208  }
209 
210  label->setStyleSheet(Style::getStylesheet(PEER_LABEL_STYLE_SHEET_PATH));
211  peerLabels.insert(peerPk, label);
212  }
213 
214  // add the labels in alphabetical order into the layout
215  auto nickLabelList = peerLabels.values();
216 
217  std::sort(nickLabelList.begin(), nickLabelList.end(), [](const QLabel* a, const QLabel* b)
218  {
219  return a->text().toLower() < b->text().toLower();
220  });
221 
222  // remove comma from last sorted label
223  QLabel* const lastLabel = nickLabelList.last();
224  QString labelText = lastLabel->text();
225  labelText.chop(2);
226  lastLabel->setText(labelText);
227  for (QLabel* l : nickLabelList) {
228  namesListLayout->addWidget(l);
229  }
230 }
231 
232 void GroupChatForm::onUserJoined(const ToxPk& user, const QString& name)
233 {
235  addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::userJoinedGroup, {name});
236  }
237  updateUserNames();
238 }
239 
240 void GroupChatForm::onUserLeft(const ToxPk& user, const QString& name)
241 {
243  addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::userLeftGroup, {name});
244  }
245  updateUserNames();
246 }
247 
248 void GroupChatForm::onPeerNameChanged(const ToxPk& peer, const QString& oldName, const QString& newName)
249 {
250  addSystemInfoMessage(QDateTime::currentDateTime(), SystemMessageType::peerNameChanged,
251  {oldName, newName});
252  updateUserNames();
253 }
254 
256 {
257  peerLabels[peerPk]->setProperty("playingAudio", LABEL_PEER_PLAYING_AUDIO);
258  peerLabels[peerPk]->style()->unpolish(peerLabels[peerPk]);
259  peerLabels[peerPk]->style()->polish(peerLabels[peerPk]);
260  // TODO(sudden6): check if this can ever be false, cause [] default constructs
261  if (!peerAudioTimers[peerPk]) {
262  peerAudioTimers[peerPk] = new QTimer(this);
263  peerAudioTimers[peerPk]->setSingleShot(true);
264  connect(peerAudioTimers[peerPk], &QTimer::timeout, [this, peerPk] {
265  auto it = peerLabels.find(peerPk);
266  if (it != peerLabels.end()) {
267  peerLabels[peerPk]->setProperty("playingAudio", LABEL_PEER_NOT_PLAYING_AUDIO);
268  peerLabels[peerPk]->style()->unpolish(peerLabels[peerPk]);
269  peerLabels[peerPk]->style()->polish(peerLabels[peerPk]);
270  }
271  delete peerAudioTimers[peerPk];
272  peerAudioTimers[peerPk] = nullptr;
273  });
274  }
275 
276  peerLabels[peerPk]->setStyleSheet(Style::getStylesheet(PEER_LABEL_STYLE_SHEET_PATH));
277  peerAudioTimers[peerPk]->start(500);
278 }
279 
280 void GroupChatForm::dragEnterEvent(QDragEnterEvent* ev)
281 {
282  if (!ev->mimeData()->hasFormat("toxPk")) {
283  return;
284  }
285  ToxPk toxPk{ev->mimeData()->data("toxPk")};
286  Friend* frnd = FriendList::findFriend(toxPk);
287  if (frnd)
288  ev->acceptProposedAction();
289 }
290 
291 void GroupChatForm::dropEvent(QDropEvent* ev)
292 {
293  if (!ev->mimeData()->hasFormat("toxPk")) {
294  return;
295  }
296  ToxPk toxPk{ev->mimeData()->data("toxPk")};
297  Friend* frnd = FriendList::findFriend(toxPk);
298  if (!frnd)
299  return;
300 
301  int friendId = frnd->getId();
302  int groupId = group->getId();
303  if (Status::isOnline(frnd->getStatus())) {
304  core.groupInviteFriend(friendId, groupId);
305  }
306 }
307 
309 {
310  if (audioInputFlag) {
311  CoreAV* av = core.getAv();
312  const bool oldMuteState = av->isGroupCallInputMuted(group);
313  const bool newMute = !oldMuteState;
314  av->muteCallInput(group, newMute);
316  }
317 }
318 
320 {
321  if (audioOutputFlag) {
322  CoreAV* av = core.getAv();
323  const bool oldMuteState = av->isGroupCallOutputMuted(group);
324  const bool newMute = !oldMuteState;
325  av->muteCallOutput(group, newMute);
327  }
328 }
329 
331 {
332  CoreAV* av = core.getAv();
333 
334  if (!inCall) {
335  joinGroupCall();
336  } else {
337  leaveGroupCall();
338  }
339 
341 
342  const bool inMute = av->isGroupCallInputMuted(group);
344 
345  const bool outMute = av->isGroupCallOutputMuted(group);
347 }
348 
349 void GroupChatForm::keyPressEvent(QKeyEvent* ev)
350 {
351  // Push to talk (CTRL+P)
352  if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
353  onMicMuteToggle();
354  }
355 
356  if (msgEdit->hasFocus())
357  return;
358 }
359 
361 {
362  // Push to talk (CTRL+P)
363  if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall) {
364  onMicMuteToggle();
365  }
366 
367  if (msgEdit->hasFocus())
368  return;
369 }
370 
375 {
376  nusersLabel->setText(tr("%n user(s) in chat", "Number of users in chat", numPeers));
378 }
379 
381 {
383 }
384 
385 void GroupChatForm::onLabelContextMenuRequested(const QPoint& localPos)
386 {
387  QLabel* label = static_cast<QLabel*>(QObject::sender());
388 
389  if (label == nullptr) {
390  return;
391  }
392 
393  const QPoint pos = label->mapToGlobal(localPos);
394  const QString muteString = tr("mute");
395  const QString unmuteString = tr("unmute");
396  QStringList blackList = settings.getBlackList();
397  QMenu* const contextMenu = new QMenu(this);
398  const ToxPk selfPk = core.getSelfPublicKey();
399  ToxPk peerPk;
400 
401  // delete menu after it stops being used
402  connect(contextMenu, &QMenu::aboutToHide, contextMenu, &QObject::deleteLater);
403 
404  peerPk = peerLabels.key(label);
405  if (peerPk.isEmpty() || peerPk == selfPk) {
406  return;
407  }
408 
409  const bool isPeerBlocked = blackList.contains(peerPk.toString());
410  QString menuTitle = label->text();
411  if (menuTitle.endsWith(QLatin1String(", "))) {
412  menuTitle.chop(2);
413  }
414  QAction* menuTitleAction = contextMenu->addAction(menuTitle);
415  menuTitleAction->setEnabled(false); // make sure the title is not clickable
416  contextMenu->addSeparator();
417 
418  const QAction* toggleMuteAction;
419  if (isPeerBlocked) {
420  toggleMuteAction = contextMenu->addAction(unmuteString);
421  } else {
422  toggleMuteAction = contextMenu->addAction(muteString);
423  }
424  contextMenu->setStyleSheet(Style::getStylesheet(PEER_LABEL_STYLE_SHEET_PATH));
425 
426  const QAction* selectedItem = contextMenu->exec(pos);
427  if (selectedItem == toggleMuteAction) {
428  if (isPeerBlocked) {
429  const int index = blackList.indexOf(peerPk.toString());
430  if (index != -1) {
431  blackList.removeAt(index);
432  }
433  } else {
434  blackList << peerPk.toString();
435  }
436 
437  settings.setBlackList(blackList);
438  }
439 }
440 
442 {
443  CoreAV* av = core.getAv();
444  av->joinGroupCall(*group);
445  audioInputFlag = true;
446  audioOutputFlag = true;
447  inCall = true;
448 }
449 
451 {
452  CoreAV* av = core.getAv();
453  av->leaveGroupCall(group->getId());
454  audioInputFlag = false;
455  audioOutputFlag = false;
456  inCall = false;
457 }
Style::getFont
static QFont getFont(Font font)
Definition: style.cpp:214
GroupChatForm::nusersLabel
QLabel * nusersLabel
Definition: groupchatform.h:80
GroupChatForm::onPeerNameChanged
void onPeerNameChanged(const ToxPk &peer, const QString &oldName, const QString &newName)
Definition: groupchatform.cpp:248
ChatFormHeader::Mode
Mode
Definition: chatformheader.h:54
GenericChatForm::audioOutputFlag
bool audioOutputFlag
Definition: genericchatform.h:133
style.h
GenericChatForm
Parent class for all chatforms. It's provide the minimum required UI elements and methods to work wit...
Definition: genericchatform.h:67
friend.h
GroupChatForm::joinGroupCall
void joinGroupCall()
Definition: groupchatform.cpp:441
friendlist.h
chatwidget.h
Group::getPeerList
const QMap< ToxPk, QString > & getPeerList() const
Gets the PKs and names of all peers.
Definition: group.cpp:159
GroupChatForm::retranslateUi
void retranslateUi()
Definition: groupchatform.cpp:380
GroupChatForm::core
Core & core
Definition: groupchatform.h:75
Core::getSelfPublicKey
ToxPk getSelfPublicKey() const override
Gets self public key.
Definition: core.cpp:1271
GroupChatForm::onTitleChanged
void onTitleChanged(const QString &author, const QString &title)
Definition: groupchatform.cpp:146
ContactId::isEmpty
bool isEmpty() const
Checks if the ContactId contains a id.
Definition: contactid.cpp:110
GroupChatForm::onAttachClicked
void onAttachClicked() override
Definition: groupchatform.cpp:161
FlowLayout::takeAt
QLayoutItem * takeAt(int index)
Definition: flowlayout.cpp:97
ChatFormHeader::volMuteToggle
void volMuteToggle()
IGroupSettings
Definition: igroupsettings.h:26
group.h
GroupChatForm::peerAudioPlaying
void peerAudioPlaying(ToxPk peerPk)
Definition: groupchatform.cpp:255
Group::titleChanged
void titleChanged(const QString &author, const QString &title)
Group::getPeersCount
int getPeersCount() const
Definition: group.cpp:150
GroupChatForm::dragEnterEvent
void dragEnterEvent(QDragEnterEvent *ev) final
Definition: groupchatform.cpp:280
GroupChatForm::onUserLeft
void onUserLeft(const ToxPk &user, const QString &name)
Definition: groupchatform.cpp:240
GenericChatForm::headWidget
ChatFormHeader * headWidget
Definition: genericchatform.h:154
GroupChatForm::dropEvent
void dropEvent(QDropEvent *ev) final
Definition: groupchatform.cpp:291
GroupChatForm::onUserJoined
void onUserJoined(const ToxPk &user, const QString &name)
Definition: groupchatform.cpp:232
Translator::unregister
static void unregister(void *owner)
Unregisters all handlers of an owner.
Definition: translator.cpp:103
GroupChatForm::updateUserNames
void updateUserNames()
Updates user names' labels at the top of group chat.
Definition: groupchatform.cpp:169
GroupChatForm::keyReleaseEvent
void keyReleaseEvent(QKeyEvent *ev) final
Definition: groupchatform.cpp:360
ChatFormHeader::micMuteToggle
void micMuteToggle()
GroupChatForm::onMicMuteToggle
void onMicMuteToggle()
Definition: groupchatform.cpp:308
ChatFormHeader::updateMuteMicButton
void updateMuteMicButton(bool active, bool inputMuted)
Definition: chatformheader.cpp:269
GroupChatForm::group
Group * group
Definition: groupchatform.h:76
ChatFormHeader::updateMuteVolButton
void updateMuteVolButton(bool active, bool outputMuted)
Definition: chatformheader.cpp:281
IMessageDispatcher
Definition: imessagedispatcher.h:34
Group::numPeersChanged
void numPeersChanged(int numPeers)
IChatLog
Definition: ichatlog.h:83
Group::getId
uint32_t getId() const override
Definition: group.cpp:140
Core::getAv
const CoreAV * getAv() const
Definition: core.cpp:703
FlowLayout
Definition: flowlayout.h:46
FriendList::findFriend
static Friend * findFriend(const ToxPk &friendPk)
Definition: friendlist.cpp:47
Group::userJoined
void userJoined(const ToxPk &user, const QString &name)
ChatTextEdit::tabPressed
void tabPressed()
croppinglabel.h
FileTransferList::Column::size
@ size
coreav.h
IGroupSettings::getBlackList
virtual QStringList getBlackList() const =0
chatform.h
TabCompleter::complete
void complete()
Definition: tabcompleter.cpp:90
Friend::getStatus
Status::Status getStatus() const
Definition: friend.cpp:190
GroupChatForm::peerAudioTimers
QMap< ToxPk, QTimer * > peerAudioTimers
Timeout = peer stopped sending audio.
Definition: groupchatform.h:78
IGroupSettings::getShowGroupJoinLeaveMessages
virtual bool getShowGroupJoinLeaveMessages() const =0
flowlayout.h
SystemMessageType::titleChanged
@ titleChanged
groupchatform.h
ChatFormHeader::updateCallButtons
void updateCallButtons(bool online, bool audio, bool video=false)
Definition: chatformheader.cpp:242
ToxPk
This class represents a Tox Public Key, which is a part of Tox ID.
Definition: toxpk.h:26
Friend
Definition: friend.h:31
Group::peerNameChanged
void peerNameChanged(const ToxPk &peer, const QString &oldName, const QString &newName)
text.h
SystemMessageType::peerNameChanged
@ peerNameChanged
maskablepixmapwidget.h
GroupChatForm::inCall
bool inCall
Definition: groupchatform.h:82
CoreAV::muteCallOutput
void muteCallOutput(const Group *g, bool mute)
Mutes or unmutes the group call's output (speaker).
Definition: coreav.cpp:620
SystemMessageType::userJoinedGroup
@ userJoinedGroup
TabCompleter
Definition: tabcompleter.h:30
Translator::registerHandler
static void registerHandler(const std::function< void()> &, void *owner)
Register a function to be called when the UI needs to be retranslated.
Definition: translator.cpp:93
CoreAV::leaveGroupCall
void leaveGroupCall(int groupNum)
Will not leave the group, just stop the call.
Definition: coreav.cpp:571
CoreAV::isGroupCallInputMuted
bool isGroupCallInputMuted(const Group *g) const
Returns the group calls input (microphone) state.
Definition: coreav.cpp:635
GroupChatForm::peerLabels
QMap< ToxPk, QLabel * > peerLabels
Maps peernumbers to the QLabels in namesListLayout.
Definition: groupchatform.h:77
groupid.h
IGroupSettings::setBlackList
virtual void setBlackList(const QStringList &blist)=0
Group
Definition: group.h:34
GroupChatForm::keyPressEvent
void keyPressEvent(QKeyEvent *ev) final
Definition: groupchatform.cpp:349
GroupChatForm::onScreenshotClicked
void onScreenshotClicked() override
Definition: groupchatform.cpp:156
tabcompleter.h
ChatTextEdit::keyPressed
void keyPressed()
GroupChatForm::settings
IGroupSettings & settings
Definition: groupchatform.h:83
CoreAV::muteCallInput
void muteCallInput(const Group *g, bool mute)
Mutes or unmutes the group call's input (microphone).
Definition: coreav.cpp:605
CoreAV::isGroupCallOutputMuted
bool isGroupCallOutputMuted(const Group *g) const
Returns the group calls output (speaker) state.
Definition: coreav.cpp:653
Style::getStylesheet
static const QString getStylesheet(const QString &filename, const QFont &baseFont=QFont())
Definition: style.cpp:165
TabCompleter::reset
void reset()
Definition: tabcompleter.cpp:126
GenericChatForm::msgEdit
ChatTextEdit * msgEdit
Definition: genericchatform.h:159
CoreAV::joinGroupCall
void joinGroupCall(const Group &group)
Starts a call in an existing AV groupchat.
Definition: coreav.cpp:545
ChatFormHeader::callTriggered
void callTriggered()
Group::setName
void setName(const QString &newTitle) override
Definition: group.cpp:51
GroupChatForm::leaveGroupCall
void leaveGroupCall()
Definition: groupchatform.cpp:450
GroupChatForm::onVolMuteToggle
void onVolMuteToggle()
Definition: groupchatform.cpp:319
core.h
GenericChatForm::audioInputFlag
bool audioInputFlag
Definition: genericchatform.h:132
ContactId::toString
QString toString() const
Converts the ContactId to a uppercase hex string.
Definition: contactid.cpp:78
GroupChatForm::onLabelContextMenuRequested
void onLabelContextMenuRequested(const QPoint &localPos)
Definition: groupchatform.cpp:385
ChatFormHeader::nameChanged
void nameChanged(const QString &name)
Friend::getId
uint32_t getId() const override
Definition: friend.cpp:136
Style::scaleSvgImage
static QPixmap scaleSvgImage(const QString &path, uint32_t width, uint32_t height)
Definition: style.cpp:381
Status::isOnline
bool isOnline(Status status)
Definition: status.cpp:83
translator.h
SystemMessageType::userLeftGroup
@ userLeftGroup
Style::Medium
@ Medium
Definition: style.h:59
GroupChatForm::onCallClicked
void onCallClicked()
Definition: groupchatform.cpp:330
groupwidget.h
GroupChatForm::~GroupChatForm
~GroupChatForm()
Definition: groupchatform.cpp:141
GroupChatForm::updateUserCount
void updateUserCount(int numPeers)
Updates users' count label text.
Definition: groupchatform.cpp:374
chatformheader.h
CoreAV
Definition: coreav.h:47
Core::groupInviteFriend
void groupInviteFriend(uint32_t friendId, int groupId)
Definition: core.cpp:1650
GenericChatForm::addSystemInfoMessage
void addSystemInfoMessage(const QDateTime &datetime, SystemMessageType messageType, SystemMessage::Args messageArgs)
Definition: genericchatform.cpp:500
GroupChatForm::namesListLayout
FlowLayout * namesListLayout
Definition: groupchatform.h:79
GroupChatForm::GroupChatForm
GroupChatForm(Core &_core, Group *chatGroup, IChatLog &chatLog, IMessageDispatcher &messageDispatcher, IGroupSettings &_settings)
Definition: groupchatform.cpp:85
editName
QString editName(const QString &name)
Edit name for correct representation if it is needed.
Definition: groupchatform.cpp:63
Core
Definition: core.h:59
igroupsettings.h
Group::userLeft
void userLeft(const ToxPk &user, const QString &name)