232 lines
7.6 KiB
C++
232 lines
7.6 KiB
C++
|
|
#include <QApplication>
|
||
|
|
#include <QMainWindow>
|
||
|
|
#include <QWidget>
|
||
|
|
#include <QVBoxLayout>
|
||
|
|
#include <QHBoxLayout>
|
||
|
|
#include <QTextEdit>
|
||
|
|
#include <QLineEdit>
|
||
|
|
#include <QPushButton>
|
||
|
|
#include <QLabel>
|
||
|
|
#include <QColorDialog>
|
||
|
|
#include <QSlider>
|
||
|
|
#include <QSpinBox>
|
||
|
|
#include <QSslSocket>
|
||
|
|
#include <QHostAddress>
|
||
|
|
#include <QMessageBox>
|
||
|
|
#include <QThread>
|
||
|
|
#include <iostream>
|
||
|
|
|
||
|
|
class ChatClient : public QMainWindow {
|
||
|
|
Q_OBJECT
|
||
|
|
|
||
|
|
public:
|
||
|
|
ChatClient(QWidget *parent = nullptr) : QMainWindow(parent) {
|
||
|
|
setWindowTitle("SCAR Chat Client");
|
||
|
|
setGeometry(100, 100, 800, 600);
|
||
|
|
|
||
|
|
// Create central widget
|
||
|
|
QWidget *central = new QWidget(this);
|
||
|
|
setCentralWidget(central);
|
||
|
|
|
||
|
|
// Main layout
|
||
|
|
QVBoxLayout *main_layout = new QVBoxLayout(central);
|
||
|
|
|
||
|
|
// Connection section
|
||
|
|
QHBoxLayout *conn_layout = new QHBoxLayout();
|
||
|
|
QLabel *host_label = new QLabel("Host:", this);
|
||
|
|
host_input = new QLineEdit("localhost", this);
|
||
|
|
QLabel *port_label = new QLabel("Port:", this);
|
||
|
|
port_input = new QLineEdit("42317", this);
|
||
|
|
connect_btn = new QPushButton("Connect", this);
|
||
|
|
conn_layout->addWidget(host_label);
|
||
|
|
conn_layout->addWidget(host_input);
|
||
|
|
conn_layout->addWidget(port_label);
|
||
|
|
conn_layout->addWidget(port_input);
|
||
|
|
conn_layout->addWidget(connect_btn);
|
||
|
|
main_layout->addLayout(conn_layout);
|
||
|
|
|
||
|
|
// Chat display
|
||
|
|
chat_display = new QTextEdit(this);
|
||
|
|
chat_display->setReadOnly(true);
|
||
|
|
main_layout->addWidget(chat_display);
|
||
|
|
|
||
|
|
// Message input
|
||
|
|
QHBoxLayout *msg_layout = new QHBoxLayout();
|
||
|
|
message_input = new QLineEdit(this);
|
||
|
|
send_btn = new QPushButton("Send", this);
|
||
|
|
msg_layout->addWidget(message_input);
|
||
|
|
msg_layout->addWidget(send_btn);
|
||
|
|
main_layout->addLayout(msg_layout);
|
||
|
|
|
||
|
|
// Settings section
|
||
|
|
QHBoxLayout *settings_layout = new QHBoxLayout();
|
||
|
|
|
||
|
|
// Background color
|
||
|
|
bg_color_btn = new QPushButton("BG Color", this);
|
||
|
|
settings_layout->addWidget(bg_color_btn);
|
||
|
|
|
||
|
|
// Chat text color
|
||
|
|
text_color_btn = new QPushButton("Text Color", this);
|
||
|
|
settings_layout->addWidget(text_color_btn);
|
||
|
|
|
||
|
|
// Transparency slider
|
||
|
|
QLabel *trans_label = new QLabel("Transparency:", this);
|
||
|
|
transparency_slider = new QSlider(Qt::Horizontal, this);
|
||
|
|
transparency_slider->setMinimum(0);
|
||
|
|
transparency_slider->setMaximum(100);
|
||
|
|
transparency_slider->setValue(100);
|
||
|
|
transparency_value = new QLabel("100%", this);
|
||
|
|
settings_layout->addWidget(trans_label);
|
||
|
|
settings_layout->addWidget(transparency_slider);
|
||
|
|
settings_layout->addWidget(transparency_value);
|
||
|
|
|
||
|
|
main_layout->addLayout(settings_layout);
|
||
|
|
|
||
|
|
// Connect signals
|
||
|
|
connect(connect_btn, &QPushButton::clicked, this, &ChatClient::on_connect);
|
||
|
|
connect(send_btn, &QPushButton::clicked, this, &ChatClient::on_send_message);
|
||
|
|
connect(message_input, &QLineEdit::returnPressed, this, &ChatClient::on_send_message);
|
||
|
|
connect(bg_color_btn, &QPushButton::clicked, this, &ChatClient::on_bg_color);
|
||
|
|
connect(text_color_btn, &QPushButton::clicked, this, &ChatClient::on_text_color);
|
||
|
|
connect(transparency_slider, &QSlider::valueChanged, this, &ChatClient::on_transparency_changed);
|
||
|
|
|
||
|
|
// Initialize socket
|
||
|
|
socket = new QSslSocket(this);
|
||
|
|
connect(socket, &QSslSocket::connected, this, &ChatClient::on_socket_connected);
|
||
|
|
connect(socket, &QSslSocket::disconnected, this, &ChatClient::on_socket_disconnected);
|
||
|
|
connect(socket, &QSslSocket::readyRead, this, &ChatClient::on_socket_read);
|
||
|
|
connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QSslSocket::error),
|
||
|
|
this, &ChatClient::on_socket_error);
|
||
|
|
connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors),
|
||
|
|
this, &ChatClient::on_ssl_errors);
|
||
|
|
|
||
|
|
// Initialize colors
|
||
|
|
bg_color = Qt::white;
|
||
|
|
text_color = Qt::black;
|
||
|
|
update_window_colors();
|
||
|
|
}
|
||
|
|
|
||
|
|
private slots:
|
||
|
|
void on_connect() {
|
||
|
|
if (socket->state() == QSslSocket::ConnectedState) {
|
||
|
|
socket->disconnectFromHost();
|
||
|
|
connect_btn->setText("Connect");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
QString host = host_input->text();
|
||
|
|
int port = port_input->text().toInt();
|
||
|
|
|
||
|
|
chat_display->append("[System] Connecting to " + host + ":" + QString::number(port) + "...");
|
||
|
|
socket->connectToHostEncrypted(host, port);
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_socket_connected() {
|
||
|
|
chat_display->append("[System] Connected to server!");
|
||
|
|
connect_btn->setText("Disconnect");
|
||
|
|
message_input->setFocus();
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_socket_disconnected() {
|
||
|
|
chat_display->append("[System] Disconnected from server");
|
||
|
|
connect_btn->setText("Connect");
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_socket_read() {
|
||
|
|
while (socket->canReadLine()) {
|
||
|
|
QString message = QString::fromUtf8(socket->readLine()).trimmed();
|
||
|
|
chat_display->append("[Server] " + message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_socket_error(QAbstractSocket::SocketError error) {
|
||
|
|
Q_UNUSED(error);
|
||
|
|
chat_display->append("[Error] " + socket->errorString());
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_ssl_errors(const QList<QSslError> &errors) {
|
||
|
|
// For development: ignore self-signed certificate errors
|
||
|
|
// In production, properly validate certificates
|
||
|
|
for (const QSslError &error : errors) {
|
||
|
|
std::cerr << "SSL Error: " << error.errorString().toStdString() << std::endl;
|
||
|
|
}
|
||
|
|
socket->ignoreSslErrors();
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_send_message() {
|
||
|
|
if (socket->state() != QSslSocket::ConnectedState) {
|
||
|
|
chat_display->append("[System] Not connected!");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
QString message = message_input->text();
|
||
|
|
if (message.isEmpty()) return;
|
||
|
|
|
||
|
|
socket->write(message.toUtf8() + "\n");
|
||
|
|
chat_display->append("[You] " + message);
|
||
|
|
message_input->clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_bg_color() {
|
||
|
|
QColor color = QColorDialog::getColor(bg_color, this, "Select Background Color");
|
||
|
|
if (color.isValid()) {
|
||
|
|
bg_color = color;
|
||
|
|
update_window_colors();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_text_color() {
|
||
|
|
QColor color = QColorDialog::getColor(text_color, this, "Select Text Color");
|
||
|
|
if (color.isValid()) {
|
||
|
|
text_color = color;
|
||
|
|
update_window_colors();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void on_transparency_changed(int value) {
|
||
|
|
transparency_value->setText(QString::number(value) + "%");
|
||
|
|
double opacity = value / 100.0;
|
||
|
|
setWindowOpacity(opacity);
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
void update_window_colors() {
|
||
|
|
// Update chat display background and text colors
|
||
|
|
QString stylesheet = QString(
|
||
|
|
"QTextEdit { background-color: %1; color: %2; }"
|
||
|
|
"QLineEdit { background-color: %1; color: %2; }"
|
||
|
|
"QPushButton { background-color: %1; color: %2; border: 1px solid gray; padding: 4px; }"
|
||
|
|
"QLabel { color: %2; }"
|
||
|
|
"QSlider { color: %2; }"
|
||
|
|
).arg(bg_color.name()).arg(text_color.name());
|
||
|
|
|
||
|
|
setStyleSheet(stylesheet);
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
QLineEdit *host_input;
|
||
|
|
QLineEdit *port_input;
|
||
|
|
QPushButton *connect_btn;
|
||
|
|
QTextEdit *chat_display;
|
||
|
|
QLineEdit *message_input;
|
||
|
|
QPushButton *send_btn;
|
||
|
|
QPushButton *bg_color_btn;
|
||
|
|
QPushButton *text_color_btn;
|
||
|
|
QSlider *transparency_slider;
|
||
|
|
QLabel *transparency_value;
|
||
|
|
QSslSocket *socket;
|
||
|
|
QColor bg_color;
|
||
|
|
QColor text_color;
|
||
|
|
};
|
||
|
|
|
||
|
|
int main(int argc, char *argv[]) {
|
||
|
|
QApplication app(argc, argv);
|
||
|
|
|
||
|
|
ChatClient client;
|
||
|
|
client.show();
|
||
|
|
|
||
|
|
return app.exec();
|
||
|
|
}
|
||
|
|
|
||
|
|
#include "main.moc"
|