diff --git a/Applications/IRCClient/IRCAppWindow.cpp b/Applications/IRCClient/IRCAppWindow.cpp index ba55d2f326..9def1e6280 100644 --- a/Applications/IRCClient/IRCAppWindow.cpp +++ b/Applications/IRCClient/IRCAppWindow.cpp @@ -1,6 +1,7 @@ #include "IRCAppWindow.h" #include "IRCClientWindow.h" -#include +#include "IRCClientWindowListModel.h" +#include #include IRCAppWindow::IRCAppWindow() @@ -23,6 +24,10 @@ void IRCAppWindow::setup_client() m_client.join_channel("#test"); }; + m_client.on_join = [this] (const String& channel_name) { + ensure_window(IRCClientWindow::Channel, channel_name); + }; + m_client.on_query_message = [this] (const String& name) { // FIXME: Update query view. }; @@ -41,11 +46,10 @@ void IRCAppWindow::setup_widgets() set_main_widget(widget); widget->set_layout(make(Orientation::Horizontal)); - auto* subwindow_list = new GListBox(widget); + auto* subwindow_list = new GTableView(widget); + subwindow_list->set_model(OwnPtr(m_client.client_window_list_model())); subwindow_list->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); subwindow_list->set_preferred_size({ 120, 0 }); - subwindow_list->add_item("Server"); - subwindow_list->add_item("#test"); m_subwindow_container = new GWidget(widget); m_subwindow_container->set_layout(make(Orientation::Vertical)); @@ -54,8 +58,17 @@ void IRCAppWindow::setup_widgets() create_subwindow(IRCClientWindow::Server, "Server"); } -void IRCAppWindow::create_subwindow(IRCClientWindow::Type type, const String& name) +IRCClientWindow& IRCAppWindow::create_subwindow(IRCClientWindow::Type type, const String& name) { - auto* subwindow = new IRCClientWindow(m_client, type, name, m_subwindow_container); - m_subwindows.append(subwindow); + return *new IRCClientWindow(m_client, type, name, m_subwindow_container); +} + +IRCClientWindow& IRCAppWindow::ensure_window(IRCClientWindow::Type type, const String& name) +{ + for (int i = 0; i < m_client.window_count(); ++i) { + auto& window = m_client.window_at(i); + if (window.name() == name) + return window; + } + return create_subwindow(type, name); } diff --git a/Applications/IRCClient/IRCAppWindow.h b/Applications/IRCClient/IRCAppWindow.h index 33b7404659..fb57f7cd77 100644 --- a/Applications/IRCClient/IRCAppWindow.h +++ b/Applications/IRCClient/IRCAppWindow.h @@ -14,10 +14,10 @@ private: void setup_client(); void setup_widgets(); - void create_subwindow(IRCClientWindow::Type, const String& name); + IRCClientWindow& create_subwindow(IRCClientWindow::Type, const String& name); + IRCClientWindow& ensure_window(IRCClientWindow::Type, const String& name); IRCClient m_client; GWidget* m_subwindow_container { nullptr }; - Vector m_subwindows; }; diff --git a/Applications/IRCClient/IRCClient.cpp b/Applications/IRCClient/IRCClient.cpp index d441da15d2..e36145d01b 100644 --- a/Applications/IRCClient/IRCClient.cpp +++ b/Applications/IRCClient/IRCClient.cpp @@ -3,6 +3,7 @@ #include "IRCQuery.h" #include "IRCLogBuffer.h" #include "IRCClientWindow.h" +#include "IRCClientWindowListModel.h" #include #include #include @@ -21,6 +22,7 @@ IRCClient::IRCClient(const String& address, int port) , m_nickname("anon") , m_log(IRCLogBuffer::create()) { + m_client_window_list_model = new IRCClientWindowListModel(*this); } IRCClient::~IRCClient() @@ -62,11 +64,11 @@ bool IRCClient::connect() m_notifier = make(m_socket_fd, GNotifier::Read); m_notifier->on_ready_to_read = [this] (GNotifier&) { receive_from_server(); }; - if (on_connect) - on_connect(); - send_user(); send_nick(); + + if (on_connect) + on_connect(); return true; } @@ -102,9 +104,6 @@ void IRCClient::receive_from_server() void IRCClient::process_line() { -#if 0 - printf("Process line: '%s'\n", line.characters()); -#endif Message msg; Vector prefix; Vector command; @@ -118,8 +117,7 @@ void IRCClient::process_line() InTrailingParameter, } state = Start; - for (int i = 0; i < m_line_buffer.size(); ++i) { - char ch = m_line_buffer[i]; + for (char ch : m_line_buffer) { switch (state) { case Start: if (ch == ':') { @@ -316,6 +314,8 @@ void IRCClient::handle_join(const Message& msg) ASSERT(it == m_channels.end()); auto channel = IRCChannel::create(*this, channel_name); m_channels.set(channel_name, move(channel)); + if (on_join) + on_join(channel_name); } void IRCClient::handle_namreply(const Message& msg) @@ -351,24 +351,28 @@ void IRCClient::register_subwindow(IRCClientWindow& subwindow) if (subwindow.type() == IRCClientWindow::Server) { m_server_subwindow = &subwindow; subwindow.set_log_buffer(*m_log); - return; - } - if (subwindow.type() == IRCClientWindow::Channel) { + } else if (subwindow.type() == IRCClientWindow::Channel) { auto it = m_channels.find(subwindow.name()); ASSERT(it != m_channels.end()); auto& channel = *(*it).value; subwindow.set_log_buffer(channel.log()); - return; - } - if (subwindow.type() == IRCClientWindow::Query) { + } else if (subwindow.type() == IRCClientWindow::Query) { subwindow.set_log_buffer(ensure_query(subwindow.name()).log()); } + m_windows.append(&subwindow); + m_client_window_list_model->update(); } void IRCClient::unregister_subwindow(IRCClientWindow& subwindow) { if (subwindow.type() == IRCClientWindow::Server) { m_server_subwindow = &subwindow; - return; } + for (int i = 0; i < m_windows.size(); ++i) { + if (m_windows.at(i) == &subwindow) { + m_windows.remove(i); + break; + } + } + m_client_window_list_model->update(); } diff --git a/Applications/IRCClient/IRCClient.h b/Applications/IRCClient/IRCClient.h index 028260ee20..fffa333aec 100644 --- a/Applications/IRCClient/IRCClient.h +++ b/Applications/IRCClient/IRCClient.h @@ -9,6 +9,7 @@ class IRCChannel; class IRCQuery; class IRCClientWindow; +class IRCClientWindowListModel; class GNotifier; class IRCClient { @@ -31,11 +32,19 @@ public: Function on_disconnect; Function on_channel_message; Function on_query_message; + Function on_join; Function on_server_message; void register_subwindow(IRCClientWindow&); void unregister_subwindow(IRCClientWindow&); + IRCClientWindowListModel* client_window_list_model() { return m_client_window_list_model; } + const IRCClientWindowListModel* client_window_list_model() const { return m_client_window_list_model; } + + int window_count() const { return m_windows.size(); } + const IRCClientWindow& window_at(int index) const { return *m_windows.at(index); } + IRCClientWindow& window_at(int index) { return *m_windows.at(index); } + private: struct Message { String prefix; @@ -66,7 +75,11 @@ private: HashMap> m_channels; HashMap> m_queries; + Vector m_windows; + IRCClientWindow* m_server_subwindow { nullptr }; + IRCClientWindowListModel* m_client_window_list_model { nullptr }; + Retained m_log; }; diff --git a/Applications/IRCClient/IRCClientWindowListModel.cpp b/Applications/IRCClient/IRCClientWindowListModel.cpp new file mode 100644 index 0000000000..77a47b0019 --- /dev/null +++ b/Applications/IRCClient/IRCClientWindowListModel.cpp @@ -0,0 +1,57 @@ +#include "IRCClientWindowListModel.h" +#include "IRCClientWindow.h" +#include "IRCClient.h" +#include +#include + +IRCClientWindowListModel::IRCClientWindowListModel(IRCClient& client) + : m_client(client) +{ +} + +IRCClientWindowListModel::~IRCClientWindowListModel() +{ +} + +int IRCClientWindowListModel::row_count() const +{ + return m_client.window_count(); +} + +int IRCClientWindowListModel::column_count() const +{ + return 1; +} + +String IRCClientWindowListModel::column_name(int column) const +{ + switch (column) { + case Column::Name: return "Name"; + } + ASSERT_NOT_REACHED(); +} + +GTableModel::ColumnMetadata IRCClientWindowListModel::column_metadata(int column) const +{ + switch (column) { + case Column::Name: return { 70, TextAlignment::CenterLeft }; + } + ASSERT_NOT_REACHED(); +} + +GVariant IRCClientWindowListModel::data(const GModelIndex& index, Role) const +{ + switch (index.column()) { + case Column::Name: return m_client.window_at(index.row()).name(); + } + ASSERT_NOT_REACHED(); +} + +void IRCClientWindowListModel::update() +{ + did_update(); +} + +void IRCClientWindowListModel::activate(const GModelIndex&) +{ +} diff --git a/Applications/IRCClient/IRCClientWindowListModel.h b/Applications/IRCClient/IRCClientWindowListModel.h new file mode 100644 index 0000000000..686a000f7a --- /dev/null +++ b/Applications/IRCClient/IRCClientWindowListModel.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +class IRCClient; + +class IRCClientWindowListModel final : public GTableModel { +public: + enum Column { + Name, + }; + + explicit IRCClientWindowListModel(IRCClient&); + virtual ~IRCClientWindowListModel() override; + + virtual int row_count() const override; + virtual int column_count() const override; + virtual String column_name(int column) const override; + virtual ColumnMetadata column_metadata(int column) const override; + virtual GVariant data(const GModelIndex&, Role = Role::Display) const override; + virtual void update() override; + virtual void activate(const GModelIndex&) override; + +private: + IRCClient& m_client; +}; diff --git a/Applications/IRCClient/Makefile b/Applications/IRCClient/Makefile index 29e0ba1573..deb9ba1130 100644 --- a/Applications/IRCClient/Makefile +++ b/Applications/IRCClient/Makefile @@ -6,6 +6,7 @@ OBJS = \ IRCLogBufferModel.o \ IRCAppWindow.o \ IRCClientWindow.o \ + IRCClientWindowListModel.o \ main.o APP = IRCClient