#ifndef XTQ_H #define XTQ_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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 items; }; struct Buffer { QString buffer_name; bool hide_unimportant = {}; Relay::BufferKind kind = {}; QString server_name; std::vector lines; // Channel: std::vector 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 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 roleNames() const override; void setBuffers(const std::vector *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 *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 command_callbacks; std::vector buffers; QString buffer_current; QString buffer_last; std::map servers; BufferListModel buffer_list_model; QTimer *date_change_timer; }; #endif // XTQ_H