diff --git a/channels.cpp b/channels.cpp index 93ad24ae..7b7ea47b 100644 --- a/channels.cpp +++ b/channels.cpp @@ -1,37 +1,51 @@ #include "channels.h" +#include "ircmanager.h" Channel Channels::m_whispers(QString("/whispers")); Channel Channels::m_mentions(QString("/mentions")); +Channel Channels::m_empty(QString("")); QMap> Channels::m_channels; Channel * Channels::addChannel(const QString &channel) { - auto c = getChannel(channel); + QString c = channel.toLower(); - if (c == NULL) { - c = new Channel(channel); - m_channels.insert(channel, std::tuple(c, 1)); + auto a = m_channels.find(c); - return c; + if (a == m_channels.end()) { + auto _c = new Channel(c); + m_channels.insert(c, std::tuple(_c, 1)); + + IrcManager::joinChannel(c); + + return _c; + } else { + std::get<1>(a.value())++; } - return c; + return std::get<0>(a.value()); } Channel * Channels::getChannel(const QString &channel) { - if (channel == "/whispers") { - return &m_whispers; + QString c = channel.toLower(); + + if (channel.length() > 1 && channel.at(0) == '/') { + if (c == "/whispers") { + return &m_whispers; + } + + if (c == "/mentions") { + return &m_mentions; + } + + return &m_empty; } - if (channel == "/mentions") { - return &m_mentions; - } - - auto a = m_channels.find(channel); + auto a = m_channels.find(c); if (a == m_channels.end()) { return NULL; @@ -43,7 +57,13 @@ Channels::getChannel(const QString &channel) void Channels::removeChannel(const QString &channel) { - auto a = m_channels.find(channel); + if (channel.length() > 1 && channel.at(0) == '/') { + return; + } + + QString c = channel.toLower(); + + auto a = m_channels.find(c); if (a == m_channels.end()) { return; @@ -52,7 +72,8 @@ Channels::removeChannel(const QString &channel) std::get<1>(a.value())--; if (std::get<1>(a.value()) == 0) { - m_channels.remove(channel); + IrcManager::partChannel(c); + m_channels.remove(c); delete std::get<0>(a.value()); } } diff --git a/channels.h b/channels.h index c39231ea..95ed0e5b 100644 --- a/channels.h +++ b/channels.h @@ -29,6 +29,7 @@ private: static Channel m_whispers; static Channel m_mentions; + static Channel m_empty; static QMap> m_channels; }; diff --git a/chatterino.pro b/chatterino.pro index 0063e147..c30015e7 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -68,7 +68,7 @@ SOURCES += main.cpp\ chatwidgetheaderbutton.cpp \ chatwidgetheaderbuttonlabel.cpp \ channels.cpp \ - textinputform.cpp + textinputdialog.cpp HEADERS += mainwindow.h \ chatwidget.h \ @@ -108,7 +108,7 @@ HEADERS += mainwindow.h \ chatwidgetheaderbutton.h \ chatwidgetheaderbuttonlabel.h \ channels.h \ - textinputform.h + textinputdialog.h PRECOMPILED_HEADER = diff --git a/chatwidget.cpp b/chatwidget.cpp index 38900e07..832a3ad9 100644 --- a/chatwidget.cpp +++ b/chatwidget.cpp @@ -1,14 +1,21 @@ #include "chatwidget.h" -#include "QFont" -#include "QFontDatabase" -#include "QPainter" -#include "QVBoxLayout" +#include "channels.h" #include "colorscheme.h" +#include "textinputdialog.h" + +#include +#include +#include +#include ChatWidget::ChatWidget(QWidget *parent) : QWidget(parent) - , m_header(this) + , m_channel(NULL) + , m_channelName(QString()) , m_vbox(this) + , m_header(this) + , m_view(this) + , m_input() { m_vbox.setSpacing(0); m_vbox.setMargin(1); @@ -22,6 +29,45 @@ ChatWidget::~ChatWidget() { } +void +ChatWidget::setChannelName(const QString &name) +{ + QString channel = name.trimmed(); + + if (QString::compare(channel, m_channelName, Qt::CaseInsensitive) == 0) { + m_channelName = channel; + m_header.updateChannelText(); + return; + } + + m_channelName = channel; + m_header.updateChannelText(); + + m_view.layoutMessages(); + + if (!m_channelName.isEmpty()) { + Channels::removeChannel(m_channelName); + } + + if (channel.isEmpty()) { + m_channel = NULL; + } else { + m_channel = Channels::addChannel(channel); + } +} + +void +ChatWidget::showChangeChannelPopup() +{ + TextInputDialog dialog(this); + + dialog.setText(m_channelName); + + if (dialog.exec() == QDialog::Accepted) { + setChannelName(dialog.text()); + } +} + void ChatWidget::paintEvent(QPaintEvent *) { diff --git a/chatwidget.h b/chatwidget.h index aa18ed4b..925f9195 100644 --- a/chatwidget.h +++ b/chatwidget.h @@ -29,17 +29,28 @@ public: return m_channel; } + const QString & + channelName() const + { + return m_channelName; + } + + void setChannelName(const QString &name); + + void showChangeChannelPopup(); + protected: void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; private: + Channel *m_channel; + QString m_channelName; + QFont m_font; QVBoxLayout m_vbox; ChatWidgetHeader m_header; ChatWidgetView m_view; ChatWidgetInput m_input; - - Channel *m_channel = NULL; }; #endif // CHATWIDGET_H diff --git a/chatwidgetheader.cpp b/chatwidgetheader.cpp index a1ac0068..32843ff2 100644 --- a/chatwidgetheader.cpp +++ b/chatwidgetheader.cpp @@ -22,6 +22,7 @@ ChatWidgetHeader::ChatWidgetHeader(ChatWidget *parent) setFixedHeight(32); updateColors(); + updateChannelText(); setLayout(&m_hbox); m_hbox.setMargin(0); @@ -37,36 +38,28 @@ ChatWidgetHeader::ChatWidgetHeader(ChatWidget *parent) QObject::connect(&m_leftLabel, &ChatWidgetHeaderButton::clicked, this, &ChatWidgetHeader::leftButtonClicked); - m_leftMenu.addAction("Add new split", this, - SLOT(menuAddSplit()), - QKeySequence(tr("Ctrl+T"))); - m_leftMenu.addAction("Close split", this, - SLOT(menuCloseSplit()), - QKeySequence(tr("Ctrl+W"))); - m_leftMenu.addAction("Move split", this, - SLOT(menuMoveSplit())); - m_leftMenu.addSeparator(); - m_leftMenu.addAction("Change channel", this, - SLOT(menuChangeChannel()), - QKeySequence(tr("Ctrl+R"))); - m_leftMenu.addAction("Clear chat", this, - SLOT(menuClearChat())); - m_leftMenu.addAction("Open channel", this, - SLOT(menuOpenChannel())); - m_leftMenu.addAction("Open pop-out player", this, - SLOT(menuPopupPlayer())); - m_leftMenu.addSeparator(); - m_leftMenu.addAction("Reload channel emotes", this, - SLOT(menuReloadChannelEmotes())); - m_leftMenu.addAction("Manual reconnect", this, - SLOT(menuManualReconnect())); - m_leftMenu.addSeparator(); - m_leftMenu.addAction("Show changelog", this, - SLOT(menuShowChangelog())); + m_leftMenu.addAction("Add new split", this, SLOT(menuAddSplit()), + QKeySequence(tr("Ctrl+T"))); + m_leftMenu.addAction("Close split", this, SLOT(menuCloseSplit()), + QKeySequence(tr("Ctrl+W"))); + m_leftMenu.addAction("Move split", this, SLOT(menuMoveSplit())); + m_leftMenu.addSeparator(); + m_leftMenu.addAction("Change channel", this, SLOT(menuChangeChannel()), + QKeySequence(tr("Ctrl+R"))); + m_leftMenu.addAction("Clear chat", this, SLOT(menuClearChat())); + m_leftMenu.addAction("Open channel", this, SLOT(menuOpenChannel())); + m_leftMenu.addAction("Open pop-out player", this, SLOT(menuPopupPlayer())); + m_leftMenu.addSeparator(); + m_leftMenu.addAction("Reload channel emotes", this, + SLOT(menuReloadChannelEmotes())); + m_leftMenu.addAction("Manual reconnect", this, SLOT(menuManualReconnect())); + m_leftMenu.addSeparator(); + m_leftMenu.addAction("Show changelog", this, SLOT(menuShowChangelog())); // middle m_middleLabel.setAlignment(Qt::AlignCenter); - m_middleLabel.setText("textString"); + QObject::connect(&m_middleLabel, &m_middleLabel.mouseDoubleClickEvent, this, + &mouseDoubleClickEvent); // right m_rightLabel.setMinimumWidth(height()); @@ -85,6 +78,14 @@ ChatWidgetHeader::updateColors() m_rightLabel.setPalette(palette); } +void +ChatWidgetHeader::updateChannelText() +{ + const QString &c = m_chatWidget->channelName(); + + m_middleLabel.setText(c.isEmpty() ? "" : c); +} + void ChatWidgetHeader::paintEvent(QPaintEvent *) { @@ -139,6 +140,14 @@ ChatWidgetHeader::mouseMoveEvent(QMouseEvent *event) } } +void +ChatWidgetHeader::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + chatWidget()->showChangeChannelPopup(); + } +} + void ChatWidgetHeader::leftButtonClicked() { @@ -166,6 +175,7 @@ ChatWidgetHeader::menuMoveSplit() void ChatWidgetHeader::menuChangeChannel() { + m_chatWidget->showChangeChannelPopup(); } void ChatWidgetHeader::menuClearChat() diff --git a/chatwidgetheader.h b/chatwidgetheader.h index c5a2d155..473030f7 100644 --- a/chatwidgetheader.h +++ b/chatwidgetheader.h @@ -28,11 +28,13 @@ public: } void updateColors(); + void updateChannelText(); protected: void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event); private: ChatWidget *m_chatWidget; diff --git a/chatwidgetview.cpp b/chatwidgetview.cpp index d01177a8..7fe8a5c8 100644 --- a/chatwidgetview.cpp +++ b/chatwidgetview.cpp @@ -1,5 +1,6 @@ #include "chatwidgetview.h" #include "channels.h" +#include "chatwidget.h" #include "message.h" #include "word.h" #include "wordpart.h" @@ -7,22 +8,20 @@ #include #include -ChatWidgetView::ChatWidgetView() +ChatWidgetView::ChatWidgetView(ChatWidget *parent) : QWidget() - , scrollbar(this) - , m_channel(NULL) + , m_chatWidget(parent) + , m_scrollbar(this) { auto scroll = QScroller::scroller(this); scroll->scrollTo(QPointF(0, 100)); - - m_channel = Channels::getChannel("fourtf"); } bool ChatWidgetView::layoutMessages() { - auto c = channel(); + auto c = m_chatWidget->channel(); if (c == NULL) return false; @@ -41,8 +40,8 @@ ChatWidgetView::layoutMessages() void ChatWidgetView::resizeEvent(QResizeEvent *) { - scrollbar.resize(scrollbar.width(), height()); - scrollbar.move(width() - scrollbar.width(), 0); + m_scrollbar.resize(m_scrollbar.width(), height()); + m_scrollbar.move(width() - m_scrollbar.width(), 0); layoutMessages(); } @@ -54,7 +53,7 @@ ChatWidgetView::paintEvent(QPaintEvent *) painter.setRenderHint(QPainter::SmoothPixmapTransform); - auto c = channel(); + auto c = m_chatWidget->channel(); if (c == NULL) return; diff --git a/chatwidgetview.h b/chatwidgetview.h index 7511d56a..5435cd71 100644 --- a/chatwidgetview.h +++ b/chatwidgetview.h @@ -6,18 +6,14 @@ #include "channel.h" #include "scrollbar.h" +class ChatWidget; + class ChatWidgetView : public QWidget { Q_OBJECT public: - ChatWidgetView(); - - Channel * - channel() - { - return m_channel; - } + ChatWidgetView(ChatWidget *parent); bool layoutMessages(); @@ -25,8 +21,9 @@ protected: void resizeEvent(QResizeEvent *); private: - ScrollBar scrollbar; - Channel *m_channel; + ChatWidget *m_chatWidget; + + ScrollBar m_scrollbar; void paintEvent(QPaintEvent *); }; diff --git a/ircmanager.cpp b/ircmanager.cpp index f15d90e1..577d382b 100644 --- a/ircmanager.cpp +++ b/ircmanager.cpp @@ -13,14 +13,14 @@ #include Account *IrcManager::account = nullptr; -IrcConnection *IrcManager::connection = NULL; -QMutex IrcManager::connectionMutex; -long IrcManager::connectionIteration = 0; +IrcConnection *IrcManager::m_connection = NULL; +QMutex IrcManager::m_connectionMutex; +long IrcManager::m_connectionIteration = 0; const QString IrcManager::defaultClientId = "7ue61iz46fz11y3cugd0l3tawb4taal"; QNetworkAccessManager IrcManager::m_accessManager; -QMap IrcManager::twitchBlockedUsers; -QMutex IrcManager::twitchBlockedUsersMutex; +QMap IrcManager::m_twitchBlockedUsers; +QMutex IrcManager::m_twitchBlockedUsersMutex; IrcManager::IrcManager() { @@ -39,7 +39,7 @@ IrcManager::beginConnecting() { IrcManager::account = const_cast(Account::anon()); - int iteration = ++connectionIteration; + int iteration = ++m_connectionIteration; auto c = new IrcConnection(); @@ -62,9 +62,9 @@ IrcManager::beginConnecting() QNetworkReply *reply = m_accessManager.get(req); QObject::connect(reply, &QNetworkReply::finished, [=] { - twitchBlockedUsersMutex.lock(); - twitchBlockedUsers.clear(); - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsers.clear(); + m_twitchBlockedUsersMutex.unlock(); QByteArray data = reply->readAll(); QJsonDocument jsonDoc(QJsonDocument::fromJson(data)); @@ -75,15 +75,15 @@ IrcManager::beginConnecting() auto blocks = root.value("blocks").toArray(); - twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsersMutex.lock(); for (QJsonValue block : blocks) { QJsonObject user = block.toObject().value("user").toObject(); // display_name - twitchBlockedUsers.insert( + m_twitchBlockedUsers.insert( user.value("name").toString().toLower(), true); } - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.unlock(); }); } @@ -104,15 +104,15 @@ IrcManager::beginConnecting() auto blocks = root.value("blocks").toArray(); - twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsersMutex.lock(); for (QJsonValue block : blocks) { QJsonObject user = block.toObject().value("user").toObject(); // display_name - twitchBlockedUsers.insert( + m_twitchBlockedUsers.insert( user.value("name").toString().toLower(), true); } - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.unlock(); }); } } @@ -123,41 +123,60 @@ IrcManager::beginConnecting() c->setUserName("justinfan123"); c->setNickName("justinfan123"); c->setRealName("justinfan123"); - c->sendRaw("JOIN #fourtf"); c->sendCommand(IrcCommand::createCapability("REQ", "twitch.tv/commands")); c->sendCommand(IrcCommand::createCapability("REQ", "twitch.tv/tags")); c->open(); - connectionMutex.lock(); - if (iteration == connectionIteration) { - delete connection; + m_connectionMutex.lock(); + if (iteration == m_connectionIteration) { + delete m_connection; c->moveToThread(QCoreApplication::instance()->thread()); - connection = c; + m_connection = c; } else { delete c; } - connectionMutex.unlock(); + m_connectionMutex.unlock(); } void IrcManager::disconnect() { - connectionMutex.lock(); + m_connectionMutex.lock(); - if (connection != NULL) { - delete connection; - connection = NULL; + if (m_connection != NULL) { + delete m_connection; + m_connection = NULL; } - connectionMutex.unlock(); + m_connectionMutex.unlock(); +} + +void +IrcManager::joinChannel(const QString &channel) +{ + m_connectionMutex.lock(); + if (m_connection != NULL) { + m_connection->sendRaw("JOIN #" + channel); + } + m_connectionMutex.unlock(); +} + +void +IrcManager::partChannel(const QString &channel) +{ + m_connectionMutex.lock(); + if (m_connection != NULL) { + m_connection->sendRaw("PART #" + channel); + } + m_connectionMutex.unlock(); } void IrcManager::messageReceived(IrcMessage *message) { -// qInfo(message->command().toStdString().c_str()); + qInfo(message->command().toStdString().c_str()); // if (message->command() == "") } @@ -165,7 +184,7 @@ IrcManager::messageReceived(IrcMessage *message) void IrcManager::privateMessageReceived(IrcPrivateMessage *message) { -// qInfo(message->content().toStdString().c_str()); + // qInfo(message->content().toStdString().c_str()); auto c = Channels::getChannel(message->target().mid(1)); @@ -177,16 +196,16 @@ IrcManager::privateMessageReceived(IrcPrivateMessage *message) bool IrcManager::isTwitchBlockedUser(QString const &username) { - twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsersMutex.lock(); - auto iterator = twitchBlockedUsers.find(username); + auto iterator = m_twitchBlockedUsers.find(username); - if (iterator == twitchBlockedUsers.end()) { - twitchBlockedUsersMutex.unlock(); + if (iterator == m_twitchBlockedUsers.end()) { + m_twitchBlockedUsersMutex.unlock(); return false; } - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.unlock(); return true; } @@ -202,9 +221,9 @@ IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessage) reply->waitForReadyRead(10000); if (reply->error() == QNetworkReply::NoError) { - twitchBlockedUsersMutex.lock(); - twitchBlockedUsers.insert(username, true); - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsers.insert(username, true); + m_twitchBlockedUsersMutex.unlock(); delete reply; return true; @@ -236,9 +255,9 @@ IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMessage) reply->waitForReadyRead(10000); if (reply->error() == QNetworkReply::NoError) { - twitchBlockedUsersMutex.lock(); - twitchBlockedUsers.remove(username); - twitchBlockedUsersMutex.unlock(); + m_twitchBlockedUsersMutex.lock(); + m_twitchBlockedUsers.remove(username); + m_twitchBlockedUsersMutex.unlock(); delete reply; return true; diff --git a/ircmanager.h b/ircmanager.h index e790c4f2..c9adf560 100644 --- a/ircmanager.h +++ b/ircmanager.h @@ -34,19 +34,23 @@ public: return m_accessManager; } + static void joinChannel(const QString &channel); + + static void partChannel(const QString &channel); + private: IrcManager(); - static QMap twitchBlockedUsers; - static QMutex twitchBlockedUsersMutex; + static QMap m_twitchBlockedUsers; + static QMutex m_twitchBlockedUsersMutex; static QNetworkAccessManager m_accessManager; static void beginConnecting(); - static IrcConnection *connection; - static QMutex connectionMutex; - static long connectionIteration; + static IrcConnection *m_connection; + static QMutex m_connectionMutex; + static long m_connectionIteration; static void messageReceived(IrcMessage *message); static void privateMessageReceived(IrcPrivateMessage *message); diff --git a/main.cpp b/main.cpp index 3daf59b2..0260710e 100644 --- a/main.cpp +++ b/main.cpp @@ -22,9 +22,6 @@ main(int argc, char *argv[]) MainWindow &w = Windows::mainWindow(); w.show(); - Channels::addChannel("ian678"); - Channels::addChannel("fourtf"); - IrcManager::connect(); return a.exec(); diff --git a/textinputdialog.cpp b/textinputdialog.cpp new file mode 100644 index 00000000..e8057bd9 --- /dev/null +++ b/textinputdialog.cpp @@ -0,0 +1,38 @@ +#include "textinputdialog.h" +#include + +TextInputDialog::TextInputDialog(QWidget *parent) + : QDialog(parent) + , m_vbox(this) + , m_lineEdit() + , m_buttonBox() + , m_okButton("OK") + , m_cancelButton("Cancel") +{ + m_vbox.addWidget(&m_lineEdit); + m_vbox.addLayout(&m_buttonBox); + m_buttonBox.addStretch(1); + m_buttonBox.addWidget(&m_okButton); + m_buttonBox.addWidget(&m_cancelButton); + + QObject::connect(&m_okButton, &m_okButton.clicked, this, &okButtonClicked); + QObject::connect(&m_cancelButton, &m_cancelButton.clicked, this, + &cancelButtonClicked); + + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + setWindowFlags((windowFlags() & ~(Qt::WindowContextHelpButtonHint)) | + Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint); +} + +void +TextInputDialog::okButtonClicked() +{ + accept(); +} + +void +TextInputDialog::cancelButtonClicked() +{ + reject(); +} diff --git a/textinputdialog.h b/textinputdialog.h new file mode 100644 index 00000000..49777b2a --- /dev/null +++ b/textinputdialog.h @@ -0,0 +1,41 @@ +#ifndef TEXTINPUTDIALOG_H +#define TEXTINPUTDIALOG_H + +#include +#include +#include +#include +#include +#include + +class TextInputDialog : public QDialog +{ + Q_OBJECT + +public: + TextInputDialog(QWidget *parent = NULL); + + QString + text() const + { + return m_lineEdit.text(); + } + + void + setText(const QString &text) + { + m_lineEdit.setText(text); + } + +private: + QVBoxLayout m_vbox; + QLineEdit m_lineEdit; + QHBoxLayout m_buttonBox; + QPushButton m_okButton; + QPushButton m_cancelButton; + + void okButtonClicked(); + void cancelButtonClicked(); +}; + +#endif // TEXTINPUTDIALOG_H diff --git a/textinputform.cpp b/textinputform.cpp deleted file mode 100644 index 5565fc6d..00000000 --- a/textinputform.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "textinputform.h" - -TextInputForm::TextInputForm() -{ - -} diff --git a/textinputform.h b/textinputform.h deleted file mode 100644 index 3a55ebd6..00000000 --- a/textinputform.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef TEXTINPUTFORM_H -#define TEXTINPUTFORM_H - -#include - -class TextInputForm : public QDialog -{ -public: - TextInputForm(); -}; - -#endif // TEXTINPUTFORM_H