23 #include "application.h"
24 #include "gui/commongui.h"
25 #include "gui/irc/ircignoresmanager.h"
26 #include "gui/irc/ircsounds.h"
27 #include "gui/irc/ircuserlistmodel.h"
28 #include "irc/chatlogrotate.h"
29 #include "irc/chatlogs.h"
30 #include "irc/configuration/chatlogscfg.h"
31 #include "irc/configuration/ircconfig.h"
32 #include "irc/entities/ircnetworkentity.h"
33 #include "irc/ircchanneladapter.h"
34 #include "irc/ircdock.h"
35 #include "irc/ircglobal.h"
36 #include "irc/ircmessageclass.h"
37 #include "irc/ircnetworkadapter.h"
38 #include "irc/ircnicknamecompleter.h"
39 #include "irc/ircuserinfo.h"
40 #include "irc/ircuserlist.h"
41 #include "irc/ops/ircdelayedoperationignore.h"
42 #include "ircdocktabcontents.h"
44 #include "ui_ircdocktabcontents.h"
51 #include <QStandardItemModel>
55 const int IRCDockTabContents::BLINK_TIMER_DELAY_MS = 650;
57 DClass<IRCDockTabContents> :
public Ui::IRCDockTabContents
61 QDateTime lastMessageDate;
81 QStringList textOutputContents;
82 ::IRCDockTabContents::UserListMenu *userListContextMenu;
104 QAction *openChatWindow;
111 IRCDockTabContents::IRCDockTabContents(
IRCDock *pParentIRCDock)
114 d->lastMessageDate = QDateTime::currentDateTime();
116 d->bBlinkTitle =
false;
117 d->bIsDestroying =
false;
118 d->lastMessageClass =
nullptr;
119 d->userListContextMenu =
nullptr;
120 this->pIrcAdapter =
nullptr;
122 this->pParentIRCDock = pParentIRCDock;
125 d->txtOutputWidget->setContextMenuPolicy(Qt::CustomContextMenu);
126 setupNewUserListModel();
130 d->lvUserList->setVisible(
false);
132 this->connect(d->btnSend, SIGNAL(clicked()), SLOT(sendMessage()));
133 this->connect(d->leCommandLine, SIGNAL(returnPressed()), SLOT(sendMessage()));
134 this->connect(gApp, SIGNAL(focusChanged(QWidget*,QWidget*)),
135 SLOT(onFocusChanged(QWidget*,QWidget*)));
139 d->blinkTimer.setSingleShot(
false);
140 this->connect(&d->blinkTimer, SIGNAL(timeout()),
141 SLOT(blinkTimerSlot()));
147 IRCDockTabContents::~IRCDockTabContents()
149 d->bIsDestroying =
true;
151 if (d->lastMessageClass !=
nullptr)
152 delete d->lastMessageClass;
154 if (d->userListContextMenu !=
nullptr)
155 delete d->userListContextMenu;
157 if (pIrcAdapter !=
nullptr)
159 disconnect(pIrcAdapter,
nullptr,
nullptr,
nullptr);
161 pIrcAdapter =
nullptr;
166 void IRCDockTabContents::adapterFocusRequest()
171 void IRCDockTabContents::adapterTerminating()
173 if (pIrcAdapter !=
nullptr && !d->bIsDestroying)
176 disconnect(pIrcAdapter,
nullptr,
nullptr,
nullptr);
177 pIrcAdapter =
nullptr;
183 void IRCDockTabContents::alertIfConfigured()
185 if (gIRCConfig.appearance.windowAlertOnImportantChatEvent)
186 QApplication::alert(gApp->mainWindowAsQWidget());
191 const static QString STYLE_SHEET_BASE_TEMPLATE =
192 "QListView, QTextEdit, QLineEdit { background: %1; color: %2; } ";
196 QString qtStyleSheet = STYLE_SHEET_BASE_TEMPLATE
197 .arg(appearance.backgroundColor)
198 .arg(appearance.defaultTextColor);
200 QColor colorSelectedText(appearance.userListSelectedTextColor);
201 QColor colorSelectedBackground(appearance.userListSelectedBackgroundColor);
202 qtStyleSheet += QString(
"QListView::item:selected { color: %1; background: %2; } ").arg(colorSelectedText.name(), colorSelectedBackground.name());
204 QColor colorHoverText = colorSelectedText.lighter();
205 QColor colorHoverBackground = colorSelectedBackground.lighter();
206 qtStyleSheet += QString(
"QListView::item:hover { color: %1; background: %2; } ").arg(colorHoverText.name(), colorHoverBackground.name());
208 QString channelActionClassName = IRCMessageClass::toStyleSheetClassName(IRCMessageClass::ChannelAction);
209 QString ctcpClassName = IRCMessageClass::toStyleSheetClassName(IRCMessageClass::Ctcp);
210 QString errorClassName = IRCMessageClass::toStyleSheetClassName(IRCMessageClass::Error);
211 QString networkActionClassName = IRCMessageClass::toStyleSheetClassName(IRCMessageClass::NetworkAction);
213 QString htmlStyleSheetMessageArea =
"";
214 htmlStyleSheetMessageArea +=
"span { white-space: pre; }";
215 htmlStyleSheetMessageArea += QString(
"a { color: %1; white-space: pre; } ").arg(appearance.urlColor);
216 htmlStyleSheetMessageArea += QString(
"." + channelActionClassName +
" { color: %1; } ").arg(appearance.channelActionColor);
217 htmlStyleSheetMessageArea += QString(
"." + ctcpClassName +
" { color: %1; } ").arg(appearance.ctcpColor);
218 htmlStyleSheetMessageArea += QString(
"." + errorClassName +
" { color: %1; } ").arg(appearance.errorColor);
219 htmlStyleSheetMessageArea += QString(
"." + networkActionClassName +
" { color: %1; } ").arg(appearance.networkActionColor);
221 d->lvUserList->setStyleSheet(qtStyleSheet);
222 d->lvUserList->setFont(appearance.userListFont);
224 d->leCommandLine->installEventFilter(
this);
225 d->leCommandLine->setStyleSheet(qtStyleSheet);
226 d->leCommandLine->setFont(appearance.mainFont);
228 d->txtOutputWidget->setStyleSheet(qtStyleSheet);
229 d->txtOutputWidget->setFont(appearance.mainFont);
231 d->txtOutputWidget->document()->setDefaultStyleSheet(htmlStyleSheetMessageArea);
232 d->txtOutputWidget->clear();
233 d->txtOutputWidget->insertHtml(d->textOutputContents.join(
""));
234 d->txtOutputWidget->moveCursor(QTextCursor::End);
237 void IRCDockTabContents::blinkTimerSlot()
239 setBlinkTitle(!d->bBlinkTitle);
242 void IRCDockTabContents::completeNickname()
245 if (d->nicknameCompleter->isReset())
246 result = d->nicknameCompleter->complete(d->leCommandLine->text(), d->leCommandLine->cursorPosition());
248 result = d->nicknameCompleter->cycleNext();
249 if (result.isValid())
252 d->leCommandLine->blockSignals(
true);
253 d->leCommandLine->setText(result.textLine);
254 d->leCommandLine->setCursorPosition(result.cursorPos);
255 d->leCommandLine->blockSignals(
false);
259 bool IRCDockTabContents::eventFilter(QObject *watched, QEvent *event)
261 if (watched == d->leCommandLine && event->type() == QEvent::KeyPress)
263 auto keyEvent =
static_cast<QKeyEvent *
>(event);
264 if (keyEvent->key() == Qt::Key_Tab)
273 QStandardItem *IRCDockTabContents::findUserListItem(
const QString &nickname)
275 auto pModel = (QStandardItemModel *)d->lvUserList->model();
278 for (
int i = 0; i < pModel->rowCount(); ++i)
280 QStandardItem *pItem = pModel->item(i);
281 if (userInfo ==
IRCUserInfo(pItem->text(), network()))
288 IRCDockTabContents::UserListMenu &IRCDockTabContents::getUserListContextMenu()
290 if (d->userListContextMenu ==
nullptr)
291 d->userListContextMenu =
new UserListMenu();
293 return *d->userListContextMenu;
299 d->blinkTimer.stop();
300 setBlinkTitle(
false);
302 d->leCommandLine->setFocus();
305 bool IRCDockTabContents::hasTabFocus()
const
307 return this->pParentIRCDock->hasTabFocus(
this);
310 QIcon IRCDockTabContents::icon()
const
312 if (pIrcAdapter ==
nullptr)
317 case IRCAdapterBase::ChannelAdapter:
318 return QIcon(
":/icons/irc_channel.png");
320 case IRCAdapterBase::NetworkAdapter:
321 return QIcon(
":/flags/lan-small");
323 case IRCAdapterBase::PrivAdapter:
324 return QIcon(
":/icons/person.png");
331 void IRCDockTabContents::insertMessage(
const IRCMessageClass &messageClass,
const QString &htmlString)
333 if (d->lastMessageClass ==
nullptr)
335 *d->lastMessageClass = messageClass;
337 d->textOutputContents << htmlString;
343 QTextCursor cursor = d->txtOutputWidget->textCursor();
344 cursor.movePosition(QTextCursor::End);
345 cursor.insertHtml(htmlString);
347 if (!d->btnPauseTextArea->isChecked())
348 d->txtOutputWidget->moveCursor(QTextCursor::End);
350 emit newMessagePrinted();
353 void IRCDockTabContents::markDate()
355 QDateTime previousMessageDate = d->lastMessageDate;
356 QDateTime nowDate = QDateTime::currentDateTime();
357 d->lastMessageDate = nowDate;
358 if (previousMessageDate.daysTo(nowDate) != 0)
360 receiveMessageWithClass(tr(
"<<<DATE>>> Date on this computer changes to %1").arg(
361 nowDate.toString()), IRCMessageClass::NetworkAction);
365 void IRCDockTabContents::myNicknameUsedSlot()
370 d->blinkTimer.start(BLINK_TIMER_DELAY_MS);
373 void IRCDockTabContents::nameAdded(
const IRCUserInfo &userInfo)
375 auto pModel = (QStandardItemModel *)d->lvUserList->model();
376 QStandardItem *pItem =
new QStandardItem(userInfo.
prefixedName());
377 pItem->setData(userInfo.
cleanNickname(), IRCUserListModel::RoleCleanNickname);
380 for (
int i = 0; i < pModel->rowCount(); ++i)
382 QStandardItem *pExistingItem = pModel->item(i);
383 QString existingNickname = pExistingItem->text();
385 if (userInfo <=
IRCUserInfo(existingNickname, network()))
387 pModel->insertRow(i, pItem);
394 pModel->appendRow(pItem);
397 void IRCDockTabContents::nameListUpdated(
const IRCUserList &userList)
399 setupNewUserListModel();
401 for (
unsigned i = 0; i < userList.size(); ++i)
402 nameAdded(*userList[i]);
405 void IRCDockTabContents::nameRemoved(
const IRCUserInfo &userInfo)
407 auto pModel = (QStandardItemModel *)d->lvUserList->model();
408 for (
int i = 0; i < pModel->rowCount(); ++i)
410 QStandardItem *pItem = pModel->item(i);
413 pModel->removeRow(i);
419 void IRCDockTabContents::nameUpdated(
const IRCUserInfo &userInfo)
421 nameRemoved(userInfo);
427 return ircAdapter()->
network();
432 return ircAdapter()->networkEntity();
439 pParentIRCDock->addIRCAdapter(pAdapter);
442 void IRCDockTabContents::onFocusChanged(QWidget *old, QWidget *now)
444 if (old == d->lvUserList && now != d->userListContextMenu)
445 d->lvUserList->clearSelection();
448 bool IRCDockTabContents::openLog()
452 if (!logs.mkLogDir(networkEntity()))
454 receiveMessageWithClass(tr(
"Failed to create chat log directory:\n'%1'").arg(
455 logs.networkDirPath(networkEntity())), IRCMessageClass::Error);
458 d->log.setFileName(
ChatLogs().logFilePath(networkEntity(), recipient()));
459 d->log.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
460 d->log.write(tr(
"<<<DATE>>> Chat log started on %1\n\n").arg(QDateTime::currentDateTime().toString()).toUtf8());
464 void IRCDockTabContents::rotateOldLog()
466 assert(!d->log.isOpen());
471 cfg.isRestoreChatFromLogs() ? cfg.oldLogsRemovalDaysThreshold() : -1);
472 logRotate.rotate(networkEntity(), recipient());
475 void IRCDockTabContents::printToSendersNetworksCurrentChatBox(
const QString &text,
const IRCMessageClass &msgClass)
480 tab->ircAdapter()->emitMessageWithClass(text, msgClass);
482 adapter->emitMessageWithClass(text, msgClass);
485 void IRCDockTabContents::receiveError(
const QString &error)
487 receiveMessageWithClass(tr(
"Error: %1").arg(error), IRCMessageClass::Error);
490 void IRCDockTabContents::receiveMessage(
const QString &message)
495 void IRCDockTabContents::receiveMessageWithClass(
const QString &message,
const IRCMessageClass &messageClass)
499 QString messageHtmlEscaped = message;
501 if (gIRCConfig.appearance.timestamps)
503 QString timestamp = Strings::timestamp(
"[hh:mm:ss] ");
505 messageHtmlEscaped = timestamp + messageHtmlEscaped;
509 messageHtmlEscaped = messageHtmlEscaped.replace(
"\n",
"\n" + timestamp);
515 messageHtmlEscaped +=
"\n";
517 writeLog(messageHtmlEscaped);
519 messageHtmlEscaped = wrapTextWithMetaTags(messageHtmlEscaped, messageClass);
522 if (pIrcAdapter->
adapterType() == IRCAdapterBase::PrivAdapter)
525 pParentIRCDock->sounds().
playIfAvailable(IRCSounds::PrivateMessageReceived);
529 d->blinkTimer.start(BLINK_TIMER_DELAY_MS);
532 this->insertMessage(messageClass, messageHtmlEscaped);
535 QString IRCDockTabContents::recipient()
const
537 return pIrcAdapter->recipient();
540 void IRCDockTabContents::resetNicknameCompletion()
542 d->nicknameCompleter->reset();
545 bool IRCDockTabContents::restoreLog()
548 QFile file(logs.logFilePath(networkEntity(), recipient()));
549 if (file.open(QIODevice::ReadOnly | QIODevice::Text))
551 QByteArray contents = file.readAll();
552 QStringList lines = QString::fromUtf8(contents, contents.size()).split(
"\n");
553 int line = lines.size() - 1000;
554 lines = lines.mid((line > 0) ? line : 0);
559 receiveMessageWithClass(tr(
"---- All lines above were loaded from log ----"),
560 IRCMessageClass::NetworkAction);
566 QString IRCDockTabContents::selectedNickname()
568 QModelIndexList selectedIndexes = d->lvUserList->selectionModel()->selectedRows();
570 if (!selectedIndexes.isEmpty())
572 int row = selectedIndexes[0].row();
573 auto pModel = (QStandardItemModel *)d->lvUserList->model();
574 QStandardItem *pItem = pModel->item(row);
576 return pItem->text();
582 void IRCDockTabContents::sendCtcpPing(
const QString &nickname)
584 network()->sendCtcp(nickname, QString(
"PING %1").arg(QDateTime::currentMSecsSinceEpoch()));
587 void IRCDockTabContents::sendCtcpTime(
const QString &nickname)
589 network()->sendCtcp(nickname, QString(
"TIME"));
592 void IRCDockTabContents::sendCtcpVersion(
const QString &nickname)
594 network()->sendCtcp(nickname, QString(
"VERSION"));
597 void IRCDockTabContents::sendMessage()
599 QString message = d->leCommandLine->text();
600 d->leCommandLine->setText(
"");
602 if (!message.trimmed().isEmpty())
603 pIrcAdapter->sendMessage(message);
606 void IRCDockTabContents::sendWhois(
const QString &nickname)
608 network()->sendMessage(QString(
"/WHOIS %1").arg(nickname));
611 void IRCDockTabContents::setBlinkTitle(
bool b)
614 if (d->bBlinkTitle != b)
623 emit titleBlinkRequested();
628 assert(pIrcAdapter ==
nullptr);
629 pIrcAdapter = pAdapter;
632 if (cfg.isRestoreChatFromLogs())
634 if (cfg.isStoreLogs())
637 connect(pIrcAdapter, SIGNAL(error(
const QString&)), SLOT(receiveError(
const QString&)));
638 connect(pIrcAdapter, SIGNAL(
focusRequest()), SLOT(adapterFocusRequest()));
639 connect(pIrcAdapter, SIGNAL(message(
const QString&)), SLOT(receiveMessage(
const QString&)));
640 connect(pIrcAdapter, SIGNAL(messageWithClass(
const QString&,
const IRCMessageClass&)), SLOT(receiveMessageWithClass(
const QString&,
const IRCMessageClass&)));
641 connect(pIrcAdapter, SIGNAL(terminating()), SLOT(adapterTerminating()));
642 connect(pIrcAdapter, SIGNAL(
titleChange()), SLOT(adapterTitleChange()));
643 connect(pIrcAdapter, SIGNAL(messageToNetworksCurrentChatBox(QString,
IRCMessageClass)),
648 case IRCAdapterBase::NetworkAdapter:
655 case IRCAdapterBase::ChannelAdapter:
658 connect(pChannelAdapter, SIGNAL(myNicknameUsed()), SLOT(myNicknameUsedSlot()));
660 connect(pChannelAdapter, SIGNAL(nameListUpdated(
const IRCUserList&)), SLOT(nameListUpdated(
const IRCUserList&)));
664 d->lvUserList->setVisible(
true);
665 connect(d->lvUserList, SIGNAL(customContextMenuRequested(
const QPoint&)),
666 SLOT(userListCustomContextMenuRequested(
const QPoint&)));
668 connect(d->lvUserList, SIGNAL(doubleClicked(
const QModelIndex&)),
669 SLOT(userListDoubleClicked()));
671 d->lvUserList->setContextMenuPolicy(Qt::CustomContextMenu);
676 case IRCAdapterBase::PrivAdapter:
683 receiveError(
"Doomseeker error: Unknown IRCAdapterBase*");
689 void IRCDockTabContents::setupNewUserListModel()
691 d->lvUserList->setModel(
new QStandardItemModel(d->lvUserList));
692 d->nicknameCompleter->setModel(d->lvUserList->model());
695 void IRCDockTabContents::showChatContextMenu(
const QPoint &pos)
697 QMenu *menu = d->txtOutputWidget->createStandardContextMenu(pos);
698 if (ircAdapter()->adapterType() == IRCAdapterBase::PrivAdapter)
700 menu->addSeparator();
701 appendPrivChatContextMenuOptions(menu);
703 menu->addSeparator();
704 appendGeneralChatContextMenuOptions(menu);
705 menu->exec(d->txtOutputWidget->mapToGlobal(pos));
709 void IRCDockTabContents::appendGeneralChatContextMenuOptions(QMenu *menu)
711 QAction *manageIgnores = menu->addAction(tr(
"Manage ignores"));
712 this->connect(manageIgnores, SIGNAL(triggered()), SLOT(showIgnoresManager()));
715 void IRCDockTabContents::appendPrivChatContextMenuOptions(QMenu *menu)
717 appendPrivChatContextMenuAction(menu, tr(
"Whois"), PrivWhois);
718 appendPrivChatContextMenuAction(menu, tr(
"CTCP Ping"), PrivCtcpPing);
719 appendPrivChatContextMenuAction(menu, tr(
"CTCP Time"), PrivCtcpTime);
720 appendPrivChatContextMenuAction(menu, tr(
"CTCP Version"), PrivCtcpVersion);
721 appendPrivChatContextMenuAction(menu, tr(
"Ignore"), PrivIgnore);
724 void IRCDockTabContents::appendPrivChatContextMenuAction(QMenu *menu,
725 const QString &text, PrivChatMenu type)
727 QAction *action = menu->addAction(text);
728 action->setData(type);
729 this->connect(action, SIGNAL(triggered()), SLOT(onPrivChatActionTriggered()));
732 void IRCDockTabContents::onPrivChatActionTriggered()
734 QString nickname = ircAdapter()->recipient();
736 auto action =
static_cast<QAction *
>(sender());
737 switch (action->data().toInt())
740 sendWhois(cleanNickname);
743 sendCtcpPing(cleanNickname);
746 sendCtcpTime(cleanNickname);
748 case PrivCtcpVersion:
749 sendCtcpVersion(cleanNickname);
752 startIgnoreOperation(cleanNickname);
755 assert(0 &&
"Unsupported priv chat action");
756 qDebug() <<
"Unsupported priv chat action: " << action->data();
761 void IRCDockTabContents::showIgnoresManager()
764 connect(dialog, SIGNAL(accepted()), network(), SLOT(reloadNetworkEntityFromConfig()));
765 dialog->setAttribute(Qt::WA_DeleteOnClose);
769 void IRCDockTabContents::startIgnoreOperation(
const QString &nickname)
772 op->setShowPatternPopup(
true);
776 QString IRCDockTabContents::title()
const
778 return pIrcAdapter->
title();
781 QString IRCDockTabContents::titleColor()
const
783 if (d->lastMessageClass !=
nullptr && !this->hasTabFocus())
790 color = d->lastMessageClass->colorFromConfig();
796 int rInverted = 0xff - c.red();
797 int gInverted = 0xff - c.green();
798 int bInverted = 0xff - c.blue();
800 QColor inverted(rInverted, gInverted, bInverted);
802 return inverted.name();
811 void IRCDockTabContents::userListCustomContextMenuRequested(
const QPoint &pos)
813 if (this->pIrcAdapter->
adapterType() != IRCAdapterBase::ChannelAdapter)
819 QString nickname = this->selectedNickname();
820 if (nickname.isEmpty())
828 const QString &channel = pAdapter->recipient();
830 UserListMenu &menu = this->getUserListContextMenu();
831 QPoint posGlobal = d->lvUserList->mapToGlobal(pos);
833 QAction *pAction = menu.exec(posGlobal);
835 if (pAction ==
nullptr)
838 if (pAction == menu.ban)
842 QString reason =
CommonGUI::askString(tr(
"Ban user"), tr(
"Input reason for banning user %1 from channel %2").arg(nickname, channel), &bOk);
844 pAdapter->banUser(cleanNickname, reason);
846 else if (pAction == menu.ctcpTime)
847 sendCtcpTime(cleanNickname);
848 else if (pAction == menu.ctcpPing)
849 sendCtcpPing(cleanNickname);
850 else if (pAction == menu.ctcpVersion)
851 sendCtcpVersion(cleanNickname);
852 else if (pAction == menu.deop)
853 pAdapter->setOp(cleanNickname,
false);
854 else if (pAction == menu.dehalfOp)
855 pAdapter->setHalfOp(cleanNickname,
false);
856 else if (pAction == menu.devoice)
857 pAdapter->setVoiced(cleanNickname,
false);
858 else if (pAction == menu.halfOp)
859 pAdapter->setHalfOp(cleanNickname,
true);
860 else if (pAction == menu.ignore)
861 startIgnoreOperation(cleanNickname);
862 else if (pAction == menu.kick)
866 QString reason =
CommonGUI::askString(tr(
"Kick user"), tr(
"Input reason for kicking user %1 from channel %2").arg(nickname, channel), &bOk);
868 pAdapter->kickUser(cleanNickname, reason);
870 else if (pAction == menu.op)
871 pAdapter->setOp(cleanNickname,
true);
872 else if (pAction == menu.openChatWindow)
873 pAdapter->network()->openNewAdapter(cleanNickname);
874 else if (pAction == menu.voice)
875 pAdapter->setVoiced(cleanNickname,
true);
876 else if (pAction == menu.whois)
877 sendWhois(cleanNickname);
880 void IRCDockTabContents::userListDoubleClicked()
882 if (this->pIrcAdapter->
adapterType() != IRCAdapterBase::ChannelAdapter)
888 QString nickname = this->selectedNickname();
889 if (nickname.isEmpty())
899 QString IRCDockTabContents::wrapTextWithMetaTags(
const QString &text,
902 QString result = text;
903 result.replace(
"<",
"<").replace(
">",
">");
906 QString className = messageClass.toStyleSheetClassName();
907 if (className.isEmpty())
908 result =
"<span>" + result +
"</span>";
910 result = (
"<span class='" + className +
"'>" + result +
"</span>");
914 bool IRCDockTabContents::writeLog(
const QString &text)
917 if (d->log.isOpen() && cfg.isStoreLogs())
919 d->log.write(text.toUtf8());
927 IRCDockTabContents::UserListMenu::UserListMenu()
929 this->openChatWindow = this->addAction(tr(
"Open chat window"));
930 this->addSeparator();
931 this->whois = this->addAction(tr(
"Whois"));
932 this->ctcpTime = this->addAction(tr(
"CTCP Time"));
933 this->ctcpPing = this->addAction(tr(
"CTCP Ping"));
934 this->ctcpVersion = this->addAction(tr(
"CTCP Version"));
935 this->addSeparator();
936 this->op = this->addAction(tr(
"Op"));
937 this->deop = this->addAction(tr(
"Deop"));
938 this->halfOp = this->addAction(tr(
"Half op"));
939 this->dehalfOp = this->addAction(tr(
"De half op"));
940 this->voice = this->addAction(tr(
"Voice"));
941 this->devoice = this->addAction(tr(
"Devoice"));
942 this->addSeparator();
943 this->ignore = this->addAction(tr(
"Ignore"));
944 this->kick = this->addAction(tr(
"Kick"));
945 this->ban = this->addAction(tr(
"Ban"));
947 this->bIsOperator =
false;