1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
#ifndef XTQ_H
#define XTQ_H
#include <cstdint>
#include <cstddef>
#include <functional>
#include <map>
#include <string>
#include <vector>
#include <QAbstractListModel>
#include <QColor>
#include <QHash>
#include <QObject>
#include <QString>
#include <QTcpSocket>
#include <QTextCharFormat>
#include <QTimer>
#include <QVariant>
#include <QtQmlIntegration/qqmlintegration.h>
#include <QQuickTextDocument>
// Forward declarations for Relay protocol
namespace Relay {
class CommandData;
class EventMessage;
class ResponseData;
enum class ServerState : int8_t;
enum class BufferKind : int8_t;
enum class Rendition : int8_t;
class ItemData;
}
// --- Data structures ---------------------------------------------------------
struct Server {
Relay::ServerState state = {};
QString user;
QString user_modes;
};
struct BufferLineItem {
QTextCharFormat format = {};
QString text;
};
struct BufferLine {
/// Leaked from another buffer, but temporarily staying in another one.
bool leaked = {};
bool is_unimportant = {};
bool is_highlight = {};
Relay::Rendition rendition = {};
uint64_t when = {};
std::vector<BufferLineItem> items;
};
struct Buffer {
QString buffer_name;
bool hide_unimportant = {};
Relay::BufferKind kind = {};
QString server_name;
std::vector<BufferLine> lines;
// Channel:
std::vector<BufferLineItem> topic;
QString modes;
// Stats:
uint32_t new_messages = {};
uint32_t new_unimportant_messages = {};
bool highlighted = {};
// Input (stored as rich text):
QString input;
int input_start = {};
int input_end = {};
std::vector<QString> history;
size_t history_at = {};
};
using Callback = std::function<
void(std::wstring error, const Relay::ResponseData *response)>;
// --- Buffer list model -------------------------------------------------------
class BufferListModel : public QAbstractListModel {
Q_OBJECT
QML_ELEMENT
public:
enum Roles {
BufferNameRole = Qt::UserRole + 1,
BufferKindRole,
ServerNameRole,
NewMessagesRole,
HighlightedRole,
DisplayTextRole,
IsBoldRole,
HighlightColorRole
};
explicit BufferListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const override;
void setBuffers(const std::vector<Buffer> *buffers);
void setCurrentBuffer(const QString ¤t);
Q_INVOKABLE int getCurrentBufferIndex() const;
void refresh();
void refreshBuffer(int index);
void bufferAdded(int index);
void bufferRemoved(int index);
signals:
void bufferActivated(const QString &bufferName);
private:
const std::vector<Buffer> *buffers_ = nullptr;
QString current;
};
// --- Main relay connection ---------------------------------------------------
class RelayConnection : public QObject {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString host READ host WRITE setHost NOTIFY hostChanged)
Q_PROPERTY(QString port READ port WRITE setPort NOTIFY portChanged)
Q_PROPERTY(bool connected READ isConnected NOTIFY connectedChanged)
Q_PROPERTY(QString currentBuffer READ currentBuffer NOTIFY currentBufferChanged)
Q_PROPERTY(QString prompt READ prompt NOTIFY promptChanged)
Q_PROPERTY(QString status READ status NOTIFY statusChanged)
Q_PROPERTY(QString topic READ topic NOTIFY topicChanged)
Q_PROPERTY(BufferListModel *bufferListModel READ bufferListModel CONSTANT)
public:
explicit RelayConnection(QObject *parent = nullptr);
QString host() const { return host_; }
void setHost(const QString &host);
QString port() const { return port_; }
void setPort(const QString &port);
bool isConnected() const;
QString currentBuffer() const { return buffer_current; }
QString prompt() const;
QString status() const;
QString topic() const;
BufferListModel *bufferListModel() { return &buffer_list_model; }
Q_INVOKABLE void connectToRelay();
Q_INVOKABLE void disconnectFromRelay();
Q_INVOKABLE void activateBuffer(const QString &name);
Q_INVOKABLE void activatePreviousBuffer();
Q_INVOKABLE void activateNextBuffer();
Q_INVOKABLE void toggleUnimportant();
Q_INVOKABLE void sendInput(const QString &input);
Q_INVOKABLE void sendCommand(const QString &command);
Q_INVOKABLE void populateBufferDocument(QQuickTextDocument *document);
Q_INVOKABLE QString getInputHistoryUp();
Q_INVOKABLE QString getInputHistoryDown();
Q_INVOKABLE void requestCompletion(const QString &text, int position);
Q_INVOKABLE void activateLastBuffer();
Q_INVOKABLE void activateNextHighlighted();
Q_INVOKABLE void activateNextWithActivity();
Q_INVOKABLE void toggleBufferLog();
Q_INVOKABLE void saveBufferInput(const QString &bufferName, const QString &input, int start, int end);
Q_INVOKABLE QString getBufferInput();
Q_INVOKABLE int getBufferInputStart();
Q_INVOKABLE int getBufferInputEnd();
signals:
void hostChanged();
void portChanged();
void connectedChanged();
void aboutToChangeBuffer(const QString &oldBuffer);
void currentBufferChanged();
void promptChanged();
void statusChanged();
void topicChanged();
void errorOccurred(const QString &message);
void beepRequested();
void completionResult(const QString &completion);
void bufferTextChanged();
void logViewChanged(const QString &logText);
private slots:
void onSocketConnected();
void onSocketDisconnected();
void onSocketReadyRead();
void onSocketError(QAbstractSocket::SocketError error);
private:
void relaySend(Relay::CommandData *data, Callback callback = {});
void processRelayEvent(const Relay::EventMessage &m);
Buffer *bufferByName(const QString &name);
void refreshPrompt();
void refreshStatus();
void refreshTopic();
void refreshIcon();
void recheckHighlighted();
QTcpSocket *socket;
QString host_;
QString port_;
uint32_t command_seq = 0;
std::map<uint32_t, Callback> command_callbacks;
std::vector<Buffer> buffers;
QString buffer_current;
QString buffer_last;
std::map<QString, Server> servers;
BufferListModel buffer_list_model;
QTimer *date_change_timer;
};
#endif // XTQ_H
|