diff --git a/Client/.gitignore b/Client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..46e947f7f60e5f095569673939896a29c2a39d35 --- /dev/null +++ b/Client/.gitignore @@ -0,0 +1,43 @@ +# C++ objects and libs +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es +object_script.*.Release +object_script.*.Debug +*_plugin_import.cpp +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +moc_*.h +qrc_*.cpp +ui_*.h +*.qmlc +*.jsc +Makefile* +*build-* + +# Qt unit tests +target_wrapper.* + +# QtCreator +*.autosave + +# QtCreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCreator CMake +CMakeLists.txt.user* diff --git a/Client/Client.pro b/Client/Client.pro index 0f9b39f53e0e467c2326ca8ceb145a101c1df862..853be7688dab6ffc11252033badc81bdbe12410d 100644 --- a/Client/Client.pro +++ b/Client/Client.pro @@ -1,4 +1,4 @@ -QT += core gui +QT += core gui network sql greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -16,17 +16,46 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ + Session/abstractsession.cpp \ + Session/offlinesession.cpp \ + Session/onlinesession.cpp \ + clientdatacenter.cpp \ + clientmain.cpp \ + databaseoperation.cpp \ + kuang.cpp \ main.cpp \ - clientmainwindow.cpp + mainwindow.cpp \ + message.cpp \ + messagemodel.cpp \ + userlogin.cpp \ + usermodel.cpp \ + userregister.cpp HEADERS += \ - clientmainwindow.h \ - ltest.h + Session/abstractsession.h \ + Session/offlinesession.h \ + Session/onlinesession.h \ + clientdatacenter.h \ + clientmain.h \ + databaseoperation.h \ + kuang.h \ + mainwindow.h \ + message.h \ + messagemodel.h \ + userlogin.h \ + usermodel.h \ + userregister.h FORMS += \ - clientmainwindow.ui + kuang.ui \ + mainwindow.ui \ + userlogin.ui \ + userregister.ui # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target + +RESOURCES += \ + rsc.qrc diff --git a/Client/Image/Frame.jpg b/Client/Image/Frame.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ebb42874be56a94951bfabddb9754fb81d69c99 Binary files /dev/null and b/Client/Image/Frame.jpg differ diff --git a/Client/Image/Luffy.png b/Client/Image/Luffy.png new file mode 100644 index 0000000000000000000000000000000000000000..f0410d86c5cd7170f470d3e05941f81edeb2b4c6 Binary files /dev/null and b/Client/Image/Luffy.png differ diff --git a/Client/Image/LuffyQ.png b/Client/Image/LuffyQ.png new file mode 100644 index 0000000000000000000000000000000000000000..580a2e5282c0bf533eeb8a32a890e1eb5f920a29 Binary files /dev/null and b/Client/Image/LuffyQ.png differ diff --git a/Client/Image/OnePiece.png b/Client/Image/OnePiece.png new file mode 100644 index 0000000000000000000000000000000000000000..f64ca90dab485f6ee612c8969ed76672df53cf57 Binary files /dev/null and b/Client/Image/OnePiece.png differ diff --git a/Client/Image/Sunny.jpg b/Client/Image/Sunny.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1eea0c44738af9016e9bbbada044ae2c35b549da Binary files /dev/null and b/Client/Image/Sunny.jpg differ diff --git a/Client/Image/butterfly.png b/Client/Image/butterfly.png new file mode 100644 index 0000000000000000000000000000000000000000..f3e050eca2bb56ac4d83a6850bc34849219f97bd Binary files /dev/null and b/Client/Image/butterfly.png differ diff --git a/Client/Image/butterfly1.png b/Client/Image/butterfly1.png new file mode 100644 index 0000000000000000000000000000000000000000..573f63c04bf919dadc64fb5204b4e770c91168dc Binary files /dev/null and b/Client/Image/butterfly1.png differ diff --git a/Client/Image/down.png b/Client/Image/down.png new file mode 100644 index 0000000000000000000000000000000000000000..4fc666e2458166fdf1604047f624bb6583767d83 Binary files /dev/null and b/Client/Image/down.png differ diff --git a/Client/Image/mario.gif b/Client/Image/mario.gif new file mode 100644 index 0000000000000000000000000000000000000000..c38a831bce2961674b50fcbd8772b24acd0ab0c4 Binary files /dev/null and b/Client/Image/mario.gif differ diff --git a/Client/Image/sunny.png b/Client/Image/sunny.png new file mode 100644 index 0000000000000000000000000000000000000000..4a7f5f50670626f6db6e5b585d146d17ed9979c3 Binary files /dev/null and b/Client/Image/sunny.png differ diff --git a/Client/Image/up.png b/Client/Image/up.png new file mode 100644 index 0000000000000000000000000000000000000000..b9095964ab9d6aeac8753db1bae526c7e9638fff Binary files /dev/null and b/Client/Image/up.png differ diff --git a/Client/Session/abstractsession.cpp b/Client/Session/abstractsession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b61ccbd9dcc019c66e356e1e5c365403ba1279f --- /dev/null +++ b/Client/Session/abstractsession.cpp @@ -0,0 +1,6 @@ +#include "abstractsession.h" + +AbstractSession::AbstractSession(QObject *parent) : QObject(parent) +{ + +} diff --git a/Client/Session/abstractsession.h b/Client/Session/abstractsession.h new file mode 100644 index 0000000000000000000000000000000000000000..6decd30fa45bf3c9e476bd12f0a8f5ba6ce8b62a --- /dev/null +++ b/Client/Session/abstractsession.h @@ -0,0 +1,32 @@ +#include +#include +#include "usermodel.h" + +#ifndef ABSTRACTSESSION_H +#define ABSTRACTSESSION_H + +using UserTypeName = QString; +using UserContainer = QList; + +class AbstractSession : virtual public QObject +{ + Q_OBJECT +public: + explicit AbstractSession(QObject *parent = nullptr); + + enum class SessionType { FRIEND, GROUP }; + + virtual SessionType getSessionType() const { + return members.size() == 2 ? SessionType::FRIEND : SessionType::GROUP; + } + + int getMemberCount() const { return members.size(); } + +protected: + UserContainer members; + +signals: + +}; + +#endif // ABSTRACTSESSION_H diff --git a/Client/Session/offlinesession.cpp b/Client/Session/offlinesession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be1cbcb07b87f12d8f476549e7a57c3cd0800255 --- /dev/null +++ b/Client/Session/offlinesession.cpp @@ -0,0 +1,15 @@ +#include "offlinesession.h" + +OfflineSession::OfflineSession(UserContainer Users, AbstractSession * parent) : QObject(parent) +{ + if (Users.size() < 2) throw "ValueError"; + members = Users; +} + +OfflineSession::OfflineSession(QList Users, AbstractSession * parent) : QObject(parent) +{ + if (Users.size() < 2) throw "ValueError"; + for (int i = 0; i != Users.size(); i++) { + members.append(Users.at(i)->getUsername()); + } +} diff --git a/Client/Session/offlinesession.h b/Client/Session/offlinesession.h new file mode 100644 index 0000000000000000000000000000000000000000..57f1074221b57884e106448bde873a70bed081de --- /dev/null +++ b/Client/Session/offlinesession.h @@ -0,0 +1,16 @@ +#ifndef OFFLINESESSION_H +#define OFFLINESESSION_H + +#include +#include "Session/abstractsession.h" + +class OfflineSession: public AbstractSession +{ + Q_OBJECT + +public: + OfflineSession(UserContainer Users, AbstractSession * parent = nullptr); + OfflineSession(QList Users, AbstractSession * parent = nullptr); +}; + +#endif // OFFLINESESSION_H diff --git a/Client/Session/onlinesession.cpp b/Client/Session/onlinesession.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10aa549b250e439e43296a03b0bf2a0e7dd33be3 --- /dev/null +++ b/Client/Session/onlinesession.cpp @@ -0,0 +1,64 @@ +#include "onlinesession.h" +#include + +OnlineSession::OnlineSession(QJsonObject &json, AbstractSession * parent) : + QObject(parent) +{ + loadDataFromJson(json); +} + +void OnlineSession::loadDataFromJson(const QJsonObject &json) +{ + id = json["SessionID"].toInt(); + loadUsersFromJson(json); + qDebug() << "debug" ; + Profile = json["Profile"].toObject(); + if ((getSessionType() == SessionType::GROUP && json["SessionType"] == "GROUP") + || (getSessionType() == SessionType::FRIEND && json["SessionType"] == "FRIEND") ) + { + if (getSessionType() == SessionType::GROUP) { + SessionName = Profile["SessionName"].toString(); + } + else { + SessionName = "foo"; + } + } + else { + qDebug() << "load error" ; + throw "load error"; + } +} + +const QString& OnlineSession::getSessionName() const { + if (getSessionType() == SessionType::FRIEND) + throw "FriendSession does not have a session name"; + return SessionName; +} + +void OnlineSession::loadUsersFromJson(const QJsonObject& json) +{ + QJsonArray userlist = json["Members"].toArray(); + + if (userlist.size() < 2) { qDebug() << "Value Error"; throw "userlist 至少需要两个 user 元素"; } + for (int i = 0; i < userlist.size(); i++) { + QString usrname = userlist.at(i).toObject()["Username"].toString(); + members.append(usrname); + } + qDebug() << "Load " << userlist.size() << " users from list"; +} + +QJsonObject OnlineSession::generateJsonFromData() const { + QJsonObject ret; + ret["MsgType"] = "SessionData"; + ret["SessionID"] = id; + ret["SessionType"] = getSessionType() == SessionType::GROUP ? "GROUP" : "FRIEND"; + ret["Profile"] = Profile; + QJsonArray userlist; + for (int i = 0; i < members.size(); i++) { + QJsonObject tmp; + tmp["username"] = members.at(i); + userlist.append(tmp); + } + ret["Members"] = userlist; + return ret; +} diff --git a/Client/Session/onlinesession.h b/Client/Session/onlinesession.h new file mode 100644 index 0000000000000000000000000000000000000000..5a37a8c4c7436ae6611ee20b742c9389561ab567 --- /dev/null +++ b/Client/Session/onlinesession.h @@ -0,0 +1,30 @@ +#ifndef ONLINESESSION_H +#define ONLINESESSION_H + +#include +#include "Session/abstractsession.h" + +class OnlineSession: public AbstractSession +{ + Q_OBJECT + +public: + OnlineSession(QJsonObject &json, AbstractSession * parent = nullptr); + OnlineSession(int sessionID, QString sessionName, QJsonObject profile, UserContainer Users) { + id = sessionID, SessionName = sessionName, Profile = profile, members = Users; + } + + int getSessionID() const { return id; } + const QString& getSessionName() const; + const QJsonObject& getProfile() const { return Profile; } + QJsonObject generateJsonFromData() const; + +private: + int id; + QString SessionName; + QJsonObject Profile; + + void loadUsersFromJson(const QJsonObject& json); + void loadDataFromJson(const QJsonObject& json); +}; +#endif // ONLINESESSION_H diff --git a/Client/client.cpp b/Client/client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..429be7b25a0610bf52d28e16061e773ffaaacd97 --- /dev/null +++ b/Client/client.cpp @@ -0,0 +1,56 @@ +#include "client.h" +#include "ui_client.h" +#include +#include +#include + +Client::Client(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::Client) +{ + ui->setupUi(this); + this->hide(); + if(connectserver()){ + userlogin = new UserLogin(this); + } +} + +Client::~Client() +{ + delete ui; +} + + +void Client::send(QJsonObject data) +{ + QString str = QString(QJsonDocument(data).toJson()); + socket->write(str.toUtf8()); +} + +bool Client::connectserver() +{ + socket = new QTcpSocket(this); + socket->connectToHost (QHostAddress("127.0.0.7"),8888); + bool bo = false; + + //连接信息提示 + connect(socket, &QTcpSocket::connected,this, [=,&bo](){ + QMessageBox::information (this, "连接信息", "连接成功!"); + bo = true; + }); + connect(socket, &QTcpSocket::disconnected,this, [=,&bo](){ + QMessageBox::information (this, "连接信息", "断开连接!"); + bo = false; + }); + + //接受消息 + connect(socket, &QTcpSocket::readyRead, this, &Client::receiveMessage); + return bo; +} + +QJsonObject Client::receiveMessage() +{ + QByteArray arr = socket->readAll (); + QJsonDocument doc = QJsonDocument::fromJson(arr); + return doc.object(); +} diff --git a/Client/client.h b/Client/client.h new file mode 100644 index 0000000000000000000000000000000000000000..99fd60b8eb4521883598ece17e36d570b5844264 --- /dev/null +++ b/Client/client.h @@ -0,0 +1,34 @@ +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class Client; } +QT_END_NAMESPACE + +class Client : public QMainWindow +{ + Q_OBJECT + +public: + Client(QWidget *parent = nullptr); + ~Client(); + UserLogin *userlogin = nullptr; + QTcpSocket *socket; + +private slots: + + //发送功能实现 + void send(QJsonObject data); + //连接功能实现 + bool connectserver(); + //接收并打印的槽函数 + QJsonObject receiveMessage(); + +private: + Ui::Client *ui; +}; +#endif // CLIENT_H diff --git a/Database_Lyh/widget.ui b/Client/client.ui similarity index 60% rename from Database_Lyh/widget.ui rename to Client/client.ui index c3fa28a3218bd25cc6bdae9e09c8e49ae36da0a2..ced9b5e716efaab88d95caa6ea31fff4f24c8e79 100644 --- a/Database_Lyh/widget.ui +++ b/Client/client.ui @@ -1,17 +1,17 @@ - Widget - + client + 0 0 - 800 - 600 + 400 + 300 - Widget + Form diff --git a/Client/clientdatacenter.cpp b/Client/clientdatacenter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..703de75f734da272eed35e169f08b49255d5e275 --- /dev/null +++ b/Client/clientdatacenter.cpp @@ -0,0 +1,38 @@ +#include "clientdatacenter.h" +#include + + +void ClientDataCenter::registerUser(OnlineUserModel * newuser) { + if (users.contains(newuser->getUsername())) { + return; + } + users[newuser->getUsername()] = newuser; + newuser->setParent(this); + registeredObjects.append(newuser); +} + +void ClientDataCenter::registerSession(OnlineSession *session) { + if (sessions.contains(session->getSessionID())) { + return; + } + sessions[session->getSessionID()] = session; + session->setParent(this); + registeredObjects.append(session); +} + +void ClientDataCenter::registerMessage(OnlineMessage *msg) { + if (messages.contains({msg->getSessionID(), msg->getMessageID()})) { + return; + } + messages[{msg->getSessionID(), msg->getMessageID()}] = msg; + msg->setParent(this); + registeredObjects.append(msg); + qDebug() << "### ClientDataCenter Down"; +} + +void ClientDataCenter::clean() { + users.clear(); + sessions.clear(); + messages.clear(); + registeredObjects.clear(); +} diff --git a/Client/clientdatacenter.h b/Client/clientdatacenter.h new file mode 100644 index 0000000000000000000000000000000000000000..21159c25f94d1de48374b03010ab965d12555a2d --- /dev/null +++ b/Client/clientdatacenter.h @@ -0,0 +1,51 @@ +#ifndef CLIENTDATACENTER_H +#define CLIENTDATACENTER_H + +#include +#include +#include +#include + +#include "Session/abstractsession.h" +#include "Session/onlinesession.h" +#include "Session/offlinesession.h" +#include "usermodel.h" +#include "messagemodel.h" + +class ClientDataCenter : public QObject +{ + Q_OBJECT +public: + static ClientDataCenter& Singleton(QObject * parent = nullptr) { + static ClientDataCenter * singleton = new ClientDataCenter(parent); + return * singleton; + } + + // 将用户模型插入到datacenter + void registerUser(OnlineUserModel * newuser); + void registerSession(OnlineSession * session); + void registerMessage(OnlineMessage * msg); + OnlineSession& getSession(int SessionId); + OnlineUserModel & getUser(QString username); + OnlineMessage & getMessage(int SessionId, int MessageId); + bool isRegistered(QObject* obj) { return registeredObjects.contains(obj); } + bool hasUser(QString username); + bool hasSession(int sessionId); + bool hasMessage(int sessionId, int messageId); + +public slots: + void clean(); + +private: + explicit ClientDataCenter(QObject *parent = nullptr); + QMap users; + QList registeredObjects; + QMap sessions; + QMap, OnlineMessage *> messages; + OnlineSession* _getSession(int SessionId); + OnlineUserModel* _getUser(QString username); + OnlineMessage* _getMessage(int SessionId, int MessageId); +}; + + +#endif // CLIENTDATACENTER_H diff --git a/Client/clientmain.cpp b/Client/clientmain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b793afeb78a6d3f220f2652f36cd1fed21ce151 --- /dev/null +++ b/Client/clientmain.cpp @@ -0,0 +1,52 @@ +#include "clientmain.h" +#include +#include + +ClientMain::ClientMain(QString IPAddress, int portOpen, QObject *parent) : + QObject(parent), ipAdd(IPAddress), port(portOpen) +{ + connectToServer(); + +} + +void ClientMain::send(QJsonObject data) +{ + QString str = QString(QJsonDocument(data).toJson()); + socket->write(str.toUtf8()); +} + +void ClientMain::connectToServer() { + socket = new QTcpSocket(); + //连接信息提示 + connect(socket, &QTcpSocket::connected, this, [=](){ + qDebug() << "Server Connected"; + is_connected = true; + emit serverConnected(); + }); + connect(socket, &QTcpSocket::disconnected,this, [=](){ + qDebug() << "Server Disconnected"; + is_connected = false; + emit serverDisconnected(); + }); + //接受消息 + connect(socket, &QTcpSocket::readyRead, this, &ClientMain::receiveMessage); + socket->connectToHost (QHostAddress(ipAdd), port); +} + +QJsonObject ClientMain::receiveMessage() +{ + QByteArray arr = socket->readAll (); + QJsonDocument doc = QJsonDocument::fromJson(arr); + return doc.object(); +} + +void ClientMain::operator()() { + login = new UserLogin(); + login->show(); + + // register form + connect(login, &UserLogin::registerButtonClicked, this, [=]() { + regist = new UserRegister(); + regist->show(); + }); +} diff --git a/Client/clientmain.h b/Client/clientmain.h new file mode 100644 index 0000000000000000000000000000000000000000..df0131652988a779b2b6a0ce18fa72d3589e60c3 --- /dev/null +++ b/Client/clientmain.h @@ -0,0 +1,46 @@ +#ifndef CLIENTMAIN_H +#define CLIENTMAIN_H + +#include +#include +#include + +#include "userlogin.h" +#include "userregister.h" + +class ClientMain : public QObject +{ + Q_OBJECT +public: + static ClientMain& Singleton(QString IPAddress="", int port=8888, QObject * parent = nullptr) { + static ClientMain * singleton = new ClientMain(IPAddress, port, parent); + return * singleton; + } + + // start client + + void operator() (void); + //发送功能实现 + void send(QJsonObject data); + //接收并打印的槽函数 + QJsonObject receiveMessage(); + bool isConnected() { return is_connected; } + +signals: + void serverConnected(); + void serverDisconnected(); + +private: + ClientMain(QString IPAddress, int portOpen, QObject *parent = nullptr); + QTcpSocket *socket; + bool is_connected = false; + void connectToServer(); + + QString ipAdd; + int port; + UserLogin * login; + UserRegister * regist; + +}; + +#endif // CLIENTMAIN_H diff --git a/Client/databaseoperation.cpp b/Client/databaseoperation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3938c0480bb502814738b934d36fd8c165be20e --- /dev/null +++ b/Client/databaseoperation.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "databaseoperation.h" + +QString json2str(QJsonObject json) { + return QString(QJsonDocument(json).toJson()); +} + +QJsonObject str2json(QString str) { + QJsonDocument jsonDoc = QJsonDocument::fromJson(str.toUtf8().data()); + if (jsonDoc.isNull()) { + qDebug() << "read json obj from str failed: str = " << str.toLocal8Bit().data(); + } + return jsonDoc.object(); +} + +DatabaseOperation::DatabaseOperation(QObject *parent) : QObject(parent) +{ + status = Status::Stop; +} + +void DatabaseOperation::startDatabaseConnection(QString dbfilename) { + if (status != Status::Stop) { + qDebug() << "db server already running..."; + throw "Already running error"; + } + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(dbfilename); //如果本目录下没有该文件,则会在本目录下生成,否则连接该文件 + if (!db.open()) { + qDebug() << db.lastError().text(); + throw "Database Error"; + } + status = Status::Running; + createTables(); +} + +void DatabaseOperation::executeSqlStatement(QString str) { + QSqlQuery query (str); + if (!query.isActive()) { + qDebug() << query.lastError(); + } +} + +void DatabaseOperation::createTables() { + executeSqlStatement("CREATE TABLE Message(SessionID INT NOT NULL, MessageID INT NOT NULL, SenderUsername TEXT NOT NULL, MessageText TEXT NOT NULL, Profile TEXT, PRIMARY KEY(SessionID, MessageID))"); +} + +bool DatabaseOperation::isDBExist(QString dbfilename) const { + QFileInfo file(dbfilename); + return file.exists(); +} + +void DatabaseOperation::closeDB() { + if (status != Status::Running) throw "already closed"; + database.close(); + + status = Status::Stop; + emit signal_DBstop(); +} + +QList DatabaseOperation::findAllMessages() { + QList ret; + QSqlQuery query; + if (!query.exec("SELECT SessionID, MessageID, senderUsername, MessageText, Profile FROM messages")) { + while (query.next()) { + int sessionID = query.value(0).toInt(); + int msgId = query.value(1).toInt(); + QString sender = query.value(2).toString(); + QString text = query.value(3).toString(); + QJsonObject profile = query.value(4).toJsonObject(); + + auto * msg = new OnlineMessage(msgId, sessionID, sender, text, profile); + ret.append(msg); + ClientDataCenter::Singleton().registerMessage(msg); + } + } + return ret; +} + +int DatabaseOperation::getTableCount(const char * tableName) const { + QSqlQuery query; + QString sql = QString("SELECT COUNT(*) FROM %1").arg(tableName); + query.addBindValue(tableName); + if (!query.exec(sql)) { + qDebug() << query.lastError(); + return -1; + } + if (!query.next()) return -1; + return query.value(0).toInt(); +} + +int DatabaseOperation::insertNewMessage(int SessionId, const char *senderUsername, const char *MessageText, const char *profile) { + QSqlQuery query; + QString sql = "select count (*) from Message WHERE SessionId = ?"; + query.prepare(sql); + query.addBindValue(SessionId); + if (!query.exec() || !query.next()) { + qDebug() << "Error Occurred when querying Message Number" << query.lastError(); + return -1; + } + int msgId = query.value(0).toInt() + 1; + qDebug() << "Current MsgId for sessionId = " << msgId; + + sql = "insert into Message(SessionID, MessageID, SenderUsername, MessageText, Profile) VALUES (?, ?, ?, ?, ?)"; + query.prepare(sql); + query.addBindValue(SessionId); + query.addBindValue(msgId); + query.addBindValue(senderUsername); + query.addBindValue(MessageText); + query.addBindValue(profile); + if (!query.exec()) { + qDebug() << "insertNewMessage : " << query.lastError(); + return -1; + } + return msgId; +} + +OnlineMessage * DatabaseOperation::findMessage(int sessionId, int MessageId) { + QSqlQuery query; + QString sql = "SELECT SenderUsername, MessageText, Profile FROM Message WHERE SessionID = " + + QString::number(sessionId) + " and MessageID = " + QString::number(MessageId); + if (!query.exec(sql) || !query.first()) { + qDebug() << "DBOps::findMessage: " << query.lastError(); + return nullptr; + } + + QString sender = query.value(0).toString(); + QString text = query.value(1).toString(); + QJsonObject json = query.value(2).toJsonObject(); + OnlineMessage * ret = new OnlineMessage(MessageId, sessionId, sender, text, json); + ClientDataCenter::Singleton().registerMessage(ret); + return ret; +} + +ClientDataCenter::ClientDataCenter(QObject *parent) : QObject(parent) +{ + connect(&DatabaseOperation::Singleton(), &DatabaseOperation::signal_DBstop, this, &ClientDataCenter::clean); +} diff --git a/Client/databaseoperation.h b/Client/databaseoperation.h new file mode 100644 index 0000000000000000000000000000000000000000..8b655d090186430785a909c1740636516712b3c0 --- /dev/null +++ b/Client/databaseoperation.h @@ -0,0 +1,50 @@ +#ifndef DATABASEOPERATION_H +#define DATABASEOPERATION_H + +#include +#include +#include +#include +#include +#include + +#include "clientdatacenter.h" + +QString json2str(QJsonObject json); + +QJsonObject str2json(QString str); + +class DatabaseOperation : public QObject +{ + Q_OBJECT +public: + static DatabaseOperation & Singleton(QObject * parent = nullptr) { + static DatabaseOperation * singleton = new DatabaseOperation(parent); + return *singleton; + } + + void startDatabaseConnection(QString dbfilename); + bool isDBExist(QString str) const; + void closeDB(); + int getTableCount(const char * tableName) const; + QList findAllMessages(); + + bool isRunning() const { return status == Status::Running; } + int insertNewMessage(int SessionId, const char *senderUsername, const char *MessageText, const char *profile); + + OnlineMessage * findMessage(int sessionId, int MessageId); + +signals: + void signal_DBstop(); + +private: + explicit DatabaseOperation(QObject *parent = nullptr); + enum class Status { Stop, Running } status; + void executeSqlStatement(QString str); + void createTables(); + + QSqlDatabase database; +}; + + +#endif // DATABASEOPERATION_H diff --git a/Client/kuang.cpp b/Client/kuang.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0eb40dedd014c11f419feadc82e7b7ce506a5249 --- /dev/null +++ b/Client/kuang.cpp @@ -0,0 +1,47 @@ +#include "kuang.h" +#include "ui_kuang.h" +#include +#include + +Kuang::Kuang(QWidget *parent) : + QWidget(parent), + ui(new Ui::Kuang) +{ + ui->setupUi(this); +} + +Kuang::Kuang(const QString &username,QJsonObject data,QWidget *parent): + QWidget(parent), + ui(new Ui::Kuang){ + ui->setupUi(this); + QJsonArray temp = data["Members"].toArray(); + SessionID = data["SessionID"].toInt(); + if(temp[0].toObject()["Username"].toString()==username){ + ui->name->setText(temp[1].toObject()["Username"].toString()); + } + else { + ui->name->setText(temp[0].toObject()["Username"].toString()); + } +} + +Kuang::Kuang(QJsonObject data,QWidget *parent): + QWidget(parent), + ui(new Ui::Kuang){ + ui->setupUi(this); + SessionID = data["SessionID"].toInt(); + ui->name->setText(data["Profile"].toObject()["SessionName"].toString()); +} +Kuang* Kuang::KuangChosenNow = nullptr; +void Kuang::mousePressEvent(QMouseEvent *ev){ + if(ev->button()==Qt::LeftButton){ + if(!KuangChosenNow || KuangChosenNow != this){ + emit KuangChosenChanged(SessionID); + KuangChosenNow = this; + } + } +} + +Kuang::~Kuang() +{ + delete ui; +} diff --git a/Client/kuang.h b/Client/kuang.h new file mode 100644 index 0000000000000000000000000000000000000000..5088cb8880425f34e9aea13391b45eae4d0a2954 --- /dev/null +++ b/Client/kuang.h @@ -0,0 +1,33 @@ +#ifndef KUANG_H +#define KUANG_H + +#include +#include +#include +#include +#include + +namespace Ui { +class Kuang; +} + +class Kuang : public QWidget +{ + Q_OBJECT + +public: + explicit Kuang(QWidget *parent = nullptr); + Kuang(const QString &username,QJsonObject data,QWidget *parent = nullptr); + Kuang(QJsonObject data,QWidget *parent = nullptr); + virtual void mousePressEvent(QMouseEvent *ev); + ~Kuang(); + int SessionID; + static Kuang *KuangChosenNow; + +signals: + void KuangChosenChanged(int SessionID); +private: + Ui::Kuang *ui; +}; + +#endif // KUANG_H diff --git a/Client/kuang.ui b/Client/kuang.ui new file mode 100644 index 0000000000000000000000000000000000000000..ae630d6a6cfe9c01c77c298d32598df8e46ba043 --- /dev/null +++ b/Client/kuang.ui @@ -0,0 +1,51 @@ + + + Kuang + + + + 0 + 0 + 200 + 75 + + + + Form + + + + + 10 + 15 + 50 + 50 + + + + QFrame::Box + + + profile + + + + + + 70 + 20 + 121 + 41 + + + + QFrame::Box + + + name + + + + + + diff --git a/Client/main.cpp b/Client/main.cpp index 20ea5a0ee2532c49c0b31ddfb9690b43b50bc9bc..743a7fb870f775e0c7d56721a011b9a982c5b25a 100644 --- a/Client/main.cpp +++ b/Client/main.cpp @@ -1,11 +1,38 @@ -#include "clientmainwindow.h" +#include "userlogin.h" +#include "userregister.h" +#include "mainwindow.h" +#include "kuang.h" +#include "clientmain.h" #include +#include +#include +#include +#include + +const QString filename = QDir::currentPath() + "/settings.json"; + +QJsonObject readSettings() { + QFile file(filename); + if (file.open(QIODevice::ReadWrite | QIODevice::Text)) { + QByteArray t = file.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(t); + file.close(); + qDebug() << "loaded local settings " << file.fileName() << doc.object(); + return doc.object(); + } + return QJsonObject(); +} int main(int argc, char *argv[]) { QApplication a(argc, argv); - ClientMainWindow w; - w.show(); + auto settings = readSettings(); + QString ip = settings.contains("Server IP") ? settings["Server IP"].toString() : "127.0.0.1"; + int port = settings.contains("Port") ? settings["Port"].toInt() : 8888; + qDebug() << "IP = " << ip << ", port = " << port; + + ClientMain & client = ClientMain::Singleton(ip, port); + client(); return a.exec(); } diff --git a/Client/mainwindow.cpp b/Client/mainwindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86d54840f1295ee9d282bffdd81cc3b2a39f35c6 --- /dev/null +++ b/Client/mainwindow.cpp @@ -0,0 +1,140 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include +#include +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::dealMessage(Message *messageW, QListWidgetItem *item, QString text, QString time, Message::UserType type) +{ + messageW->setFixedWidth(ui->listWidget->width() -10);//固定聊天气泡的长度 不能超过父窗口 + QSize size = messageW->setSize(text); //设置message基本规格 + item->setSizeHint(size); //设置item基本规格 同widget + messageW->setTextContent(text, time, size, type); //设置message基本内容 + ui->listWidget->setItemWidget(item, messageW); //将message的内容 在给定的 item中显示 +} + +void MainWindow::dealMessageTime(QString curMsgTime) +{ + bool isShowTime = false; + if(ui->listWidget->count() > 0) { + QListWidgetItem* lastItem = ui->listWidget->item(ui->listWidget->count() - 1); + Message* messageW = (Message*)ui->listWidget->itemWidget(lastItem); + int lastTime = messageW->time().toInt(); + int curTime = curMsgTime.toInt(); + qDebug() << "curTime lastTime:" << curTime - lastTime; + isShowTime = ((curTime - lastTime) > 60); // 两个消息相差一分钟 +// isShowTime = true; + } else { + isShowTime = true; + } + if(isShowTime) { + Message* messageTime = new Message(ui->listWidget->parentWidget()); + QListWidgetItem* itemTime = new QListWidgetItem(ui->listWidget); + + QSize size = QSize(ui->listWidget->width() - 10, 40); + messageTime->resize(size); + itemTime->setSizeHint(size); + messageTime->setTextContent(curMsgTime, curMsgTime, size, Message::userTime); + ui->listWidget->setItemWidget(itemTime, messageTime); + } +} + +void MainWindow::on_btnSend_clicked() +{ + QString msg = ui->textEdit->toPlainText(); //返回文字 + ui->textEdit->setText(""); //清空 + QString time = QString::number(QDateTime::currentDateTime().toTime_t()); //获取当前时间并转为时间戳 + +// dealMessageTime(time); //用于处理时间 +// Message *messageW = new Message(ui->listWidget->parentWidget()); +// QListWidgetItem *item = new QListWidgetItem(ui->listWidget); +// dealMessage(messageW, item, msg, time, Message::userMe); + + //test 用例 +// if(ui->listWidget->count()%2) { +// bool isSending = true; +// if(isSending) { +// dealMessageTime(time); + +// Message* messageW = new Message(ui->listWidget->parentWidget()); +// QListWidgetItem* item = new QListWidgetItem(ui->listWidget); +// dealMessage(messageW, item, msg, time, Message::userMe); +// } +// } else { +// if(msg != "") { +// dealMessageTime(time); + +// Message* messageW = new Message(ui->listWidget->parentWidget()); +// QListWidgetItem* item = new QListWidgetItem(ui->listWidget); +// dealMessage(messageW, item, msg, time, Message::userOther); +// } +// } + + ui->listWidget->setCurrentRow(ui->listWidget->count()-1); +} + +void MainWindow::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + for(int i = 0; i < ui->listWidget->count(); i++) { + Message* messageW = (Message*)ui->listWidget->itemWidget(ui->listWidget->item(i)); + QListWidgetItem* item = ui->listWidget->item(i); + + dealMessage(messageW, item, messageW->text(), messageW->time(), messageW->userType()); + } +} + +MainWindow::MainWindow(QWidget *parent,QJsonObject data): + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + friendlayout = new QVBoxLayout(ui->frd); + grouplayout = new QVBoxLayout(ui->group); + ui->userNameShow->setText(data["Username"].toString()); + username = data["Username"].toString(); + ui->nickNameShow->setText(data["Nickname"].toString()); +} + +void MainWindow::FriendSessionAdd(QJsonObject data){ + Kuang *k = new Kuang(username,data,this); + FriendSessionMap.insert(std::pair(data["SessionID"].toInt(),k)); + friendlayout->addWidget(k); + connect(k,&Kuang::KuangChosenChanged,this,&MainWindow::MessageDatarequired); +} + +void MainWindow::GroupSessionAdd(QJsonObject data){ + Kuang *k = new Kuang(data,this); + GroupSessionMap.insert(std::pair(data["SessionID"].toInt(),k)); + grouplayout->addWidget(k); + connect(k,&Kuang::KuangChosenChanged,this,&MainWindow::MessageDatarequired); +} + +void MainWindow::MessageDatarequired(int SessionID){ + //send() + ui->listWidget->clear(); +} + +void MainWindow::AddMessage(QJsonObject data){ + QString time = QString::number(QDateTime::currentDateTime().toTime_t()); + dealMessageTime(time); //用于处理时间 + Message *messageW = new Message(ui->listWidget->parentWidget()); + QListWidgetItem *item = new QListWidgetItem(ui->listWidget); + QString msg = data["Body"].toObject()["Text"].toString(); + if(data["SenderName"].toString() == username){ + dealMessage(messageW, item, msg, time, Message::userMe); + } + else{ + dealMessage(messageW, item, msg, time, Message::userOther); + } +} diff --git a/Client/mainwindow.h b/Client/mainwindow.h new file mode 100644 index 0000000000000000000000000000000000000000..46dbc53d8ed4b416ff81e06108442ee7687f678c --- /dev/null +++ b/Client/mainwindow.h @@ -0,0 +1,50 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "message.h" +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + MainWindow(QWidget *parent,QJsonObject data); + ~MainWindow(); + void FriendSessionAdd(QJsonObject data); + void GroupSessionAdd(QJsonObject data); + QVBoxLayout *friendlayout; + QVBoxLayout *grouplayout; + QString username; + std::mapFriendSessionMap,GroupSessionMap; + //处理信息 + void dealMessage(Message *messageW, QListWidgetItem *item, QString text, QString time, Message::UserType type); + //处理时间 + void dealMessageTime(QString curMsgTime); + void MessageDatarequired(int SessionID); + void AddMessage(QJsonObject data); + +private slots: + void on_btnSend_clicked(); + +protected: + //重生事件 调整聊天框大小 + void resizeEvent(QResizeEvent *event); +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/Client/mainwindow.ui b/Client/mainwindow.ui new file mode 100644 index 0000000000000000000000000000000000000000..de275638539310ce15685d0700442786e6c50a27 --- /dev/null +++ b/Client/mainwindow.ui @@ -0,0 +1,581 @@ + + + MainWindow + + + + 0 + 0 + 810 + 642 + + + + BICQ + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::West + + + QTabWidget::Rounded + + + 0 + + + false + + + false + + + + Personal + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 400 + 400 + + + + + + 100 + 200 + 200 + 40 + + + + QFrame::Box + + + + + + + + + 100 + 270 + 200 + 40 + + + + QFrame::Box + + + nick name + + + + + + 100 + 130 + 200 + 40 + + + + QFrame::Box + + + user name + + + + + + 150 + 0 + 120 + 120 + + + + profile photo + + + + + + 100 + 330 + 200 + 40 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Chatting + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 570 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 370 + 30 + + + + + 16777215 + 30 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + + 0 + 0 + + + + + 370 + 350 + + + + QListWidget{background-color: rgb(247, 247, 247); color:rgb(51,51,51); border: 1px solid rgb(247, 247, 247);outline:0px;} +QListWidget::Item{background-color: rgb(247, 247, 247);} +QListWidget::Item:hover{background-color: rgb(247, 247, 247); } +QListWidget::item:selected{ + background-color: rgb(247, 247, 247); + color:black; + border: 1px solid rgb(247, 247, 247); +} +QListWidget::item:selected:!active{border: 1px solid rgb(247, 247, 247); background-color: rgb(247, 247, 247); color:rgb(51,51,51); } + + + QFrame::NoFrame + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAlwaysOff + + + + + + + + 0 + 40 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 30 + + + + send + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + + 370 + 150 + + + + + 16777215 + 150 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + 0 + + + + + 0 + 0 + 200 + 551 + + + + friend + + + + + + + 0 + 0 + 200 + 551 + + + + group + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + 0 + 0 + 200 + 551 + + + + top session + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + Search + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 500 + 40 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + diff --git a/Client/message.cpp b/Client/message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..852cc6f191240088af26e278da818254f9998514 --- /dev/null +++ b/Client/message.cpp @@ -0,0 +1,212 @@ +#include "message.h" +#include +#include +#include +Message::Message(QWidget *parent) : QWidget(parent) +{ + //设置字体 + QFont textFont("MicrosoftYaHei", 12); + this->setFont(textFont); + //缓冲按钮暂定 +} +void Message::setTextContent(QString text, QString time, QSize size, UserType type) +{ + m_msg = text; + m_userType = type; + m_time = time; + m_currentTime = QDateTime::fromTime_t(time.toInt()).toString("hh:mm");//时间戳 自1970年过去的秒数 + m_wholeSize = size; + + //自定义头像 next + m_meRightIcon = QPixmap(":/img/Image/Luffy.png"); + m_otherLeftIcon = QPixmap(":/img/Image/OnePiece.png"); + //需增加名称显示 next +} +QSize Message::setSize(QString str) +{ + int minHeight = 30; //聊天气泡最小高度 + int iconWidth = 40; //头像宽度 同头像长度 + int iconSpaceWidth = 20; //头像与聊天界面框 长度距离 + int iconSpaceHeight= 10; //头像与聊天界面框 高度距离 + int iconRectWidth = 5; //头像与小三角的距离 + int triWidth = 6; //小三角长度 + int kuangTMP = 20; //?????? + int textSpaceWidth = 12; //聊天气泡中 文本距单侧气泡框空白宽度 + + m_msg = str; + m_kuangWidth = this->width() - kuangTMP - 2 * (iconWidth + iconSpaceWidth + iconRectWidth); + m_textWidth = m_kuangWidth - 2 * textSpaceWidth; + m_spaceWidth = this->width() - m_textWidth; + m_iconLeftRect = QRect(iconSpaceWidth, iconSpaceHeight, iconWidth, iconWidth); + m_iconRightRect = QRect(this->width() - iconSpaceWidth - iconWidth, iconSpaceHeight, iconWidth, iconWidth); + + QSize size = getStringSize(m_msg); + int height = size.height() < minHeight ? minHeight : size.height(); + + m_triLeftRect = QRect(iconSpaceWidth + iconWidth + iconRectWidth, m_lineHeight / 2, triWidth, height - m_lineHeight);//??? + m_triRightRect = QRect(this->width() - iconSpaceWidth - iconWidth - iconRectWidth - triWidth, m_lineHeight / 2, triWidth, height - m_lineHeight); + + if(size.width() < (m_textWidth + m_spaceWidth)) + { + m_kuangLeftRect.setRect(m_triLeftRect.x() + m_triLeftRect.width(), m_lineHeight / 4 * 3, size.width() - m_spaceWidth + 2 * textSpaceWidth, height - m_lineHeight); + m_kuangRightRect.setRect(this->width() - size.width() + m_spaceWidth - 2 * textSpaceWidth - iconWidth - iconSpaceWidth - iconRectWidth - triWidth, + m_lineHeight / 4 * 3, size.width() - m_spaceWidth + 2 * textSpaceWidth, height - m_lineHeight); + } + else + { + m_kuangLeftRect.setRect(m_triLeftRect.x() + m_triLeftRect.width(), m_lineHeight / 4 * 3, m_kuangWidth, height - m_lineHeight); + m_kuangRightRect.setRect(iconWidth + kuangTMP + iconSpaceWidth + iconRectWidth - triWidth, m_lineHeight/4*3, m_kuangWidth, height-m_lineHeight); + } + + m_textLeftRect.setRect(m_kuangLeftRect.x() + textSpaceWidth, m_kuangLeftRect.y() + iconSpaceHeight, + m_kuangLeftRect.width() - 2 * textSpaceWidth, m_kuangLeftRect.height() - 2 * iconSpaceHeight); + m_textRightRect.setRect(m_kuangRightRect.x() + textSpaceWidth, m_kuangRightRect.y() + iconSpaceHeight, + m_kuangRightRect.width() - 2 * textSpaceWidth, m_kuangRightRect.height() -2 * iconSpaceHeight); + + return QSize(size.width(), height); +} +QSize Message::getStringSize(QString str) +{ + QFontMetricsF fm(this->font()); + m_lineHeight = fm.lineSpacing(); //行间距 + int nCount = str.count("\n"); //\n数量 + int textMaxWidth; + + if (nCount == 0) + {//实际文本无换行 + textMaxWidth = fm.width(str);//返回给定文本中字符的宽度 + if (textMaxWidth > m_textWidth) + {//实际文本宽度大于当前可实现文本宽度,根据当前文本宽度重新编辑文本 \n + textMaxWidth = m_textWidth; + int size = m_textWidth / fm.width(" ");//每行字符数 + int num = fm.width(str) / m_textWidth;//需换行数 + nCount += num; + QString strAfter = ""; + for (int i = 0; i < num ; i++) + { + strAfter += str.mid(i * size, (i + 1) * size) + "\n"; + } + str = strAfter; + } + } + else + {//实际文本有换行 + for (int i = 0; i <= nCount; i++) + { + QString strSplit = str.split("\n").at(i);//依据实际文本的换行符进行分割 + textMaxWidth = fm.width(strSplit) > textMaxWidth ? fm.width(strSplit) : textMaxWidth; + if (fm.width(strSplit) > m_textWidth) + { + textMaxWidth = m_textWidth; + int size = m_textWidth / fm.width(" ");//每行字符数 + int num = fm.width(strSplit) / m_textWidth;//需换行数 + num = ((i + num) * fm.width(" ") + fm.width(strSplit)) / m_textWidth; //??? + nCount += num; + QString strAfter = ""; + for (int i = 0; i < num; i++) + { + strAfter += strSplit.mid(i * size, (i + 1) * size) + "\n"; + } + str.replace(strSplit, strAfter);//需改进 + } + } + } + + //换行效果需增强 + return QSize(textMaxWidth + m_spaceWidth, (nCount + 1) * m_lineHeight + 2 * m_lineHeight); +} +void Message::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);//消锯齿 + painter.setPen(Qt::NoPen);//无线 + painter.setBrush(QBrush(Qt::gray));//形状填充为 灰色 纯色图案 + + if(m_userType == UserType::userOther) { // 聊天对象 + //放置头像 + painter.drawPixmap(m_iconLeftRect, m_otherLeftIcon); + + //框加边 + QColor col_KuangB(234, 234, 234); + painter.setBrush(QBrush(col_KuangB)); + painter.drawRoundedRect(m_kuangLeftRect.x() - 1,m_kuangLeftRect.y() - 1,m_kuangLeftRect.width()+2,m_kuangLeftRect.height()+2,4,4);//圆角框 + + //框 气泡 + QColor col_Kuang(255,255,255); + painter.setBrush(QBrush(col_Kuang)); + painter.drawRoundedRect(m_kuangLeftRect,4,4); + + //三角 + QPointF points[3] = { + QPointF(m_triLeftRect.x(), 30),// + QPointF(m_triLeftRect.x()+m_triLeftRect.width(), 25), + QPointF(m_triLeftRect.x()+m_triLeftRect.width(), 35), + }; + QPen pen; + pen.setColor(col_Kuang); + painter.setPen(pen); + painter.drawPolygon(points, 3);//画多边形 + + //三角加边 + QPen penSanJiaoBian; + penSanJiaoBian.setColor(col_KuangB); + painter.setPen(penSanJiaoBian); + painter.drawLine(QPointF(m_triLeftRect.x() - 1, 30), QPointF(m_triLeftRect.x()+m_triLeftRect.width(), 24)); + painter.drawLine(QPointF(m_triLeftRect.x() - 1, 30), QPointF(m_triLeftRect.x()+m_triLeftRect.width(), 36)); + + //内容 + QPen penText; + penText.setColor(QColor(51,51,51)); + painter.setPen(penText); + QTextOption option(Qt::AlignLeft | Qt::AlignVCenter);//左对齐 中心水平对齐 + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);//包围字体 + painter.setFont(this->font()); + painter.drawText(m_textLeftRect, m_msg,option);//写文本 + } else if(m_userType == UserType::userMe) { // 自己 + //头像 + + + painter.drawPixmap(m_iconRightRect, m_meRightIcon); + qDebug() << "this->width()" << this->width(); + qDebug() << "x" << m_iconRightRect.x(); + qDebug() << "this->width()" << this->width(); + + //框 + QColor col_Kuang(75,164,242); + painter.setBrush(QBrush(col_Kuang)); + painter.drawRoundedRect(m_kuangRightRect,4,4); + + //三角 + QPointF points[3] = { + QPointF(m_triRightRect.x()+m_triRightRect.width(), 30), + QPointF(m_triRightRect.x(), 25), + QPointF(m_triRightRect.x(), 35), + }; + QPen pen; + pen.setColor(col_Kuang); + painter.setPen(pen); + painter.drawPolygon(points, 3); + + //内容 + QPen penText; + penText.setColor(Qt::white); + painter.setPen(penText); + QTextOption option(Qt::AlignLeft | Qt::AlignVCenter); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + painter.setFont(this->font()); + painter.drawText(m_textRightRect,m_msg,option); + } else if(m_userType == UserType::userTime) { // 时间 + QPen penText; + penText.setColor(QColor(153,153,153)); + painter.setPen(penText); + QTextOption option(Qt::AlignCenter); + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + QFont te_font = this->font(); + te_font.setFamily("MicrosoftYaHei"); + te_font.setPointSize(10); + painter.setFont(te_font); + painter.drawText(this->rect(),m_currentTime,option); + } +} diff --git a/Client/message.h b/Client/message.h new file mode 100644 index 0000000000000000000000000000000000000000..752b77173c95ffa44b92c44e8a552c297322b4dd --- /dev/null +++ b/Client/message.h @@ -0,0 +1,70 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include + +class Message : public QWidget +{ + Q_OBJECT +public: + explicit Message(QWidget *parent = nullptr); + + //发送者类别 + enum UserType + { + userMe, //自己 + userOther, //他人 + userTime, //时间 + }; + + //设置基本属性 + void setTextContent(QString txt, QString t, QSize allSize, UserType type); + //计算聊天气泡的size + QSize setSize(QString str); + //设置文本动态换行 并获取发送文字的size + QSize getStringSize(QString str); + //画图事件 + void paintEvent(QPaintEvent *event); + + inline UserType userType() + { + return m_userType; + } + inline QString text() + { + return m_msg; + } + inline QString time() + { + return m_time; + } + +private: + UserType m_userType; + + QSize m_wholeSize; //总规格 ??? + QString m_msg; + QString m_time; + QString m_currentTime; + + QPixmap m_meRightIcon;//自己 右头像 + QPixmap m_otherLeftIcon;//他人 左头像 + + QRect m_iconRightRect;//左头像 所在矩形 + QRect m_iconLeftRect;//右头像 所在矩形 + QRect m_triRightRect;//右三角 + QRect m_triLeftRect;//左三角 + QRect m_kuangLeftRect;// ??? + QRect m_kuangRightRect;// ??? + QRect m_textLeftRect;//??? + QRect m_textRightRect;//??? + + int m_kuangWidth;//聊天框宽度 ??? + int m_textWidth;//聊天气泡内文本宽度 + int m_spaceWidth;//??? + int m_lineHeight;//基线之间的距离 ??? +signals: + +}; + +#endif // MESSAGE_H diff --git a/Client/message.ui b/Client/message.ui new file mode 100644 index 0000000000000000000000000000000000000000..dd2ffdd1c3e98c2474796fe39e894be0764a9877 --- /dev/null +++ b/Client/message.ui @@ -0,0 +1,45 @@ + + + Message + + + + 0 + 0 + 390 + 152 + + + + Form + + + + + 50 + 30 + 101 + 101 + + + + TextLabel + + + + + + 190 + 70 + 131 + 16 + + + + TextLabel + + + + + + diff --git a/Client/messagemodel.cpp b/Client/messagemodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e4695ce4b5fae191ceb1f4c0bf3d1ec1d4765f9 --- /dev/null +++ b/Client/messagemodel.cpp @@ -0,0 +1,50 @@ +#include "messagemodel.h" +#include +MessageModel::MessageModel(OnlineUserModel& senderUser, OnlineSession& sessionDest, + QString msgText, QJsonObject msgProfile, QObject *parent) : + QObject(parent) +{ + senderUsername = senderUser.getUsername(); + sessionID = sessionDest.getSessionID(); + text = msgText; + profile = msgProfile; +} + +int MessageModel::getSessionID() const { return sessionID; } +const QString& MessageModel::getSenderUsername() const { return senderUsername; } + + +const QString& MessageModel::getMessageText() const { return text; } +const QJsonObject& MessageModel::getMessageProfile() const { return profile; } + +MessageModel::MessageModel(MessageModel * old) +{ + if (old == nullptr) { + return; + } + senderUsername = old->senderUsername; + text = old->text; + profile = old->profile; + sessionID = old->sessionID; +} +OnlineMessage::OnlineMessage(QJsonObject json, MessageModel * parent) : + MessageModel(parent) +{ + messageID = json["MessageID"].toInt(); + sessionID = json["SessionID"].toInt(); + senderUsername = json["SenderUsername"].toString(); + + QJsonObject body = json["Body"].toObject(); + text = body["Text"].toString(); + profile = body["Profile"].toObject(); +} + +OnlineMessage::OnlineMessage(int MessageID, int SessionID, QString sender, QString messageText, QJsonObject Profile, MessageModel * parent) +{ + messageID = MessageID; + sessionID = SessionID; + senderUsername = sender; + text = messageText; + profile = Profile; + this->setParent(parent); +} diff --git a/Client/messagemodel.h b/Client/messagemodel.h new file mode 100644 index 0000000000000000000000000000000000000000..a160369d7bfdc2684c7aa4a6ad7ebf85686094bf --- /dev/null +++ b/Client/messagemodel.h @@ -0,0 +1,50 @@ +#ifndef MESSAGEMODEL_H +#define MESSAGEMODEL_H + +#include +#include "usermodel.h" +#include "Session/onlinesession.h" + +class MessageModel : public QObject +{ + Q_OBJECT +public: + explicit MessageModel(OnlineUserModel& senderUser, OnlineSession& sessionDest, + QString msgText, QJsonObject msgProfile, QObject *parent = nullptr); + MessageModel(MessageModel * old = nullptr); + int getSessionID() const; + const OnlineSession & getSession() const; + const QString& getSenderUsername() const; + const OnlineUserModel& getSender() const; + virtual int getMessageID() const { throw "Offline Message do not have messageID"; } + + const QString& getMessageText() const; + const QJsonObject& getMessageProfile() const; + + enum class Type { Offline, Online }; + virtual Type getType() const { return Type::Offline; } + + QJsonObject generateJsonOutput() const; + + +signals: + +protected: + QString senderUsername; + int sessionID; + QString text; + QJsonObject profile; +}; + +class OnlineMessage : public MessageModel +{ + Q_OBJECT +public: + explicit OnlineMessage(QJsonObject json, MessageModel * parent = nullptr); + explicit OnlineMessage(int MessageID, int SessionID, QString sender, QString text, QJsonObject Profile, MessageModel * parent = nullptr); + int getMessageID() const override { return messageID; } +private: + int messageID; +}; + +#endif // MESSAGEMODEL_H diff --git a/Client/rsc.qrc b/Client/rsc.qrc new file mode 100644 index 0000000000000000000000000000000000000000..f793e769ea534498754c98b44a0a2547307069aa --- /dev/null +++ b/Client/rsc.qrc @@ -0,0 +1,15 @@ + + + Image/butterfly.png + Image/butterfly1.png + Image/down.png + Image/Frame.jpg + Image/Luffy.png + Image/LuffyQ.png + Image/mario.gif + Image/OnePiece.png + Image/Sunny.jpg + Image/sunny.png + Image/up.png + + diff --git a/Client/userlogin.cpp b/Client/userlogin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1d64ea4e83f94a8789bfd32eb9f710de7680103 --- /dev/null +++ b/Client/userlogin.cpp @@ -0,0 +1,86 @@ +#include "userlogin.h" +#include "ui_userlogin.h" +#include "clientmain.h" + +#include +#include +#include +#include +#include + +UserLogin::UserLogin(QWidget *parent) + : QWidget(parent) + , ui(new Ui::UserLogin) +{ + ui->setupUi(this); + + ClientMain & client = ClientMain::Singleton(); + + //点击注册跳转到注册页面 + connect(ui->btnRegister,&QPushButton::clicked,[=](){ + this->hide(); + emit registerButtonClicked(); + }); + + //注册完成后显示登录界面 +// connect(regist,&UserRegister::registfinished,this,&UserLogin::show); + + connect(&client, &ClientMain::serverConnected, this, [=]() { + this->ui->btnLogIn->setEnabled(true); + this->ui->btnRegister->setEnabled(true); + }); + + connect(&client, &ClientMain::serverDisconnected, this, [=]() { + this->ui->btnLogIn->setEnabled(false); + this->ui->btnRegister->setEnabled(false); + }); + //点击登录发送登录信息 + connect(ui->btnLogIn,&QPushButton::clicked,[=](){ + qDebug() << "Login Button Clicked"; + QJsonObject login = { {"Username",ui->lineEditUserName->text()},{"Password",ui->lineEditPassword->text()}}; + //send发送登录信息 +// send() + }); +} + +void UserLogin::login(QJsonObject data){ + if(data["IsLegal"].toBool()==false){ + QMessageBox::critical(this,"Error!","用户名或密码有误"); + } + else{ + this->hide(); +// main = new MainWindow(this,data); +// main->show(); +// connect(this,&UserLogin::FriendSessionDataReceived,this->main,&MainWindow::FriendSessionAdd); +// connect(this,&UserLogin::GroupSessionDataReceived,this->main,&MainWindow::GroupSessionAdd); +// connect(this,&UserLogin::SessionMessageReceived,this->main,&MainWindow::AddMessage); + } +} + +void UserLogin::receivemessage(QJsonObject data){ + if(data["MsgType"].toString()=="UserData"){ + emit UserDataReceived(data); + } + if(data["MsgType"].toString()=="LogInConfirm"){ + this->login(data); + } +// if(data["MsgType"].toString()=="RegistConfirm"){ +// regist->registconfirm(data); +// } + if(data["MsgType"].toString()=="SessionMessage"){ + emit SessionMessageReceived(data); + } + if(data["MsgType"].toString()=="SessionData"){ + if(data["SessionType"].toString()=="FRIEND"){ + emit FriendSessionDataReceived(data); + } + if(data["SessionType"].toString()=="GROUP"){ + emit GroupSessionDataReceived(data); + } + } +} + +UserLogin::~UserLogin() +{ + delete ui; +} diff --git a/Client/userlogin.h b/Client/userlogin.h new file mode 100644 index 0000000000000000000000000000000000000000..d3f8229986bbce7b889326e3bee3e3c061114e27 --- /dev/null +++ b/Client/userlogin.h @@ -0,0 +1,43 @@ +#ifndef USERLOGIN_H +#define USERLOGIN_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class UserLogin; } +QT_END_NAMESPACE + +class UserLogin : public QWidget +{ + Q_OBJECT + +public: + UserLogin(QWidget *parent = nullptr); + ~UserLogin(); + void receivemessage(QJsonObject data); + void login(QJsonObject data); + //打包login请求 + QJsonObject wrapLoginRequest(); + //连接功能实现 + void connectserver(); + +signals: + void registerButtonClicked(); + + + void UserDataReceived(QJsonObject data); + void LogInConfirmReceived(QJsonObject data); + void SessionMessageReceived(QJsonObject data); + void FriendSessionDataReceived(QJsonObject data); + void GroupSessionDataReceived(QJsonObject data); + void RegistConfirmReceived(QJsonObject data); + +public slots: + + +private: + Ui::UserLogin *ui; +}; +#endif // USERLOGIN_H diff --git a/Client/userlogin.ui b/Client/userlogin.ui new file mode 100644 index 0000000000000000000000000000000000000000..fea7c7b63e40f150df1a7c4807d6f8bcce5590b7 --- /dev/null +++ b/Client/userlogin.ui @@ -0,0 +1,261 @@ + + + UserLogin + + + + 0 + 0 + 400 + 300 + + + + + 400 + 300 + + + + + 400 + 300 + + + + UserLogin + + + + + + + + + + + + QLineEdit::Password + + + + + + + 用户名 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 密码 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + 登录 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + 注册 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + diff --git a/Client/usermodel.cpp b/Client/usermodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf3f1543dd1aed49e2a84877e8eadf21a0f14fe7 --- /dev/null +++ b/Client/usermodel.cpp @@ -0,0 +1,50 @@ +#include "usermodel.h" + + +UserModel::UserModel(QObject *parent) : QObject(parent) +{ + +} + +OfflineUserModel::OfflineUserModel(QString Username, QObject *parent) :QObject (parent) +{ + username = Username; +} + +OnlineUserModel::OnlineUserModel(QJsonObject &json, QObject *parent) : QObject (parent) +{ + loadBasicInfoFromJson(json); +} + +void OnlineUserModel::loadBasicInfoFromJson(QJsonObject &json) { + username = json["Username"].toString(); + nickname = json["Nickname"].toString(); + profile = json["Profile"].toObject(); +} + + +OnlineUserModel::OnlineUserModel(QString usrname, QString nick, QJsonObject json, QObject * parent) : + UserModel(parent) +{ + username = usrname; + nickname = nick; + profile = json; +} + + +QJsonObject OnlineUserModel::generateUserModelJson() const { + QJsonObject json; + json["MsgType"] = "UserData"; + json["Username"] = username; + json["Nickname"] = nickname; + json["Profile"] = profile; + return json; +} + +QJsonObject OfflineUserModel::generateUserModelJson() const { + QJsonObject json; + json["Username"] = username; + json["Nickname"] = nickname; + json["Profile"] = profile; + return json; +} diff --git a/Client/usermodel.h b/Client/usermodel.h new file mode 100644 index 0000000000000000000000000000000000000000..ccb7ab9ce1a89949e47833aae52e30afa3012b77 --- /dev/null +++ b/Client/usermodel.h @@ -0,0 +1,72 @@ +#ifndef USERMODEL_H +#define USERMODEL_H + +#include +#include +#include +#include + +class UserModel : virtual public QObject +{ + Q_OBJECT +public: + UserModel(QObject *parent = nullptr); + enum class Type { Offline, Online, None}; + virtual Type getType() const { return Type::None; } + const QString& getUsername() const { return username; } + const QJsonObject& getProfile() const { return profile; } + +signals: + +protected: + QString username; + QString nickname; + QJsonObject profile; +}; + +class OfflineUserModel : virtual public UserModel, virtual public QObject +{ + Q_OBJECT +public: + OfflineUserModel(QString Username, QObject *parent = nullptr); + Type getType() const { return Type::Offline; } + void setNickname(QString nname) { nickname = nname; } + void setSigniture(QString sig) { profile["Signiture"] = sig; } + QJsonObject generateUserModelJson() const; + + + +signals: + +}; + + +class OnlineUserModel : virtual public UserModel, virtual public QObject +{ + Q_OBJECT +public: + OnlineUserModel(QJsonObject &json, QObject *parent = nullptr); + OnlineUserModel(QString usrname, QString nick, QJsonObject json, QObject * parent = nullptr); + Type getType() const { return Type::Online; } + const QString& getNickname() const { return nickname; } + const QString getSigniture() const { return profile["Signiture"].toString(); } + + QJsonObject generateUserModelJson() const; +signals: + +private: + void loadBasicInfoFromJson(QJsonObject &json); +}; + +class LocalUser : virtual public OnlineUserModel +{ + Q_OBJECT +public: + + +signals: + +private: +}; + +#endif // USERMODEL_H diff --git a/Client/userregister.cpp b/Client/userregister.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b564f5d3a7c245d31707447e61c030d03bff8958 --- /dev/null +++ b/Client/userregister.cpp @@ -0,0 +1,58 @@ +#include "userregister.h" +#include "ui_userregister.h" +#include +#include +#include +#include +#include + + +UserRegister::UserRegister(QWidget *parent) : + QWidget(parent), + ui(new Ui::UserRegister) +{ + ui->setupUi(this); + connect(ui->btnRegister,&QPushButton::clicked,[=](){ + bool islegal = true; + QJsonObject registration_info; + QString s = ui->lERgUserName->text(), s1; + if(s.size()==0){ + QMessageBox::critical(this,"Error!","用户名不能为空"); + islegal = false; + } + s = ui->lERgPassword1->text(); + s1 = ui->lERgPassword2->text(); + if((s.size()==0 || s1.size()==0) && islegal){ + QMessageBox::critical(this,"Error!","密码不能为空"); + islegal = false; + } + if(s != s1 && islegal){ + QMessageBox::critical(this,"Error!","两次输入的密码不一致"); + islegal = false; + } + if(islegal){ + //发送注册信息 + registration_info.insert("username",ui->lERgUserName->text()); + registration_info.insert("nickname",ui->lERgNickName->text()); + registration_info.insert("password",ui->lERgPassword1->text()); + //send + } + }); +} + +void UserRegister::registconfirm(QJsonObject data){ + bool legal = data["IsLegal"].toBool(); + if(legal){ + QMessageBox::information(this,"提示","注册成功"); + emit UserRegister::registfinished(); + this->close(); + } + else{ + QMessageBox::critical(this,"Error!","用户名已存在"); + } +} + +UserRegister::~UserRegister() +{ + delete ui; +} diff --git a/Client/userregister.h b/Client/userregister.h new file mode 100644 index 0000000000000000000000000000000000000000..e1231bf90c3ca0b159a4ec89438d83c305361dee --- /dev/null +++ b/Client/userregister.h @@ -0,0 +1,27 @@ +#ifndef USERREGISTER_H +#define USERREGISTER_H + +#include +#include + +namespace Ui { +class UserRegister; +} + +class UserRegister : public QWidget +{ + Q_OBJECT + +public: + explicit UserRegister(QWidget *parent = nullptr); + ~UserRegister(); + void registconfirm(QJsonObject data); + +signals: + void registfinished(); + +private: + Ui::UserRegister *ui; +}; + +#endif // USERREGISTER_H diff --git a/Client/userregister.ui b/Client/userregister.ui new file mode 100644 index 0000000000000000000000000000000000000000..7ffabdacf4f3b5595fc1d66d46579a93937296f5 --- /dev/null +++ b/Client/userregister.ui @@ -0,0 +1,100 @@ + + + UserRegister + + + + 0 + 0 + 400 + 300 + + + + + 400 + 300 + + + + + 400 + 300 + + + + Form + + + + + 90 + 70 + 226 + 128 + + + + + + + 用户名 + + + + + + + + + + 昵称 + + + + + + + QLineEdit::Password + + + + + + + 密码 + + + + + + + + + + 确认密码 + + + + + + + + + + + + 170 + 220 + 84 + 24 + + + + 注册 + + + + + + diff --git a/Database_Lyh/Database_Lyh.pro b/Database_Lyh/Database_Lyh.pro deleted file mode 100644 index eb7a5ba37e7786a47cf9faa00f449545f77b74f4..0000000000000000000000000000000000000000 --- a/Database_Lyh/Database_Lyh.pro +++ /dev/null @@ -1,31 +0,0 @@ -QT += core gui sql - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -CONFIG += c++11 - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -SOURCES += \ - main.cpp \ - widget.cpp - -HEADERS += \ - widget.h - -FORMS += \ - widget.ui - -# Default rules for deployment. -qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin -!isEmpty(target.path): INSTALLS += target diff --git a/Database_Lyh/main.cpp b/Database_Lyh/main.cpp deleted file mode 100644 index e57e09ca21147eeccd4fff1bea4273e8d8a46b28..0000000000000000000000000000000000000000 --- a/Database_Lyh/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "widget.h" - -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - Widget w; - w.show(); - return a.exec(); -} diff --git a/Database_Lyh/widget.cpp b/Database_Lyh/widget.cpp deleted file mode 100644 index e32fbbb5f2e18cea962668e11882bfda951f548d..0000000000000000000000000000000000000000 --- a/Database_Lyh/widget.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include "widget.h" -#include "ui_widget.h" -#include -#include -#include -#include -#include -#include - -Widget::Widget(QWidget *parent) - : QWidget(parent) - , ui(new Ui::Widget) -{ - ui->setupUi(this); - createDB(); - createTable (); - insertData_User("124","Li","123456","..."); - insertData_User("123","Wang","123456","..."); - insertData_Dialog("friend","..."); - insertData_Message(1,"123","123to124","..."); - insertData_Message(1,"124","124to123","..."); - insertData_Member(1,"123"); - insertData_Member(2,"124"); -// insertData_Alldialog("123",1); -// insertData_Alldialog("124",1); - queryTable(); - database.close(); -} - -Widget::~Widget() -{ - delete ui; -} - - -//创建数据库 -void Widget::createDB(){ - - if (QSqlDatabase::contains("qt_sql_default_connection")) - { - database = QSqlDatabase::database("qt_sql_default_connection"); - } - else - { - database = QSqlDatabase::addDatabase("QSQLITE"); - database.setDatabaseName("MyDataBase.db"); - } - //建立连接 - if (!database.open()) - { - qDebug() << "Error: Failed to connect database." << database.lastError(); - } - else - { - qDebug() <<"数据库链接成功"; - } -} - - -//创建表格 -void Widget::createTable (void) { - // 构建创建数据表sql语句的字符串 - //先有成员、然后会话,然后才有消息 - //用户表 - QString userstr ("CREATE TABLE User(username TEXT PRIMARY KEY NOT NULL, nickname TEXT NOT NULL, password TEXT NOT NULL, profile TEXT NOT NULL)"); - //消息表 - QString messagestr ("CREATE TABLE Message(messageID INT PRIMARY KEY NOT NULL, sessionID INT NOT NULL, senderUsername TEXT NOT NULL, messageText TEXT NOT NULL, profile TEXT NOT NULL, foreign KEY (senderUsername) references User(username), foreign KEY (sessionID) references Dialog(sessionID))"); - //会话表 - QString dialoguestr ("CREATE TABLE Dialog(sessionID INT PRIMARY KEY NOT NULL, SessionType TEXT NOT NULL, profile TEXT NOT NULL)"); - //会话中成员表 - QString memberstr ("CREATE TABLE Member(sessionID INT NOT NULL, username TEXT NOT NULL)");//, primary key(sessionID,username), foreign KEY (sessionID) references Dialog(sessionID), foreign KEY (username) references User(username) - //用户所拥有的会话表 - //QString alldialogstr ("CREATE TABLE Alldialog(username TEXT NOT NULL, sessionID INT NOT NULL)");//, primary key(username,sessionID), foreign KEY (sessionID) references Dialog(sessionID), foreign KEY (username) references User(username) - // 执行sql语句 - QSqlQuery *query; - query = new QSqlQuery(); - query->exec (userstr); - query->exec (messagestr); - query->exec (dialoguestr); - query->exec (memberstr); - //query->exec (alldialogstr); -} - - -//查询所有User表中的数据 -void Widget::queryTable (void) { - QSqlQuery sqlQuery; - sqlQuery.exec("SELECT * FROM User"); - if(!sqlQuery.exec()) - { - qDebug() << "Error: Fail to query table. " << sqlQuery.lastError(); - } - else - { - while(sqlQuery.next()) - { - QString username = sqlQuery.value(0).toString(); - QString nickname = sqlQuery.value(1).toString(); - QString password = sqlQuery.value(2).toString(); - QString profile = sqlQuery.value(3).toString(); - qDebug()<prepare(insert_sql); - query->addBindValue(username); - query->addBindValue(nickname); - query->addBindValue(password); - query->addBindValue(profile); - query->exec(); -} -//往message表中插入数据 -void Widget::insertData_Message(int sessionID, const char* senderUsername, const char* messageText,const char* profile){ - QSqlQuery *query; - query = new QSqlQuery(); - QString insert_sql = "insert into Message values (?, ?, ?, ?, ?)"; - query->prepare(insert_sql); - query->addBindValue(++maxMessage); - query->addBindValue(sessionID); - query->addBindValue(senderUsername); - query->addBindValue(messageText); - query->addBindValue(profile); - query->exec(); -} -//往Dialog表中插入数据 -void Widget::insertData_Dialog(const char* SessionType, const char* profile){ - QSqlQuery *query; - query = new QSqlQuery(); - QString insert_sql = "insert into Dialog values(?, ?, ?)"; - query->prepare(insert_sql); - query->addBindValue(++maxDioalog); - query->addBindValue(SessionType); - query->addBindValue(profile); - query->exec(); -} -//记录一个会议的参加人员 -void Widget::insertData_Member(int sessionID, const char* username){ - QSqlQuery *query; - query = new QSqlQuery(); - QString insert_sql = "insert into Member values(?, ?)"; - query->prepare(insert_sql); - query->addBindValue(sessionID); - query->addBindValue(username); - if(!query->exec()){ - qDebug()<<"query error: "<lastError(); - } -} -//记录一人参加的会议 -//void Widget::insertData_Alldialog (const char* username, int sessionID){ -// QSqlQuery *query; -// query = new QSqlQuery(); -// QString insert_sql = "insert into Alldialog values(?, ?)"; -// query->addBindValue(username); -// query->addBindValue(sessionID); -// if(!query->exec()){ -// qDebug()<<"query error: "<lastError(); -// } -//} - diff --git a/Database_Lyh/widget.h b/Database_Lyh/widget.h deleted file mode 100644 index 99a4ee789c1ea2462015031e946f9bfa32754413..0000000000000000000000000000000000000000 --- a/Database_Lyh/widget.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef WIDGET_H -#define WIDGET_H - -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -namespace Ui { class Widget; } -QT_END_NAMESPACE - -class Widget : public QWidget -{ - Q_OBJECT - -public: - Widget(QWidget *parent = nullptr); - ~Widget(); -private: - QSqlDatabase database;// 建立QT程序和数据的连接 - QSqlQueryModel model; // 保存和遍历查询结果 - int maxMessage=0; - int maxDioalog=0; -private: - void createDB (void);//创建数据库 - void createTable (void);//创建数据表 -public: - void queryTable (void);//查询数据 - void insertData_User (const char* username,const char* nickname,const char* password,const char* profile);//往User中插入数据 - void insertData_Message (int sessionID, const char* senderUsername, const char* messageText,const char* profile); - void insertData_Dialog (const char* SessionType, const char* profile); - void insertData_Member (int sessionID, const char* username); - //void insertData_Alldialog (const char* username, int sessionID); -private: - Ui::Widget *ui; -}; -#endif // WIDGET_H diff --git a/README.md b/README.md index 254f44b17e19046206e3a66c7493ac5e44c7d5d6..dfe05748e5e34010353aae4996fdcc8b9727d49f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework ``` json { - "MsgType": "Regist, + "MsgType": "Regist", "Username": "...", "Nickname": "...", "Password": "..." @@ -28,7 +28,7 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework ``` json { - "MsgType": "LogIn, + "MsgType": "LogIn", "Username": "...", "Password": "..." } @@ -37,7 +37,7 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework ``` json { "MsgType": "LogInConfirm", - "IsLegal":true/false, + "IsLegal":true, "Username": "...", "Nickname": "...", "Profile" : { @@ -47,16 +47,31 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework } ``` +``` json + { + "MsgType": "LogInConfirm", + "IsLegal": false, + } + } + ``` +### 登录后服务端行为 + +首先发送 LogInConfirm +接下来分别发送所有与该用户相关的 Session 信息, 相关 User 信息 +客户端加载数据库,发送消息版本信息 +服务端发送缺少的消息 + + ### 数据格式协议 #### User Model 的 Json 表示 ``` json { - "MsgType": "UserData, + "MsgType": "UserData", "Username": "...", "Nickname": "...", "Profile" : { - "signiture" : "...", + "Signiture" : "...", "..." : "...", } } @@ -126,6 +141,24 @@ BIT ICQ, a Realtime Communicating Solution using C++ Qt framework } ``` +消息版本列表 +``` json +{ + "MsgType": "MessageVersion", + "Data": [ + { + "SessionID": ..., + "LatestMessageID": ... + }, + { + "SessionID": ..., + "LatestMessageID": ... + }, + ... + ] +} +``` + #### 软件架构 软件架构说明 diff --git a/Server/Server.pro b/Server/Server.pro index 76e092e3ecc3e5ebe1e910b4859e8d11bb0e39b4..cc4d2c635022a4d42c942c20a8aeb41d7999ebdd 100644 --- a/Server/Server.pro +++ b/Server/Server.pro @@ -22,6 +22,7 @@ SOURCES += \ databaseoperation.cpp \ main.cpp \ messagemodel.cpp \ + operations.cpp \ serverdatacenter.cpp \ widget.cpp\ handlesignal.cpp \ @@ -36,6 +37,7 @@ HEADERS += \ databaseoperation.h \ ltest.h \ messagemodel.h \ + operations.h \ serverdatacenter.h \ handlesignal.h\ sever.h\ @@ -49,3 +51,6 @@ FORMS += \ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target + +DISTFILES += \ + test.py diff --git a/Server/databaseoperation.cpp b/Server/databaseoperation.cpp index 742a3d782fc8de0daac9414a796ba72df3fcd2c0..18b00dc30332a8b9260c3439d10f3aff2d3d7346 100644 --- a/Server/databaseoperation.cpp +++ b/Server/databaseoperation.cpp @@ -10,8 +10,8 @@ QString json2str(QJsonObject json) { return QString(QJsonDocument(json).toJson()); } -QJsonObject str2json(QString & str) { - QJsonDocument jsonDoc = QJsonDocument::fromJson(str.toLocal8Bit().data()); +QJsonObject str2json(QString str) { + QJsonDocument jsonDoc = QJsonDocument::fromJson(str.toUtf8().data()); if (jsonDoc.isNull()) { qDebug() << "read json obj from str failed: str = " << str.toLocal8Bit().data(); } @@ -30,18 +30,21 @@ void DatabaseOperation::startDatabaseConnection(QString dbfilename) { } QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(dbfilename); //如果本目录下没有该文件,则会在本目录下生成,否则连接该文件 - if (!db.open()) { - qDebug() << db.lastError().text(); - throw "Database Error"; - } - status = Status::Running; + if (!db.open()) { + qDebug() << db.lastError().text(); + throw "Database Error"; + } + status = Status::Running; + createTables(); + findAllUsers(); + findAllSessions(); + findAllMessages(); } void DatabaseOperation::executeSqlStatement(QString str) { QSqlQuery query (str); if (!query.isActive()) { qDebug() << query.lastError(); - throw query.lastError(); } } @@ -62,9 +65,10 @@ void DatabaseOperation::closeDB() { database.close(); status = Status::Stop; + emit signal_DBstop(); } -QList DatabaseOperation::findAllUsers(QObject * parent) { +QList DatabaseOperation::findAllUsers() { QList ret; QSqlQuery sqlQuery; sqlQuery.exec("SELECT Username, Nickname, Password, Profile FROM User"); @@ -73,31 +77,79 @@ QList DatabaseOperation::findAllUsers(QObject * parent) { throw "DB read error"; } else { + auto & dcenter = ServerDataCenter::Singleton(); while(sqlQuery.next()) { QString username = sqlQuery.value(0).toString(); QString nickname = sqlQuery.value(1).toString(); QString profile = sqlQuery.value(3).toString(); -// qDebug() << QString("Username:%1 Nickname:%2 Profile:%3").arg(username).arg(nickname).arg(profile); - ret.append(new OnlineUserModel(username, nickname, str2json(profile))); - ret.last()->setParent(parent); + auto newuser = new OnlineUserModel(username, nickname, str2json(profile)); + dcenter.registerUser(newuser); + ret.append(newuser); + } + } + return ret; +} + +QList DatabaseOperation::findAllSessions() { + QList ret; + QSqlQuery query; + if (!query.exec("SELECT SessionID, Profile FROM Session")) { + qDebug() << "findAllSessions: " << query.lastError(); + throw "DB read error"; + } + auto & dcenter = ServerDataCenter::Singleton(); + while (query.next()) { + int sessionId = query.value(0).toInt(); + QJsonObject json = query.value(1).toJsonObject(); + QString sessionName = json.contains("SessionName") ? json["SessionName"].toString() : "None"; + + QList members = queryMembersBySession(sessionId); + + OnlineSession * session = new OnlineSession(sessionId, sessionName, json, members); + ret.append(session); + dcenter.registerSession(session); + } + return ret; +} + +QList DatabaseOperation::findAllMessages() { + QList ret; + QSqlQuery query; + if (!query.exec("SELECT SessionID, MessageID, senderUsername, MessageText, Profile FROM messages")) { + while (query.next()) { + int sessionID = query.value(0).toInt(); + int msgId = query.value(1).toInt(); + QString sender = query.value(2).toString(); + QString text = query.value(3).toString(); + QJsonObject profile = query.value(4).toJsonObject(); + + auto * msg = new OnlineMessage(msgId, sessionID, sender, text, profile); + ret.append(msg); + ServerDataCenter::Singleton().registerMessage(msg); } } return ret; } + //往User表中插入数据 bool DatabaseOperation::insertUser(const char* username, const char* nickname, const char* password, const char* profile){ QSqlQuery query; - QString insert_sql = "insert into User(Username, Nickname, Password, Profile) values (?, ?, ?, ?)"; - query.prepare(insert_sql); - query.addBindValue(username); - query.addBindValue(nickname); - query.addBindValue(password); - query.addBindValue(profile); - if (! query.exec() ) { +// QString insert_sql = "insert into User(Username, Nickname, Password, Profile) values (?, ?, ?, ?)"; + QString insert_sql = QString("INSERT INTO User(Username, Nickname, Password, Profile) VALUES ('%1', '%2', '%3', '%4')") + .arg(username).arg(nickname).arg(password).arg(profile); + qDebug() << insert_sql; +// query.prepare(insert_sql); +// query.addBindValue(username); +// query.addBindValue(nickname); +// query.addBindValue(password); +// query.addBindValue(profile); + if (! query.exec(insert_sql) ) { qDebug() << query.lastError(); return false; } + ServerDataCenter::Singleton().registerUser(new OnlineUserModel( + QString(username), QString(nickname), str2json(QString(profile)) )); return true; } @@ -186,7 +238,7 @@ QList DatabaseOperation::querySessionsByMember(const char * username){ return member_List; } -bool DatabaseOperation::attemptLogIn(const char *username, const char *password) const { +bool DatabaseOperation::attemptLogIn(QString username, QString password) const { //用户名检测 QSqlQuery query(database); query.prepare("select username, password from User where username=?"); @@ -250,9 +302,7 @@ QList DatabaseOperation::getMessageListBySessionID(int SessionId) const { QJsonObject profile = query.value(3).toJsonObject(); auto * msg = new OnlineMessage(msgId, SessionId, senderUsername, messageText, profile); ret.append(msgId); - if (!ServerDataCenter::Singleton().hasMessage(SessionId, msgId)) { - ServerDataCenter::Singleton().registerMessage(msg); - } + ServerDataCenter::Singleton().registerMessage(msg); } return ret; } @@ -275,30 +325,19 @@ OnlineSession & ServerDataCenter::getSession(int SessionId) { OnlineUserModel* ServerDataCenter::_getUser(QString username) { if (users.contains(username)) return users[username]; - auto * ret = DatabaseOperation::Singleton().findUser(username); - if (ret == nullptr) return nullptr; - registerUser(ret); - return ret; + return nullptr; } OnlineSession* ServerDataCenter::_getSession(int SessionId) { if (sessions.contains(SessionId)) return sessions[SessionId]; - auto * ret = DatabaseOperation::Singleton().findSession(SessionId); - if (ret == nullptr) - return nullptr; - registerSession(ret); - return ret; + return nullptr; } OnlineMessage* ServerDataCenter::_getMessage(int SessionId, int MessageId) { if (messages.contains({SessionId, MessageId})) return messages[{SessionId, MessageId}]; - auto * ret = DatabaseOperation::Singleton().findMessage(SessionId, MessageId); - if (ret == nullptr) - return nullptr; - registerMessage(ret); - return ret; + return nullptr; } OnlineUserModel * DatabaseOperation::findUser(QString username) { @@ -350,3 +389,7 @@ OnlineMessage * DatabaseOperation::findMessage(int sessionId, int MessageId) { return ret; } +ServerDataCenter::ServerDataCenter(QObject *parent) : QObject(parent) +{ + connect(&DatabaseOperation::Singleton(), &DatabaseOperation::signal_DBstop, this, &ServerDataCenter::clean); +} diff --git a/Server/databaseoperation.h b/Server/databaseoperation.h index f64f37ccfe7d998b6fcc9d2390c02132941dd392..f990432a9215b960d7d8fb29c6f1466dfa7c20e6 100644 --- a/Server/databaseoperation.h +++ b/Server/databaseoperation.h @@ -12,7 +12,7 @@ QString json2str(QJsonObject json); -QJsonObject str2json(QString & str); +QJsonObject str2json(QString str); class DatabaseOperation : public QObject { @@ -23,35 +23,41 @@ public: return *singleton; } - bool attemptLogIn(const char * username, const char * password) const; void startDatabaseConnection(QString dbfilename); - void createTables(); bool isDBExist(QString str) const; void closeDB(); - QList findAllUsers(QObject * parent = nullptr); + int getTableCount(const char * tableName) const; + QList findAllUsers(); + QList findAllSessions(); + QList findAllMessages(); + bool insertUser(const char * username, const char * nickname, const char * password, const char * profile); bool insertUser(const OnlineUserModel &user, const QString &password); // 返回SessionID int insertSessionBasicInfo(const char * sessionType, const char * profile); bool isRunning() const { return status == Status::Running; } - bool loginRequest(const char * username, const char * password); - int getTableCount(const char * tableName) const; bool insertMember(int sessionID, const OnlineUserModel& user); bool insertMember(int sessionID, const char * user); + int insertNewMessage(int SessionId, const char *senderUsername, const char *MessageText, const char *profile); + QList queryMembersBySession(int sessionID); QList querySessionsByMember(const char * username); QList getMessageListBySessionID(int SessionId) const; - int insertNewMessage(int SessionId, const char *senderUsername, const char *MessageText, const char *profile); + OnlineMessage * findMessage(int sessionId, int MessageId); OnlineSession * findSession(int sessionID); OnlineUserModel * findUser(QString username); + bool attemptLogIn(QString username, QString password) const; signals: + void signal_DBstop(); + private: explicit DatabaseOperation(QObject *parent = nullptr); enum class Status { Stop, Running } status; void executeSqlStatement(QString str); + void createTables(); QSqlDatabase database; }; diff --git a/Server/operations.cpp b/Server/operations.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b878eceb3a4f376742532ecd74b0e74a3fac7bb --- /dev/null +++ b/Server/operations.cpp @@ -0,0 +1,67 @@ +#include "operations.h" +#include "serverdatacenter.h" +#include "databaseoperation.h" + +Operations::Operations(QObject *parent) : QObject(parent) +{ + +} + + + + + +ServerDataCenter& dcenter = ServerDataCenter::Singleton(); +using resp = QList; +using Json = QJsonObject; + + + +resp Operations::loginResponse(QJsonObject json) { + DatabaseOperation & db = DatabaseOperation::Singleton(); + QString username = json["Username"].toString(); + QString password = json["Password"].toString(); + + Json response = { {"MsgType", "LogInConfirm"}, {"IsLegal", false}}; + if (!db.attemptLogIn(username, password)) { + return {response}; + } + response["IsLegal"] = true; + response["Username"] = username; + auto & user = dcenter.getUser(username); + response["Nickname"] = user.getNickname(); + response["Profile"] = user.getProfile(); + resp ret = {response}; + + auto sessionlist = db.querySessionsByMember(username.toUtf8().data()); + for (int i = 0; i < sessionlist.size(); i++) { + auto userlist = db.queryMembersBySession(sessionlist.at(i)); + for (int j = 0; j < userlist.size(); j++) { + auto cur = userlist.at(j); + if (cur == username) continue; + + auto & curuser = dcenter.getUser(cur); + ret.append(curuser.generateUserModelJson()); + } + ret.append(dcenter.getSession(sessionlist.at(i)).generateJsonFromData()); + } + return ret; +} + + +resp Operations::registerResponse(QJsonObject json) { + DatabaseOperation & db = DatabaseOperation::Singleton(); + auto & dcenter = ServerDataCenter::Singleton(); + Json head = {{"MsgType", "RegistConfirm"}, + {"IsLegal", false}}; + if (dcenter.hasUser(json["Username"].toString())) return {head}; + char * username = json["Username"].toString().toUtf8().data(); + Q_ASSERT(username == json["Username"].toString()); + char * nickname = json["Nickname"].toString().toUtf8().data(); + char * password = json["Password"].toString().toUtf8().data(); + + if (!db.insertUser(username, nickname, password, "{ \"Signiture\": \"None\"}")) + return {head}; + head["IsLegal"] = true; + return {head}; +} diff --git a/Server/operations.h b/Server/operations.h new file mode 100644 index 0000000000000000000000000000000000000000..96f2b6824d2ca32681ed3fc87a3bdd05dadb4625 --- /dev/null +++ b/Server/operations.h @@ -0,0 +1,33 @@ +#ifndef OPERATIONS_H +#define OPERATIONS_H + +#include +#include +#include + +class Operations : public QObject +{ + Q_OBJECT + using resp = QList; + using Json = QJsonObject; + +public: + static Operations& Singleton(QObject *parent = nullptr) + { + static Operations * singleton = new Operations(parent); + return *singleton; + } + + QList request(QJsonObject json); + +signals: +public: + explicit Operations(QObject *parent = nullptr); + + QList registerResponse(QJsonObject json); + + QList loginResponse(QJsonObject json); + +}; + +#endif // OPERATIONS_H diff --git a/Server/serverdatacenter.cpp b/Server/serverdatacenter.cpp index 79ec0a1d6196625b48f27acdf58c6e382c558b43..20076d6374fb164e63a52abd7556a96592a8e36c 100644 --- a/Server/serverdatacenter.cpp +++ b/Server/serverdatacenter.cpp @@ -1,9 +1,6 @@ #include "serverdatacenter.h" +#include -ServerDataCenter::ServerDataCenter(QObject *parent) : QObject(parent) -{ - -} void ServerDataCenter::registerUser(OnlineUserModel * newuser) { if (users.contains(newuser->getUsername())) { @@ -11,7 +8,8 @@ void ServerDataCenter::registerUser(OnlineUserModel * newuser) { } users[newuser->getUsername()] = newuser; newuser->setParent(this); - registeredObjects.insert(newuser); + registeredObjects.append(newuser); + } void ServerDataCenter::registerSession(OnlineSession *session) { @@ -20,7 +18,7 @@ void ServerDataCenter::registerSession(OnlineSession *session) { } sessions[session->getSessionID()] = session; session->setParent(this); - registeredObjects.insert(session); + registeredObjects.append(session); } void ServerDataCenter::registerMessage(OnlineMessage *msg) { @@ -29,7 +27,8 @@ void ServerDataCenter::registerMessage(OnlineMessage *msg) { } messages[{msg->getSessionID(), msg->getMessageID()}] = msg; msg->setParent(this); - registeredObjects.insert(msg); + registeredObjects.append(msg); + qDebug() << "### ServerDataCenter Down"; } @@ -43,3 +42,10 @@ bool ServerDataCenter::hasSession(int sessionId) { bool ServerDataCenter::hasMessage(int sessionId, int messageId) { return _getMessage(sessionId, messageId) != nullptr; } + +void ServerDataCenter::clean() { + users.clear(); + sessions.clear(); + messages.clear(); + registeredObjects.clear(); +} diff --git a/Server/serverdatacenter.h b/Server/serverdatacenter.h index 569ef4820b7e1a79346847e6b5cda5205c7976fe..b3606d239013e81e6e3faa04f04a30727665ce23 100644 --- a/Server/serverdatacenter.h +++ b/Server/serverdatacenter.h @@ -22,6 +22,7 @@ public: return * singleton; } + // 将用户模型插入到datacenter void registerUser(OnlineUserModel * newuser); void registerSession(OnlineSession * session); void registerMessage(OnlineMessage * msg); @@ -33,16 +34,19 @@ public: bool hasSession(int sessionId); bool hasMessage(int sessionId, int messageId); -signals: +public slots: + void clean(); + private: explicit ServerDataCenter(QObject *parent = nullptr); QMap users; - QSet registeredObjects; + QList registeredObjects; QMap sessions; QMap, OnlineMessage *> messages; OnlineSession* _getSession(int SessionId); OnlineUserModel* _getUser(QString username); OnlineMessage* _getMessage(int SessionId, int MessageId); + }; diff --git a/Server/sever.cpp b/Server/sever.cpp index 334840558a989da85b94af81b2546675d10b4443..943d40a6feb626c35acc6cb2cba4c44f9ac769f9 100644 --- a/Server/sever.cpp +++ b/Server/sever.cpp @@ -1,58 +1,83 @@ -#include "sever.h" -#include"handlesignal.h" -#include -#include - - -Sever::Sever(QObject *parent) : QTcpServer (parent) -{ - - - - -} - -void Sever::incomingConnection(qintptr handle) -{ - - qDebug()<<"产生了新连接!!!"; - //重写产生新连接 - QTcpSocket *socket = new QTcpSocket(this); - socket->setSocketDescriptor (handle); - qDebug()<< handle; - - - clientMap.insert (handle,socket); - - handleSignal *newHandle = new handleSignal(handle); - - connect(newHandle, &handleSignal::sendSignal, this,&Sever::receiveMessage); - connect (socket, &QTcpSocket::readyRead, [=](){ - newHandle->aaa(handle); - }); - - - emit sendChannel (handle); - - emit sendMsg (socket->peerAddress ().toString ()+"上线了", 2); -} - -void Sever::setIP(QString str) -{ - - if(listen(QHostAddress(str) ,8888)) - { - qDebug()<<"服务器成功开启!"; - } -} - - -void Sever::receiveMessage(int handle) -{ - qDebug()<<"in receive message!"; - - QMap::iterator it = clientMap.find (handle); - QString receiveMes = it.value ()->readAll ().data (); - - emit sendMsg (receiveMes, 1); -} +#include "sever.h" +#include"handlesignal.h" +#include +#include +#include"operations.h" +#include +#include"databaseoperation.h" + +Sever::Sever(QObject *parent) : QTcpServer (parent) +{ + +} + +void Sever::incomingConnection(qintptr handle) +{ + + qDebug()<<"产生了新连接!!!"; + //设置新加入的socket并加入clientMap + QTcpSocket *socket = new QTcpSocket(this); + socket->setSocketDescriptor (handle); + + clientMap.insert (handle,socket); + + handleSignal *newHandle = new handleSignal(handle); + + connect(newHandle, &handleSignal::sendSignal, this,&Sever::receiveMessage); + + //以后的每次数据读入,将会触发handle信号,随后连锁反应会接受上面的信号 + connect (socket, &QTcpSocket::readyRead, [=](){ + newHandle->aaa(handle); + }); + + emit sendChannel (handle); + + emit linkMsg (socket->peerAddress ().toString ()+"上线了", 2); //2表示在登录框中显示 + +} + +void Sever::setIP(QString str) +{ + + if(listen(QHostAddress(str) ,8888)) + { + DatabaseOperation& db = DatabaseOperation::Singleton(); + db.startDatabaseConnection ("Server.db"); + qDebug()<<"服务器成功开启!"; + } +} + + +void Sever::receiveMessage(int handle) +{ + qDebug()<<"in receive message!"; + + //根据不同handle信号找到应该接受信息的socket + QMap::iterator it = clientMap.find (handle); + QByteArray receiveMes = it.value ()->readAll (); + QJsonDocument receJson = QJsonDocument::fromJson (receiveMes); + QJsonObject recejson = receJson.object (); + if(!recejson.contains ("MsgType")) + { + qDebug()<<"receive message is not json!"; + + return ; + } + QString method = recejson["MsgType"].toString().toLower(); + + auto returnList = QList(); + auto &op = Operations::Singleton (); + if(method == "login") + { + returnList = op.loginResponse (recejson); + } + else if (method == "regist") { + returnList = op.registerResponse(recejson); + } + else if (method == "info") { + qDebug() << recejson["Message"].toString(); + emit linkMsg(recejson["Message"].toString(), 1); + } + qDebug() << returnList; + emit sendMsg (returnList, handle); //1表示在文本框中显示 +} diff --git a/Server/sever.h b/Server/sever.h index 92cad24aef8f73e3ce77f7021300a25df2022609..2c6d4689b9f77840f47c96eb1378ec2ab7432b18 100644 --- a/Server/sever.h +++ b/Server/sever.h @@ -5,6 +5,7 @@ #include #include #include +#include class Sever : public QTcpServer { Q_OBJECT @@ -22,7 +23,8 @@ public slots: void setIP(QString); signals: - void sendMsg(QString, int); //将tcp_server收到的信息作为信号发送给mianwindow + void linkMsg(QString, int); + void sendMsg(QList, int);//将tcp_server收到的信息作为信号发送给mianwindow void ready_Read(qintptr); void sendChannel(int); }; diff --git a/Server/test.py b/Server/test.py new file mode 100644 index 0000000000000000000000000000000000000000..976f0d663b5b74c0bfab9179a1cb8fb03bb244fd --- /dev/null +++ b/Server/test.py @@ -0,0 +1,5 @@ +# This Python file uses the following encoding: utf-8 + +# if__name__ == "__main__": +# pass + diff --git a/Server/testcases.cpp b/Server/testcases.cpp index f85702adc5578bcda405dbbc4e4432008863842d..3fb65ca9bb9a5a1d4baa2b892e1727ca25a28331 100644 --- a/Server/testcases.cpp +++ b/Server/testcases.cpp @@ -7,6 +7,7 @@ #include "databaseoperation.h" #include "serverdatacenter.h" +#include "operations.h" #include "ltest.h" @@ -208,20 +209,21 @@ void execute() { } ENDSUITE(MessageTest) +QString randDBname; + TESTSUITE(DB) DatabaseOperation& db = DatabaseOperation::Singleton(); QString dbname, fixed_dbname = "test.db"; void ctor() override { qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); - dbname = QString::number(qrand()) + ".db"; + randDBname = dbname = QString::number(qrand()) + ".db"; testlog("dbname = %s (testlog)", dbname.toUtf8().data()); } CASE(CanCreateNewDB) { assertTrue(!db.isDBExist(dbname)); db.startDatabaseConnection(dbname); - db.createTables(); assertTrue(db.isDBExist(dbname)); db.closeDB(); assertTrue(!db.isRunning()); @@ -237,7 +239,7 @@ void insertUser() { void checkInsertedUser() { auto list = db.findAllUsers(); - assertEqual(db.getTableCount("User"), 5); + assertEqual(db.getTableCount("User"), 5, db.getTableCount("User")); assertEqual(list.size(), 5); assertEqual(list.at(0)->getUsername(), "xiaoming"); assertEqual(list.at(2)->getNickname(), "wuzirui"); @@ -333,9 +335,77 @@ CASE(LogIn_FailedTest) { void execute() override { EXE(CanCreateNewDB); EXE(EmptyDB_InsertionTest); - EXE(CanLoadExistingDB); +// EXE(CanLoadExistingDB); EXE(CanLogIn_With_CorrectAccount); EXE(LogIn_FailedTest); } ENDSUITE(DB) + + +TESTSUITE(Functional) + +DatabaseOperation &db = DatabaseOperation::Singleton(); +ServerDataCenter &dcenter = ServerDataCenter::Singleton(); +Operations &op = Operations::Singleton(); + +void ctor() { + db.startDatabaseConnection(randDBname); + qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime())); +} +void dtor() { db.closeDB(); } + +CASE(LoginProcessTest) { + QJsonObject loginRequest; + loginRequest["MsgType"] = "LogIn"; + loginRequest["Username"] = "wuzirui"; + loginRequest["Password"] = "1234"; + + auto response = op.loginResponse(loginRequest); + assertTrue(response.size() > 0); + assertEqual(response.at(0)["MsgType"], "LogInConfirm"); + assertEqual(response.at(0)["IsLegal"].toBool(), true); + + loginRequest["Password"] = "4321"; + response = op.loginResponse(loginRequest); + assertEqual(response.size(), 1); + assertEqual(response.at(0)["IsLegal"].toBool(), false); +} + +CASE(RegisterTest) { + QString username = "User_" + QString::number(qrand()); + auto & dcenter = ServerDataCenter::Singleton(); + while (dcenter.hasUser(username)) { + username = "User_" + QString::number(qrand()); + } + testlog("register username %s", username.toUtf8().data()); + QString password = "upass::" + username; + QString nickname = "tempuser"; + + QJsonObject request = {{ "MsgType", "Regist" }}; + request["Username"] = username; + request["Password"] = password; + request["Nickname"] = nickname; + + auto response = op.registerResponse(request); + assertEqual(response.size(), 1); + assertEqual(response[0]["IsLegal"].toBool(), true); + + response = op.registerResponse(request); + assertEqual(response.size(), 1); + assertEqual(response[0]["IsLegal"].toBool(), false); +} + +CASE(AddFriendTest) { + +} + +void execute() { + EXE(LoginProcessTest); + for (int i = 0; i < 10; i++) { + EXE(RegisterTest); + } + EXE(AddFriendTest); +} + +ENDSUITE(Functional) diff --git a/Server/usermodel.cpp b/Server/usermodel.cpp index e687885325f947c0524d9a3b1b51ba0d9038d7aa..bf3f1543dd1aed49e2a84877e8eadf21a0f14fe7 100644 --- a/Server/usermodel.cpp +++ b/Server/usermodel.cpp @@ -22,13 +22,6 @@ void OnlineUserModel::loadBasicInfoFromJson(QJsonObject &json) { profile = json["Profile"].toObject(); } -OnlineUserModel::OnlineUserModel(OnlineUserModel& old): - QObject(old.parent()) -{ - username = old.username; - nickname = old.nickname; - profile = old.profile; -} OnlineUserModel::OnlineUserModel(QString usrname, QString nick, QJsonObject json, QObject * parent) : UserModel(parent) @@ -39,6 +32,15 @@ OnlineUserModel::OnlineUserModel(QString usrname, QString nick, QJsonObject json } +QJsonObject OnlineUserModel::generateUserModelJson() const { + QJsonObject json; + json["MsgType"] = "UserData"; + json["Username"] = username; + json["Nickname"] = nickname; + json["Profile"] = profile; + return json; +} + QJsonObject OfflineUserModel::generateUserModelJson() const { QJsonObject json; json["Username"] = username; diff --git a/Server/usermodel.h b/Server/usermodel.h index b0bcbb93231f5c5ca2b7acd2530eb7396f4edc9a..ccb7ab9ce1a89949e47833aae52e30afa3012b77 100644 --- a/Server/usermodel.h +++ b/Server/usermodel.h @@ -32,10 +32,10 @@ public: Type getType() const { return Type::Offline; } void setNickname(QString nname) { nickname = nname; } void setSigniture(QString sig) { profile["Signiture"] = sig; } - QJsonObject generateUserModelJson() const; + signals: }; @@ -47,11 +47,11 @@ class OnlineUserModel : virtual public UserModel, virtual public QObject public: OnlineUserModel(QJsonObject &json, QObject *parent = nullptr); OnlineUserModel(QString usrname, QString nick, QJsonObject json, QObject * parent = nullptr); - OnlineUserModel(OnlineUserModel& old); Type getType() const { return Type::Online; } const QString& getNickname() const { return nickname; } const QString getSigniture() const { return profile["Signiture"].toString(); } + QJsonObject generateUserModelJson() const; signals: private: diff --git a/Server/widget.cpp b/Server/widget.cpp index 1bf7bf7e7a6407107e45d92b0b16af35fd0160f5..29a6129c7df51a6cd7b0a9e1d9749a599e249b82 100644 --- a/Server/widget.cpp +++ b/Server/widget.cpp @@ -1,5 +1,8 @@ #include "widget.h" #include "ui_widget.h" +#include "operations.h" +#include +#include Widget::Widget(QWidget *parent) : QWidget(parent) @@ -7,8 +10,13 @@ Widget::Widget(QWidget *parent) { ui->setupUi(this); - connect(&sever, &Sever::sendMsg,this, &Widget::printMes); + //widget接受来自server的信息,并进行打印 + connect(&sever, &Sever::linkMsg,this, &Widget::printLink); + connect(&sever, &Sever::sendMsg,this, &Widget::printMsg); + //socket首次连接之后设置handle connect(&sever, &Sever::sendChannel,this,&Widget::setChannel); + + //widget发出setip信号,给server设置ip,开启listen connect(this,&Widget::pushIP,&sever, &Sever::setIP); } @@ -19,7 +27,7 @@ Widget::~Widget() } -void Widget::printMes(QString str, int type) +void Widget::printLink(QString str, int type) { if(type==1) { @@ -34,16 +42,30 @@ void Widget::printMes(QString str, int type) } +void Widget::printMsg(QList list, int handle) +{ + qDebug() << "in printMsg!"; + for(int i=0;iwrite(send2.data ()); + } +} + void Widget::on_btnSend_clicked() { + //发送功能实现,点对点 int channelName = ui->comboBox->currentText ().toUInt (); QByteArray sendText = ui->teSend->toPlainText ().toUtf8 (); - + //通过handle键取到值 sever.clientMap[channelName]->write (sendText); } void Widget::on_btnRadio_clicked() { + //广播功能实现,点对多点 QMap::iterator it; for ( it = sever.clientMap.begin(); it != sever.clientMap.end(); ++it ) { @@ -53,6 +75,7 @@ void Widget::on_btnRadio_clicked() void Widget::setChannel(int channel) { + //将handle加入combobox待选 qDebug()<<"setchannel"; if(ui->comboBox->findText(QString::number (channel)) == -1) qDebug()<,int); void on_btnSend_clicked(); @@ -35,6 +37,7 @@ signals: private: Ui::Widget *ui; + Sever sever; //实例化一个sever对象 }; #endif // WIDGET_H diff --git a/git_try_0827/git_try_0827.pro b/git_try_0827/git_try_0827.pro index b695efb6826519086829e7609a364b4a071f96ac..7b47cc2e7a1b366e46267db11c08bd2f5f91106b 100644 --- a/git_try_0827/git_try_0827.pro +++ b/git_try_0827/git_try_0827.pro @@ -1,31 +1,31 @@ -QT += core gui network - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -CONFIG += c++11 - -# The following define makes your compiler emit warnings if you use -# any Qt feature that has been marked deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -SOURCES += \ - main.cpp \ - widget.cpp - -HEADERS += \ - widget.h - -FORMS += \ - widget.ui - -# Default rules for deployment. -qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin -!isEmpty(target.path): INSTALLS += target +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + widget.cpp + +HEADERS += \ + widget.h + +FORMS += \ + widget.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/git_try_0827/main.cpp b/git_try_0827/main.cpp index b0a4ec26478f6b9aba3e1747ec464ea0c26dd5b9..c3efeb46c6278c0805a7e7764d78bd6bf01eea76 100644 --- a/git_try_0827/main.cpp +++ b/git_try_0827/main.cpp @@ -1,11 +1,11 @@ -#include "widget.h" - -#include - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - Widget w; - w.show(); - return a.exec(); -} +#include "widget.h" + +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Widget w; + w.show(); + return a.exec(); +} diff --git a/git_try_0827/widget.cpp b/git_try_0827/widget.cpp index 63b8f3513e019244c9fff21b6aac64a4f5575a27..4f66be1f864c81c70313ea8256cdbc4dcd22b577 100644 --- a/git_try_0827/widget.cpp +++ b/git_try_0827/widget.cpp @@ -1,28 +1,28 @@ -#include "widget.h" -#include "ui_widget.h" -#include -#include - -Widget::Widget(QWidget *parent) - : QWidget(parent) - , ui(new Ui::Widget) -{ - ui->setupUi(this); -} - -Widget::~Widget() -{ - delete ui; -} - - -void Widget::on_btnGet_clicked() -{ - QByteArray file = get(ui->lineEdit->text ()); - ui->textEdit->setText (file); - - QJsonDocument newjson = QJsonDocument::fromJson(file); - QJsonObject jsonObject = newjson.object (); - qDebug() << jsonObject["commit"].toObject ()["message"]; - -} +#include "widget.h" +#include "ui_widget.h" +#include +#include + +Widget::Widget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::Widget) +{ + ui->setupUi(this); +} + +Widget::~Widget() +{ + delete ui; +} + + +void Widget::on_btnGet_clicked() +{ + QByteArray file = get(ui->lineEdit->text ()); + ui->textEdit->setText (file); + + QJsonDocument newjson = QJsonDocument::fromJson(file); + QJsonObject jsonObject = newjson.object (); + qDebug() << jsonObject["commit"].toObject ()["message"]; + +} diff --git a/git_try_0827/widget.h b/git_try_0827/widget.h index 31fa66c1b02b4e5bb9634ca26efb986725619158..a4f2a7dd23873934777dcd02237f93b582d14982 100644 --- a/git_try_0827/widget.h +++ b/git_try_0827/widget.h @@ -1,41 +1,41 @@ -#ifndef WIDGET_H -#define WIDGET_H - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE -namespace Ui { class Widget; } -QT_END_NAMESPACE - -class Widget : public QWidget -{ - Q_OBJECT - -public: - Widget(QWidget *parent = nullptr); - ~Widget(); - QByteArray get(const QString &str_url){ - - const QUrl url = QUrl::fromUserInput(str_url); - QNetworkRequest qnr(url); - QNetworkAccessManager qnam; - QNetworkReply *reply = qnam.get(qnr); - QEventLoop eventloop; - QObject::connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit); - eventloop.exec(QEventLoop::ExcludeUserInputEvents); - QByteArray reply_data = reply->readAll(); - reply->deleteLater(); - reply = nullptr; - return reply_data; - } - -private slots: - void on_btnGet_clicked(); - -private: - Ui::Widget *ui; -}; -#endif // WIDGET_H +#ifndef WIDGET_H +#define WIDGET_H + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class Widget; } +QT_END_NAMESPACE + +class Widget : public QWidget +{ + Q_OBJECT + +public: + Widget(QWidget *parent = nullptr); + ~Widget(); + QByteArray get(const QString &str_url){ + + const QUrl url = QUrl::fromUserInput(str_url); + QNetworkRequest qnr(url); + QNetworkAccessManager qnam; + QNetworkReply *reply = qnam.get(qnr); + QEventLoop eventloop; + QObject::connect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit); + eventloop.exec(QEventLoop::ExcludeUserInputEvents); + QByteArray reply_data = reply->readAll(); + reply->deleteLater(); + reply = nullptr; + return reply_data; + } + +private slots: + void on_btnGet_clicked(); + +private: + Ui::Widget *ui; +}; +#endif // WIDGET_H diff --git a/git_try_0827/widget.ui b/git_try_0827/widget.ui index 43a5c186e46a3de24824f746fa72ca24a5d38622..4efb67538faa7a2b8ffb4a1486dc7d0705e3c955 100644 --- a/git_try_0827/widget.ui +++ b/git_try_0827/widget.ui @@ -1,78 +1,78 @@ - - - Widget - - - - 0 - 0 - 1200 - 900 - - - - Widget - - - - - 110 - 30 - 951 - 71 - - - - - - - 40 - 20 - 151 - 81 - - - - URL - - - - - - 1080 - 30 - 111 - 71 - - - - get! - - - - - - 30 - 170 - 1151 - 701 - - - - - - - 40 - 110 - 171 - 61 - - - - JSON file - - - - - - + + + Widget + + + + 0 + 0 + 1200 + 900 + + + + Widget + + + + + 110 + 30 + 951 + 71 + + + + + + + 40 + 20 + 151 + 81 + + + + URL + + + + + + 1080 + 30 + 111 + 71 + + + + get! + + + + + + 30 + 170 + 1151 + 701 + + + + + + + 40 + 110 + 171 + 61 + + + + JSON file + + + + + +