1 /***************************************************************************
2 * Copyright (C) 2005-2020 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "networkmodelcontroller.h"
24 #include <QDialogButtonBox>
25 #include <QGridLayout>
27 #include <QInputDialog>
30 #include <QMessageBox>
31 #include <QPushButton>
33 #include "buffermodel.h"
34 #include "buffersettings.h"
36 #include "clientidentity.h"
37 #include "clientignorelistmanager.h"
42 NetworkModelController::NetworkModelController(QObject* parent)
44 , _actionCollection(new ActionCollection(this))
46 connect(_actionCollection, &ActionCollection::actionTriggered, this, &NetworkModelController::actionTriggered);
49 Action* NetworkModelController::registerAction(ActionType type, const QString& text, bool checkable)
51 return registerAction(type, QPixmap(), text, checkable);
54 Action* NetworkModelController::registerAction(ActionType type, const QIcon& icon, const QString& text, bool checkable)
58 act = new Action(text, this);
60 act = new Action(icon, text, this);
62 act->setCheckable(checkable);
65 _actionCollection->addAction(QString::number(type, 16), act);
66 _actionByType[type] = act;
70 /******** Helper Functions ***********************************************************************/
72 void NetworkModelController::setIndexList(const QModelIndex& index)
74 _indexList = QList<QModelIndex>() << index;
77 void NetworkModelController::setIndexList(const QList<QModelIndex>& list)
82 void NetworkModelController::setMessageFilter(MessageFilter* filter)
84 _messageFilter = filter;
87 void NetworkModelController::setContextItem(const QString& contextItem)
89 _contextItem = contextItem;
92 void NetworkModelController::setSlot(ActionSlot slot)
94 _actionSlot = std::move(slot);
97 bool NetworkModelController::checkRequirements(const QModelIndex& index, ItemActiveStates requiredActiveState)
102 ItemActiveStates isActive = index.data(NetworkModel::ItemActiveRole).toBool() ? ActiveState : InactiveState;
104 if (!(isActive & requiredActiveState))
110 QString NetworkModelController::nickName(const QModelIndex& index) const
112 auto* ircUser = qobject_cast<IrcUser*>(index.data(NetworkModel::IrcUserRole).value<QObject*>());
114 return ircUser->nick();
116 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
117 if (!bufferInfo.isValid())
119 if (bufferInfo.type() != BufferInfo::QueryBuffer)
122 return bufferInfo.bufferName(); // FIXME this might break with merged queries maybe
125 BufferId NetworkModelController::findQueryBuffer(const QModelIndex& index, const QString& predefinedNick) const
127 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
128 if (!networkId.isValid())
131 QString nick = predefinedNick.isEmpty() ? nickName(index) : predefinedNick;
135 return findQueryBuffer(networkId, nick);
138 BufferId NetworkModelController::findQueryBuffer(NetworkId networkId, const QString& nick) const
140 return Client::networkModel()->bufferId(networkId, nick);
143 void NetworkModelController::removeBuffers(const QModelIndexList& indexList)
145 QList<BufferInfo> inactive;
146 foreach (QModelIndex index, indexList) {
147 BufferInfo info = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
148 if (info.isValid()) {
149 if (info.type() == BufferInfo::QueryBuffer
150 || (info.type() == BufferInfo::ChannelBuffer && !index.data(NetworkModel::ItemActiveRole).toBool()))
155 if (inactive.count()) {
156 msg = tr("Do you want to delete the following buffer(s) permanently?", "", inactive.count());
159 foreach (BufferInfo info, inactive) {
161 msg += QString("<li>%1</li>").arg(info.bufferName());
168 if (count > 9 && inactive.size() - count != 0)
169 msg += tr("...and <b>%1</b> more<br><br>").arg(inactive.size() - count);
171 "<b>Note:</b> This will delete all related data, including all backlog data, from the core's database and cannot be undone.");
172 if (inactive.count() != indexList.count())
173 msg += tr("<br>Active channel buffers cannot be deleted, please part the channel first.");
175 if (QMessageBox::question(nullptr, tr("Remove buffers permanently?"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
176 == QMessageBox::Yes) {
177 foreach (BufferInfo info, inactive)
178 Client::removeBuffer(info.bufferId());
183 void NetworkModelController::handleExternalAction(ActionType type, QAction* action)
191 /******** Handle Actions *************************************************************************/
193 void NetworkModelController::actionTriggered(QAction* action)
195 ActionType type = (ActionType)action->data().toInt();
197 if (type & NetworkMask)
198 handleNetworkAction(type, action);
199 else if (type & BufferMask)
200 handleBufferAction(type, action);
201 else if (type & HideMask)
202 handleHideAction(type, action);
203 else if (type & GeneralMask)
204 handleGeneralAction(type, action);
205 else if (type & NickMask)
206 handleNickAction(type, action);
207 else if (type & ExternalMask)
208 handleExternalAction(type, action);
210 qWarning() << "NetworkModelController::actionTriggered(): Unhandled action!";
214 void NetworkModelController::handleNetworkAction(ActionType type, QAction*)
216 if (type == NetworkConnectAllWithDropdown || type == NetworkDisconnectAllWithDropdown || type == NetworkConnectAll
217 || type == NetworkDisconnectAll) {
218 if (type == NetworkConnectAllWithDropdown
219 && QMessageBox::question(nullptr,
221 tr("Really Connect to all IRC Networks?"),
222 QMessageBox::Yes | QMessageBox::No,
226 if (type == NetworkDisconnectAllWithDropdown
227 && QMessageBox::question(nullptr,
229 tr("Really disconnect from all IRC Networks?"),
230 QMessageBox::Yes | QMessageBox::No,
234 foreach (NetworkId id, Client::networkIds()) {
235 const Network* net = Client::network(id);
236 if ((type == NetworkConnectAllWithDropdown || type == NetworkConnectAll) && net->connectionState() == Network::Disconnected)
237 net->requestConnect();
238 if ((type == NetworkDisconnectAllWithDropdown || type == NetworkDisconnectAll) && net->connectionState() != Network::Disconnected)
239 net->requestDisconnect();
244 if (!indexList().count())
247 const Network* network = Client::network(indexList().at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>());
248 Q_CHECK_PTR(network);
254 network->requestConnect();
256 case NetworkDisconnect:
257 network->requestDisconnect();
264 void NetworkModelController::handleBufferAction(ActionType type, QAction*)
266 if (type == BufferRemove) {
267 removeBuffers(indexList());
270 QList<BufferInfo> bufferList; // create temp list because model indexes might change
271 foreach (QModelIndex index, indexList()) {
272 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
273 if (bufferInfo.isValid())
274 bufferList << bufferInfo;
277 foreach (BufferInfo bufferInfo, bufferList) {
280 Client::userInput(bufferInfo, QString("/JOIN %1").arg(bufferInfo.bufferName()));
283 QString reason = Client::identity(Client::network(bufferInfo.networkId())->identity())->partReason();
284 Client::userInput(bufferInfo, QString("/PART %1").arg(reason));
288 Client::bufferModel()->switchToBuffer(bufferInfo.bufferId());
297 void NetworkModelController::handleHideAction(ActionType type, QAction* action)
301 if (type == HideJoinPartQuit) {
302 bool anyChecked = NetworkModelController::action(HideJoin)->isChecked();
303 anyChecked |= NetworkModelController::action(HidePart)->isChecked();
304 anyChecked |= NetworkModelController::action(HideQuit)->isChecked();
306 // If any are checked, uncheck them all.
307 // If none are checked, check them all.
308 bool newCheckedState = !anyChecked;
309 NetworkModelController::action(HideJoin)->setChecked(newCheckedState);
310 NetworkModelController::action(HidePart)->setChecked(newCheckedState);
311 NetworkModelController::action(HideQuit)->setChecked(newCheckedState);
315 if (NetworkModelController::action(HideJoin)->isChecked())
316 filter |= Message::Join | Message::NetsplitJoin;
317 if (NetworkModelController::action(HidePart)->isChecked())
318 filter |= Message::Part;
319 if (NetworkModelController::action(HideQuit)->isChecked())
320 filter |= Message::Quit | Message::NetsplitQuit;
321 if (NetworkModelController::action(HideNick)->isChecked())
322 filter |= Message::Nick;
323 if (NetworkModelController::action(HideMode)->isChecked())
324 filter |= Message::Mode;
325 if (NetworkModelController::action(HideDayChange)->isChecked())
326 filter |= Message::DayChange;
327 if (NetworkModelController::action(HideTopic)->isChecked())
328 filter |= Message::Topic;
331 case HideJoinPartQuit:
340 BufferSettings(_messageFilter->idString()).setMessageFilter(filter);
342 foreach (QModelIndex index, _indexList) {
343 BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
344 if (!bufferId.isValid())
346 BufferSettings(bufferId).setMessageFilter(filter);
351 BufferSettings().setMessageFilter(filter);
353 case HideUseDefaults:
355 BufferSettings(_messageFilter->idString()).removeFilter();
357 foreach (QModelIndex index, _indexList) {
358 BufferId bufferId = index.data(NetworkModel::BufferIdRole).value<BufferId>();
359 if (!bufferId.isValid())
361 BufferSettings(bufferId).removeFilter();
370 void NetworkModelController::handleGeneralAction(ActionType type, QAction* action)
374 if (!indexList().count())
376 NetworkId networkId = indexList().at(0).data(NetworkModel::NetworkIdRole).value<NetworkId>();
380 QString channelName = contextItem();
381 QString channelPassword;
382 if (channelName.isEmpty()) {
383 JoinDlg dlg(indexList().first());
384 if (dlg.exec() == QDialog::Accepted) {
385 channelName = dlg.channelName();
386 networkId = dlg.networkId();
387 channelPassword = dlg.channelPassword();
390 if (!channelName.isEmpty()) {
391 if (!channelPassword.isEmpty())
392 Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId),
393 QString("/JOIN %1 %2").arg(channelName).arg(channelPassword));
395 Client::instance()->userInput(BufferInfo::fakeStatusBuffer(networkId), QString("/JOIN %1").arg(channelName));
399 case ShowChannelList:
400 if (networkId.isValid()) {
401 // Don't immediately list channels, allowing customization of filter first
402 emit showChannelList(networkId, {}, false);
405 case ShowNetworkConfig:
406 if (networkId.isValid())
407 emit showNetworkConfig(networkId);
410 if (networkId.isValid())
411 emit showIgnoreList(QString());
418 void NetworkModelController::handleNickAction(ActionType type, QAction* action)
420 foreach (QModelIndex index, indexList()) {
421 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
422 if (!networkId.isValid())
424 QString nick = nickName(index);
427 BufferInfo bufferInfo = index.data(NetworkModel::BufferInfoRole).value<BufferInfo>();
428 if (!bufferInfo.isValid())
433 Client::userInput(bufferInfo, QString("/WHOIS %1 %1").arg(nick));
435 case NickCtcpVersion:
436 Client::userInput(bufferInfo, QString("/CTCP %1 VERSION").arg(nick));
439 Client::userInput(bufferInfo, QString("/CTCP %1 PING").arg(nick));
442 Client::userInput(bufferInfo, QString("/CTCP %1 TIME").arg(nick));
444 case NickCtcpClientinfo:
445 Client::userInput(bufferInfo, QString("/CTCP %1 CLIENTINFO").arg(nick));
448 Client::userInput(bufferInfo, QString("/OP %1").arg(nick));
451 Client::userInput(bufferInfo, QString("/DEOP %1").arg(nick));
454 Client::userInput(bufferInfo, QString("/HALFOP %1").arg(nick));
457 Client::userInput(bufferInfo, QString("/DEHALFOP %1").arg(nick));
460 Client::userInput(bufferInfo, QString("/VOICE %1").arg(nick));
463 Client::userInput(bufferInfo, QString("/DEVOICE %1").arg(nick));
466 Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
469 Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
472 Client::userInput(bufferInfo, QString("/BAN %1").arg(nick));
473 Client::userInput(bufferInfo, QString("/KICK %1").arg(nick));
477 Client::bufferModel()->switchToOrStartQuery(networkId, nick);
479 case NickIgnoreUser: {
480 auto* ircUser = qobject_cast<IrcUser*>(index.data(NetworkModel::IrcUserRole).value<QObject*>());
483 Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
484 action->property("ignoreRule").toString(),
486 IgnoreListManager::SoftStrictness,
487 IgnoreListManager::NetworkScope,
488 ircUser->network()->networkName(),
492 case NickIgnoreHost: {
493 auto* ircUser = qobject_cast<IrcUser*>(index.data(NetworkModel::IrcUserRole).value<QObject*>());
496 Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
497 action->property("ignoreRule").toString(),
499 IgnoreListManager::SoftStrictness,
500 IgnoreListManager::NetworkScope,
501 ircUser->network()->networkName(),
505 case NickIgnoreDomain: {
506 auto* ircUser = qobject_cast<IrcUser*>(index.data(NetworkModel::IrcUserRole).value<QObject*>());
509 Client::ignoreListManager()->requestAddIgnoreListItem(IgnoreListManager::SenderIgnore,
510 action->property("ignoreRule").toString(),
512 IgnoreListManager::SoftStrictness,
513 IgnoreListManager::NetworkScope,
514 ircUser->network()->networkName(),
518 case NickIgnoreCustom:
519 // forward that to mainwin since we can access the settingspage only from there
520 emit showIgnoreList(action->property("ignoreRule").toString());
522 case NickIgnoreToggleEnabled0:
523 case NickIgnoreToggleEnabled1:
524 case NickIgnoreToggleEnabled2:
525 case NickIgnoreToggleEnabled3:
526 case NickIgnoreToggleEnabled4:
527 Client::ignoreListManager()->requestToggleIgnoreRule(action->property("ignoreRule").toString());
530 qWarning() << "Unhandled nick action";
535 /***************************************************************************************************************
537 ***************************************************************************************************************/
539 NetworkModelController::JoinDlg::JoinDlg(const QModelIndex& index, QWidget* parent)
542 setWindowIcon(icon::get("irc-join-channel"));
543 setWindowTitle(tr("Join Channel"));
545 auto* layout = new QGridLayout(this);
546 layout->addWidget(new QLabel(tr("Network:")), 0, 0);
547 layout->addWidget(networks = new QComboBox, 0, 1);
548 layout->addWidget(new QLabel(tr("Channel:")), 1, 0);
549 layout->addWidget(channel = new QLineEdit, 1, 1);
550 layout->addWidget(new QLabel(tr("Password:")), 2, 0);
551 layout->addWidget(password = new QLineEdit, 2, 1);
552 layout->addWidget(buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel), 3, 0, 1, 2);
556 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
557 networks->setInsertPolicy(QComboBox::InsertAlphabetically);
558 password->setEchoMode(QLineEdit::Password);
560 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
561 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
562 connect(channel, &QLineEdit::textChanged, this, &JoinDlg::on_channel_textChanged);
564 foreach (NetworkId id, Client::networkIds()) {
565 const Network* net = Client::network(id);
566 if (net->isConnected()) {
567 networks->addItem(net->networkName(), QVariant::fromValue(id));
571 if (index.isValid()) {
572 NetworkId networkId = index.data(NetworkModel::NetworkIdRole).value<NetworkId>();
573 if (networkId.isValid()) {
574 networks->setCurrentIndex(networks->findText(Client::network(networkId)->networkName()));
575 if (index.data(NetworkModel::BufferTypeRole) == BufferInfo::ChannelBuffer && !index.data(NetworkModel::ItemActiveRole).toBool())
576 channel->setText(index.data(Qt::DisplayRole).toString());
581 NetworkId NetworkModelController::JoinDlg::networkId() const
583 return networks->itemData(networks->currentIndex()).value<NetworkId>();
586 QString NetworkModelController::JoinDlg::channelName() const
588 return channel->text();
591 QString NetworkModelController::JoinDlg::channelPassword() const
593 return password->text();
596 void NetworkModelController::JoinDlg::on_channel_textChanged(const QString& text)
598 buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty());