mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:57:35 +00:00
IRCClient: Hacking on IRCClient bringup.
This commit is contained in:
parent
aa19735c5a
commit
850c7504a2
11 changed files with 210 additions and 12 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
65
Applications/IRCClient/IRCLogBufferModel.cpp
Normal file
65
Applications/IRCClient/IRCLogBufferModel.cpp
Normal 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&)
|
||||
{
|
||||
}
|
29
Applications/IRCClient/IRCLogBufferModel.h
Normal file
29
Applications/IRCClient/IRCLogBufferModel.h
Normal 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;
|
||||
};
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@ OBJS = \
|
|||
IRCChannel.o \
|
||||
IRCQuery.o \
|
||||
IRCLogBuffer.o \
|
||||
IRCLogBufferModel.o \
|
||||
IRCAppWindow.o \
|
||||
IRCSubWindow.o \
|
||||
main.o
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue