Explorar el Código

IRCClient: Use a model for the window list.

Andreas Kling hace 6 años
padre
commit
a23dddc56f

+ 20 - 7
Applications/IRCClient/IRCAppWindow.cpp

@@ -1,6 +1,7 @@
 #include "IRCAppWindow.h"
 #include "IRCClientWindow.h"
-#include <LibGUI/GListBox.h>
+#include "IRCClientWindowListModel.h"
+#include <LibGUI/GTableView.h>
 #include <LibGUI/GBoxLayout.h>
 
 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<GBoxLayout>(Orientation::Horizontal));
 
-    auto* subwindow_list = new GListBox(widget);
+    auto* subwindow_list = new GTableView(widget);
+    subwindow_list->set_model(OwnPtr<IRCClientWindowListModel>(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<GBoxLayout>(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)
+{
+    return *new IRCClientWindow(m_client, type, name, m_subwindow_container);
+}
+
+IRCClientWindow& IRCAppWindow::ensure_window(IRCClientWindow::Type type, const String& name)
 {
-    auto* subwindow = new IRCClientWindow(m_client, type, name, m_subwindow_container);
-    m_subwindows.append(subwindow);
+    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);
 }

+ 2 - 2
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<IRCClientWindow*> m_subwindows;
 };

+ 19 - 15
Applications/IRCClient/IRCClient.cpp

@@ -3,6 +3,7 @@
 #include "IRCQuery.h"
 #include "IRCLogBuffer.h"
 #include "IRCClientWindow.h"
+#include "IRCClientWindowListModel.h"
 #include <LibGUI/GNotifier.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -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<GNotifier>(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<char> prefix;
     Vector<char> 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();
 }

+ 13 - 0
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<void()> on_disconnect;
     Function<void(const String& channel)> on_channel_message;
     Function<void(const String& name)> on_query_message;
+    Function<void(const String& channel)> on_join;
     Function<void()> 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<String, RetainPtr<IRCChannel>> m_channels;
     HashMap<String, RetainPtr<IRCQuery>> m_queries;
 
+    Vector<IRCClientWindow*> m_windows;
+
     IRCClientWindow* m_server_subwindow { nullptr };
 
+    IRCClientWindowListModel* m_client_window_list_model { nullptr };
+
     Retained<IRCLogBuffer> m_log;
 };

+ 57 - 0
Applications/IRCClient/IRCClientWindowListModel.cpp

@@ -0,0 +1,57 @@
+#include "IRCClientWindowListModel.h"
+#include "IRCClientWindow.h"
+#include "IRCClient.h"
+#include <stdio.h>
+#include <time.h>
+
+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&)
+{
+}

+ 26 - 0
Applications/IRCClient/IRCClientWindowListModel.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include <LibGUI/GTableModel.h>
+
+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;
+};

+ 1 - 0
Applications/IRCClient/Makefile

@@ -6,6 +6,7 @@ OBJS = \
     IRCLogBufferModel.o \
     IRCAppWindow.o \
     IRCClientWindow.o \
+    IRCClientWindowListModel.o \
     main.o
 
 APP = IRCClient