1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:07:35 +00:00

IRCClient: Hacking on IRCClient bringup.

This commit is contained in:
Andreas Kling 2019-03-15 13:07:04 +01:00
parent aa19735c5a
commit 850c7504a2
11 changed files with 210 additions and 12 deletions

View file

@ -44,11 +44,22 @@ void IRCAppWindow::setup_widgets()
auto* subwindow_list = new GListBox(widget);
subwindow_list->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
subwindow_list->set_preferred_size({ 120, 0 });
subwindow_list->add_item("test1");
subwindow_list->add_item("test2");
subwindow_list->add_item("test3");
subwindow_list->add_item("Server");
subwindow_list->add_item("#test");
auto* container = new GWidget(widget);
m_subwindow_container = new GWidget(widget);
m_subwindow_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
m_subwindow_container->set_fill_with_background_color(true);
m_subwindow_container->set_background_color(Color::Yellow);
m_subwindow_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fill);
auto* subwindow = new IRCSubWindow("Server", container);
create_subwindow(IRCSubWindow::Server, "Server");
}
void IRCAppWindow::create_subwindow(IRCSubWindow::Type type, const String& name)
{
auto* subwindow = new IRCSubWindow(m_client, type, name, m_subwindow_container);
subwindow->set_fill_with_background_color(true);
subwindow->set_background_color(Color::Magenta);
m_subwindows.append(subwindow);
}

View file

@ -3,6 +3,7 @@
#include <LibGUI/GWindow.h>
#include <LibGUI/GWidget.h>
#include "IRCClient.h"
#include "IRCSubWindow.h"
class IRCAppWindow : public GWindow {
public:
@ -13,5 +14,10 @@ private:
void setup_client();
void setup_widgets();
void create_subwindow(IRCSubWindow::Type, const String& name);
IRCClient m_client;
GWidget* m_subwindow_container { nullptr };
Vector<IRCSubWindow*> m_subwindows;
};

View file

@ -1,6 +1,8 @@
#include "IRCClient.h"
#include "IRCChannel.h"
#include "IRCQuery.h"
#include "IRCLogBuffer.h"
#include "IRCSubWindow.h"
#include <LibGUI/GNotifier.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -17,6 +19,7 @@ IRCClient::IRCClient(const String& address, int port)
: m_hostname(address)
, m_port(port)
, m_nickname("anon")
, m_log(IRCLogBuffer::create())
{
}
@ -165,7 +168,7 @@ void IRCClient::process_line()
msg.arguments.append(String(current_parameter.data(), current_parameter.size()));
msg.prefix = String(prefix.data(), prefix.size());
msg.command = String(command.data(), command.size());
handle(msg);
handle(msg, String(m_line_buffer.data(), m_line_buffer.size()));
}
void IRCClient::send(const String& text)
@ -198,7 +201,7 @@ void IRCClient::join_channel(const String& channel_name)
send(String::format("JOIN %s\r\n", channel_name.characters()));
}
void IRCClient::handle(const Message& msg)
void IRCClient::handle(const Message& msg, const String& verbatim)
{
printf("IRCClient::execute: prefix='%s', command='%s', arguments=%d\n",
msg.prefix.characters(),
@ -231,6 +234,8 @@ void IRCClient::handle(const Message& msg)
if (msg.command == "PRIVMSG")
return handle_privmsg(msg);
m_log->add_message(0, "Server", verbatim);
}
bool IRCClient::is_nick_prefix(char ch) const
@ -297,7 +302,7 @@ void IRCClient::handle_ping(const Message& msg)
{
if (msg.arguments.size() < 0)
return;
m_server_messages.enqueue(String::format("Ping? Pong! %s\n", msg.arguments[0].characters()));
m_log->add_message(0, "", String::format("Ping? Pong! %s\n", msg.arguments[0].characters()));
send_pong(msg.arguments[0]);
}
@ -339,3 +344,30 @@ void IRCClient::handle_namreply(const Message& msg)
channel.dump();
}
void IRCClient::register_subwindow(IRCSubWindow& subwindow)
{
if (subwindow.type() == IRCSubWindow::Server) {
m_server_subwindow = &subwindow;
subwindow.set_log_buffer(*m_log);
return;
}
if (subwindow.type() == IRCSubWindow::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() == IRCSubWindow::Query) {
subwindow.set_log_buffer(ensure_query(subwindow.name()).log());
}
}
void IRCClient::unregister_subwindow(IRCSubWindow& subwindow)
{
if (subwindow.type() == IRCSubWindow::Server) {
m_server_subwindow = &subwindow;
return;
}
}

View file

@ -4,9 +4,11 @@
#include <AK/HashMap.h>
#include <AK/CircularQueue.h>
#include <AK/Function.h>
#include "IRCLogBuffer.h"
class IRCChannel;
class IRCQuery;
class IRCSubWindow;
class GNotifier;
class IRCClient {
@ -31,6 +33,9 @@ public:
Function<void(const String& name)> on_query_message;
Function<void()> on_server_message;
void register_subwindow(IRCSubWindow&);
void unregister_subwindow(IRCSubWindow&);
private:
struct Message {
String prefix;
@ -48,7 +53,7 @@ private:
void handle_ping(const Message&);
void handle_namreply(const Message&);
void handle_privmsg(const Message&);
void handle(const Message&);
void handle(const Message&, const String& verbatim);
IRCQuery& ensure_query(const String& name);
String m_hostname;
@ -61,5 +66,7 @@ private:
HashMap<String, RetainPtr<IRCChannel>> m_channels;
HashMap<String, RetainPtr<IRCQuery>> m_queries;
CircularQueue<String, 1024> m_server_messages;
IRCSubWindow* m_server_subwindow { nullptr };
Retained<IRCLogBuffer> m_log;
};

View file

@ -1,4 +1,5 @@
#include "IRCLogBuffer.h"
#include "IRCLogBufferModel.h"
#include <stdio.h>
#include <time.h>
@ -9,6 +10,7 @@ Retained<IRCLogBuffer> IRCLogBuffer::create()
IRCLogBuffer::IRCLogBuffer()
{
m_model = new IRCLogBufferModel(*this);
}
IRCLogBuffer::~IRCLogBuffer()
@ -18,6 +20,7 @@ IRCLogBuffer::~IRCLogBuffer()
void IRCLogBuffer::add_message(char prefix, const String& name, const String& text)
{
m_messages.enqueue({ time(nullptr), prefix, name, text });
m_model->update();
}
void IRCLogBuffer::dump() const

View file

@ -5,6 +5,8 @@
#include <AK/Retainable.h>
#include <AK/RetainPtr.h>
class IRCLogBufferModel;
class IRCLogBuffer : public Retainable<IRCLogBuffer> {
public:
static Retained<IRCLogBuffer> create();
@ -24,8 +26,13 @@ public:
void dump() const;
const IRCLogBufferModel* model() const { return m_model; }
IRCLogBufferModel* model() { return m_model; }
private:
IRCLogBuffer();
IRCLogBufferModel* m_model { nullptr };
CircularQueue<Message, 1000> m_messages;
};

View file

@ -0,0 +1,65 @@
#include "IRCLogBufferModel.h"
#include "IRCLogBuffer.h"
#include <stdio.h>
IRCLogBufferModel::IRCLogBufferModel(Retained<IRCLogBuffer>&& log_buffer)
: m_log_buffer(move(log_buffer))
{
}
IRCLogBufferModel::~IRCLogBufferModel()
{
}
int IRCLogBufferModel::row_count() const
{
return m_log_buffer->count();
}
int IRCLogBufferModel::column_count() const
{
return 4;
}
String IRCLogBufferModel::column_name(int column) const
{
switch (column) {
case Column::Timestamp: return "Time";
case Column::Prefix: return "@";
case Column::Name: return "Name";
case Column::Text: return "Text";
}
ASSERT_NOT_REACHED();
}
GTableModel::ColumnMetadata IRCLogBufferModel::column_metadata(int column) const
{
switch (column) {
case Column::Timestamp: return { 90, TextAlignment::CenterLeft };
case Column::Prefix: return { 10, TextAlignment::CenterLeft };
case Column::Name: return { 70, TextAlignment::CenterRight };
case Column::Text: return { 400, TextAlignment::CenterLeft };
}
ASSERT_NOT_REACHED();
}
GVariant IRCLogBufferModel::data(const GModelIndex& index, Role role) const
{
auto& entry = m_log_buffer->at(index.row());
switch (index.column()) {
case Column::Timestamp: return String::format("%u", entry.timestamp);
case Column::Prefix: return entry.prefix;
case Column::Name: return entry.sender;
case Column::Text: return entry.text;
}
ASSERT_NOT_REACHED();
}
void IRCLogBufferModel::update()
{
did_update();
}
void IRCLogBufferModel::activate(const GModelIndex&)
{
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <LibGUI/GTableModel.h>
class IRCLogBuffer;
class IRCLogBufferModel final : public GTableModel {
public:
enum Column {
Timestamp = 0,
Prefix,
Name,
Text,
};
explicit IRCLogBufferModel(Retained<IRCLogBuffer>&&);
virtual ~IRCLogBufferModel() 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:
Retained<IRCLogBuffer> m_log_buffer;
};

View file

@ -1,11 +1,30 @@
#include "IRCSubWindow.h"
#include "IRCClient.h"
#include "IRCLogBufferModel.h"
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GTableView.h>
#include <LibGUI/GTextBox.h>
IRCSubWindow::IRCSubWindow(const String& name, GWidget* parent)
IRCSubWindow::IRCSubWindow(IRCClient& client, Type type, const String& name, GWidget* parent)
: GWidget(parent)
, m_client(client)
, m_type(type)
, m_name(name)
{
set_layout(make<GBoxLayout>(Orientation::Vertical));
m_table_view = new GTableView(this);
m_table_view->set_font(Font::default_fixed_width_font());
m_client.register_subwindow(*this);
}
IRCSubWindow::~IRCSubWindow()
{
m_client.unregister_subwindow(*this);
}
void IRCSubWindow::set_log_buffer(const IRCLogBuffer& log_buffer)
{
m_log_buffer = &log_buffer;
m_table_view->set_model(OwnPtr<IRCLogBufferModel>((IRCLogBufferModel*)log_buffer.model()));
}

View file

@ -2,14 +2,32 @@
#include <LibGUI/GWidget.h>
class IRCClient;
class IRCLogBuffer;
class GTableView;
class IRCSubWindow : public GWidget {
public:
explicit IRCSubWindow(const String& name, GWidget* parent);
enum Type {
Server,
Channel,
Query,
};
explicit IRCSubWindow(IRCClient&, Type, const String& name, GWidget* parent);
virtual ~IRCSubWindow() override;
String name() const { return m_name; }
void set_name(const String& name) { m_name = name; }
Type type() const { return m_type; }
void set_log_buffer(const IRCLogBuffer&);
private:
IRCClient& m_client;
Type m_type;
String m_name;
GTableView* m_table_view { nullptr };
RetainPtr<IRCLogBuffer> m_log_buffer;
};

View file

@ -3,6 +3,7 @@ OBJS = \
IRCChannel.o \
IRCQuery.o \
IRCLogBuffer.o \
IRCLogBufferModel.o \
IRCAppWindow.o \
IRCSubWindow.o \
main.o