diff --git a/DOCS/MainScheme.md b/DOCS/MainScheme.md index df33264..1356240 100644 --- a/DOCS/MainScheme.md +++ b/DOCS/MainScheme.md @@ -74,13 +74,8 @@ UnityClient ServerLMS ^EJX4eIpX Mainthread: -*serverLMS -*dataParser -*MultiThreadServer -*processingSystem -*commonClientHandler -*chatSystem -*processParser ^ite9vjus +*ServerLMSWidget + ^ite9vjus ClientHandler: Thread @@ -95,8 +90,7 @@ UpdateThread: *updateController *assetsManager *docsUpdater -*cfi controller - +*cfiController ^ZvWgIkFz Client QT ^sWMT4y6l @@ -315,613 +309,604 @@ SEND DOCS ^iM67vAqM потому что по умолчанию он больше не пересылается ^WR3pLokt -клиент ^jS176TGw - -сервер ^iocxwS9A - -распознать ^bqTQQhWG - -дать ответ ^iMm4VpVB - -клиент ^4Cpz1VHI +ServerThread: +*providerDBLMS +*dataParser +*MultiThreadServer +*processingSystem +*commonClientHandler +*chatSystem +*processParser ^UjfEZdiN %% ## Drawing ```compressed-json -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 ``` %% \ No newline at end of file diff --git a/FILES/translations/RRJServer_ru_RU.qm b/FILES/translations/RRJServer_ru_RU.qm index 76bba9d..0622911 100644 Binary files a/FILES/translations/RRJServer_ru_RU.qm and b/FILES/translations/RRJServer_ru_RU.qm differ diff --git a/LibDataBaseInterface/databaselms.cpp b/LibDataBaseInterface/databaselms.cpp index d4216e3..1108a6c 100644 --- a/LibDataBaseInterface/databaselms.cpp +++ b/LibDataBaseInterface/databaselms.cpp @@ -9,12 +9,12 @@ const QString DataBaseLMS::TypeUserDBInstructor = "instructor"; const QString DataBaseLMS::TypeUserDBTrainee = "trainee"; -DataBaseLMS::DataBaseLMS(QWidget *ownerWidget, QObject *parent): +QString DataBaseLMS::UserNamePostgres = ""; +QString DataBaseLMS::PasswordPostgres = ""; + +DataBaseLMS::DataBaseLMS(QObject *parent): QObject(parent), - db(nullptr), - UserNamePostgres(""), - PasswordPostgres(""), - ownerWidget(ownerWidget) + db(nullptr) { } diff --git a/LibDataBaseInterface/databaselms.h b/LibDataBaseInterface/databaselms.h index 64d4fd9..6b8b702 100644 --- a/LibDataBaseInterface/databaselms.h +++ b/LibDataBaseInterface/databaselms.h @@ -31,7 +31,7 @@ class DATABASELMS_EXPORT DataBaseLMS : public QObject Q_OBJECT public: - DataBaseLMS(QWidget *ownerWidget, QObject *parent = nullptr); + DataBaseLMS(QObject *parent = nullptr); ~DataBaseLMS(); signals: @@ -40,11 +40,14 @@ signals: public: static const QString TypeUserDBInstructor; static const QString TypeUserDBTrainee; +protected: + static QString UserNamePostgres; + static QString PasswordPostgres; public: //PostgreSQL - bool setUserPasswordPostgres(QString userName, QString password); - bool checkDriverQPSQLavailable(); + static bool checkDriverQPSQLavailable(); + static bool setUserPasswordPostgres(QString userName, QString password); bool checkUserLMSexist(); bool checkDataBaseLMSexist(); bool createUser(); @@ -118,7 +121,7 @@ protected: int updateReportFIMforTask(TaskAmmFim task); public: - DataBaseSettings getDataBaseSettings(); + static DataBaseSettings getDataBaseSettings(); private: int queryExecInt(QString queryStr); QString queryExecString(QString queryStr); @@ -129,12 +132,6 @@ private: protected: QSqlDatabase* db; DataBaseSettings dbSettings; - - QString UserNamePostgres; - QString PasswordPostgres; - -private: - QWidget* ownerWidget; }; #endif // DATABASELMS_H diff --git a/LibDataBaseInterface/interfacedatabaselms.cpp b/LibDataBaseInterface/interfacedatabaselms.cpp index 1cea546..97f0d01 100644 --- a/LibDataBaseInterface/interfacedatabaselms.cpp +++ b/LibDataBaseInterface/interfacedatabaselms.cpp @@ -4,9 +4,8 @@ #include #include "interfacedatabaselms.h" -InterfaceDataBaseLMS::InterfaceDataBaseLMS(QWidget *ownerWidget, QObject *parent): - DataBaseLMS(ownerWidget, parent), - ownerWidget(ownerWidget) +InterfaceDataBaseLMS::InterfaceDataBaseLMS(QObject *parent): + DataBaseLMS(parent) { } diff --git a/LibDataBaseInterface/interfacedatabaselms.h b/LibDataBaseInterface/interfacedatabaselms.h index a63f7c4..4fa01d4 100644 --- a/LibDataBaseInterface/interfacedatabaselms.h +++ b/LibDataBaseInterface/interfacedatabaselms.h @@ -20,7 +20,7 @@ public: errAlreadyLogIn }; public: - InterfaceDataBaseLMS(QWidget *ownerWidget, QObject *parent = nullptr); + InterfaceDataBaseLMS(QObject *parent = nullptr); public: //Соединение @@ -105,9 +105,6 @@ public: int replaceReportFIM(TaskAmmFim task); int changeStatusTaskFIM(int id_task, QString status); int changeStatusTaskAMM(int id_task, QString status); - -private: - QWidget* ownerWidget; }; #endif // INTERFACEDATABASELMS_H diff --git a/LibDataBaseInterface/typeQueryToDB.h b/LibDataBaseInterface/typeQueryToDB.h index 1bf1107..a69a30e 100644 --- a/LibDataBaseInterface/typeQueryToDB.h +++ b/LibDataBaseInterface/typeQueryToDB.h @@ -5,6 +5,9 @@ enum TypeQueryToDB{ TYPE_QUERY_GET_ALL_LISTS, + TYPE_QUERY_GET_ALL_INSTRUCTORS, + TYPE_QUERY_GET_ALL_TRAINEES, + TYPE_QUERY_GET_ALL_GROUPS, TYPE_QUERY_NEW_INSTRUCTOR, TYPE_QUERY_DEL_INSTRUCTOR, TYPE_QUERY_EDIT_INSTRUCTOR, diff --git a/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.cpp b/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.cpp index 4e394cf..0292499 100644 --- a/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.cpp +++ b/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.cpp @@ -37,7 +37,7 @@ void RecognizeSystem::initialize(DataParser *dataParser/*,MainWindow *mainWindow void RecognizeSystem::recognize(QTcpSocket *socket) { - qDebug() << "RecognizeThreadId " << QThread::currentThreadId(); + qDebug() << "RecognizeSystem::recognize thread ID " << QThread::currentThreadId(); QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); @@ -154,7 +154,7 @@ void RecognizeSystem::recognize(QTcpSocket *socket) continue; } - quint64 toFile = file.write(tmpBlock); + qint64 toFile = file.write(tmpBlock); emit sigSendDebugLog(Tools::getTime() + "CLIENT: toFile :" + toFile); sizeReceiveData += toFile; @@ -278,12 +278,8 @@ void RecognizeSystem::recognize(QTcpSocket *socket) emit signal_AnswerDocsChanged(); } - //if(packetType == PacketType::TYPE_XMLANSWER_QUERY_LIST_SUB_PROC_AMM) - //{ - //} - - //А)xml-ответы на запросы к БД + //А)xml-ответы на запросы к БД (или автоматическая рассылка) //B)перечни Подпроцедур switch(packetType) { @@ -294,6 +290,8 @@ void RecognizeSystem::recognize(QTcpSocket *socket) case TYPE_XMLANSWER_QUERY_DB__LIST_CLASSROOMS: case TYPE_XMLANSWER_QUERY_TASKS_AMM_FOR_TRAINEE: case TYPE_XMLANSWER_QUERY_TASKS_FIM_FOR_TRAINEE: + case TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_ALL_TRAINEES: + case TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_ALL_TRAINEES: case TYPE_XMLANSWER_QUERY_LIST_SUB_PROC_AMM: { //ПОЛУЧЕНИЕ РАЗМЕРА ФАЙЛА @@ -302,15 +300,16 @@ void RecognizeSystem::recognize(QTcpSocket *socket) stream.startTransaction(); stream >> fileSize; - if(!stream.commitTransaction()){ + if(!stream.commitTransaction()) + { emit sigSendDebugLog(Tools::getTime() + "CLIENT: fileSize - FAIL commitTransaction"); - if (!socket->waitForReadyRead(TCP_READ_TIMEOUT)) { + if (!socket->waitForReadyRead(TCP_READ_TIMEOUT)) + { emit sigSendDebugLog(Tools::getTime() + "CLIENT: ERROR! readyRead timeout - fileSize!!!"); return; } continue; - } emit sigSendDebugLog("CLIENT: filesize: " + QString::number(fileSize)); @@ -330,13 +329,16 @@ void RecognizeSystem::recognize(QTcpSocket *socket) stream.startTransaction(); stream >> tmpBlock; - if(!stream.commitTransaction()){ + if(!stream.commitTransaction()) + { - if(socket->state() == QAbstractSocket::UnconnectedState){ + if(socket->state() == QAbstractSocket::UnconnectedState) + { emit sigSocketDisabled(); return; } - if(socket->waitForReadyRead(TCP_READ_TIMEOUT)){ + if(socket->waitForReadyRead(TCP_READ_TIMEOUT)) + { continue; } @@ -347,12 +349,14 @@ void RecognizeSystem::recognize(QTcpSocket *socket) emit sigSendDebugLog(Tools::getTime() + "CLIENT: toFile :" + array.size()); - sizeReceiveData += array.size(); + sizeReceiveData = array.size(); countSend++; tmpBlock.clear(); - if(sizeReceiveData == fileSize){ + //if(sizeReceiveData == fileSize) + if(sizeReceiveData >= fileSize) + { emit sigSendDebugLog(Tools::getTime() + "FINAL Count send: " + QString::number(countSend)); emit sigSendDebugLog(Tools::getTime() + "FINAL Size received: " + QString::number(sizeReceiveData)); emit sigSendDebugLog(Tools::getTime() + "FINAL File size" + QString::number(fileSize)); @@ -379,21 +383,6 @@ void RecognizeSystem::recognize(QTcpSocket *socket) } packetType = PacketType::TYPE_NONE; - - - - /* - QByteArray array; - stream.startTransaction(); - stream >> array; - - if(!stream.commitTransaction()) - continue; - - xmlParserQueryToDB(packetType, array); - - packetType = PacketType::TYPE_NONE; - */ } break; }; @@ -952,6 +941,164 @@ void RecognizeSystem::xmlParserQueryToDB(PacketType packetType, QByteArray array emit sigAnswerQueryToDB_ListTasksFIMforTrainee(listTasks, trainee_id); } break; + + case TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_ALL_TRAINEES: + { + QMap > mapOfLists; + + QDomNode listsAllNode = commonDOM.namedItem("ListsTasksAMMofAllTrainees"); + + for(int i = 0; i < listsAllNode.childNodes().count(); i++) + { + QDomNode listOneNode = listsAllNode.childNodes().at(i); + if(listOneNode.nodeName() == "ListTasksAMM") + { + QList listTasks; + int trainee_id = 0; + trainee_id = listOneNode.toElement().attribute("trainee_id").toInt(); + + for(int i = 0; i < listOneNode.childNodes().count(); i++) + { + QDomNode taskNode = listOneNode.childNodes().at(i); + if(taskNode.nodeName() == "taskAMM") + {//Задача + TaskAmmFim task; + task.setID(taskNode.toElement().attribute("task_id").toInt()); + task.ammProcedure.title = taskNode.toElement().attribute("title"); + task.ammProcedure.dmCode = taskNode.toElement().attribute("dmCode"); + task.status = taskNode.toElement().attribute("status"); + + for(int j = 0; j < taskNode.childNodes().count(); j++) + { + QDomNode subProcNode = taskNode.childNodes().at(j); + if(subProcNode.nodeName() == "SubProc") + {//Подпроцедура + SubProc subProc; + subProc.setDmCode(subProcNode.toElement().attribute("dmCode")); + subProc.setTitle(subProcNode.toElement().attribute("title")); + subProc.setModeListStr(subProcNode.toElement().attribute("canplay")); + + task.listSubProc.append(subProc); + } + } + + listTasks.append(task); + } + } + mapOfLists.insert(trainee_id, listTasks); + } + } + + emit sigAnswerQueryToDB_ListsTasksAMMofAllTrainees(mapOfLists); + } + break; + + case TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_ALL_TRAINEES: + { + QMap > mapOfLists; + + QDomNode listsAllNode = commonDOM.namedItem("ListsTasksFIMofAllTrainees"); + + for(int i = 0; i < listsAllNode.childNodes().count(); i++) + { + QDomNode listOneNode = listsAllNode.childNodes().at(i); + if(listOneNode.nodeName() == "ListTasksFIM") + { + QList listTasks; + int trainee_id = 0; + trainee_id = listOneNode.toElement().attribute("trainee_id").toInt(); + + for(int i = 0; i < listOneNode.childNodes().count(); i++) + {//Задачи + QDomNode taskNode = listOneNode.childNodes().at(i); + if(taskNode.nodeName() == "taskFIM") + { + TaskAmmFim task; + task.setID(taskNode.toElement().attribute("task_id").toInt()); + task.title = taskNode.toElement().attribute("title"); + task.status = taskNode.toElement().attribute("status"); + + for(int j = 0; j < taskNode.childNodes().count(); j++) + { + QDomNode malfOrReportNode = taskNode.childNodes().at(j); + if(malfOrReportNode.nodeName() == "malfunction") + {//Неисправность + Malfunction malfunction; + malfunction.num = malfOrReportNode.toElement().attribute("num"); + malfunction.dmCode = malfOrReportNode.toElement().attribute("dmCode"); + malfunction.description = malfOrReportNode.toElement().attribute("description"); + malfunction.goName = malfOrReportNode.toElement().attribute("goName"); + malfunction.objName = malfOrReportNode.toElement().attribute("objName"); + + for(int s = 0; s < malfOrReportNode.childNodes().count(); s++) + { + QDomNode signNode = malfOrReportNode.childNodes().at(s); + if(signNode.nodeName() == "malfunctionSign") + { + MalfunctionSign sign; + sign.type = signNode.toElement().attribute("type").toInt(); + sign.description = signNode.toElement().attribute("description"); + + malfunction.malfunctionSigns.append(sign); + } + } + + task.malfunctionList.append(malfunction); + } + else + if(malfOrReportNode.nodeName() == "report") + {//Отчет + FIMReport report; + report.id = malfOrReportNode.toElement().attribute("report_id").toInt(); + report.mmel = malfOrReportNode.toElement().attribute("mmel") == "true" ? true : false; + + for(int k = 0; k < malfOrReportNode.childNodes().count(); k++) + { + QDomNode reportItemNode = malfOrReportNode.childNodes().at(k); + if(reportItemNode.nodeName() == "reportItem") + { + FIMReportItem reportItem; + reportItem.id = reportItemNode.toElement().attribute("item_id").toInt(); + reportItem.text = reportItemNode.toElement().attribute("text"); + + if(reportItemNode.childNodes().count()) + { + QDomNode procedureIDNode = reportItemNode.childNodes().at(0); + reportItem.procedure.doc = procedureIDNode.toElement().attribute("doc"); + reportItem.procedure.title = procedureIDNode.toElement().attribute("title"); + reportItem.procedure.dmCode = procedureIDNode.toElement().attribute("dmCode"); + reportItem.procedure.result = procedureIDNode.toElement().attribute("result"); + } + + report.itemList.append(reportItem); + } + else if(reportItemNode.nodeName() == "reportWHItem") + { + FIMReportWarehouseItem reportWhItem; + reportWhItem.id = reportItemNode.toElement().attribute("wh_item_id").toInt(); + reportWhItem.status = reportItemNode.toElement().attribute("status").toInt(); + reportWhItem.goName = reportItemNode.toElement().attribute("goName"); + reportWhItem.objName = reportItemNode.toElement().attribute("objName"); + reportWhItem.code = reportItemNode.toElement().attribute("code"); + + report.warehouseItemList.append(reportWhItem); + } + } + + task.report = report; + } + } + + listTasks.append(task); + } + } + mapOfLists.insert(trainee_id, listTasks); + } + } + + emit sigAnswerQueryToDB_ListsTasksFIMofAllTrainees(mapOfLists); + } + break; }; } diff --git a/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.h b/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.h index d9b5b1b..0b78a68 100644 --- a/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.h +++ b/LibInstructorsAndTrainees/connectorToServer/Core/recognizesystem.h @@ -14,6 +14,7 @@ #include "Datas.h" #include "tasksAmmFim.h" #include "module.h" +#include "metatypes.h" class RecognizeSystem : public QObject @@ -53,6 +54,10 @@ signals: void sigAnswerQueryToDB_ListClassrooms(QList listClassrooms); void sigAnswerQueryToDB_ListTasksAMMforTrainee(QListlistTasks, int trainee_id); void sigAnswerQueryToDB_ListTasksFIMforTrainee(QListlistTasks, int trainee_id); + + void sigAnswerQueryToDB_ListsTasksAMMofAllTrainees(MapListsTasksAllTraineeType mapOfLists); + void sigAnswerQueryToDB_ListsTasksFIMofAllTrainees(MapListsTasksAllTraineeType mapOfLists); + void sigAnswerQueryTasksXML_FIM(QByteArray array); void sigAnswerQueryTasksXML_AMM(QByteArray array); void sigShowServerDataList(QList *versions); diff --git a/LibInstructorsAndTrainees/connectorToServer/Core/tcpclient.cpp b/LibInstructorsAndTrainees/connectorToServer/Core/tcpclient.cpp index 6328fe0..3513cb6 100644 --- a/LibInstructorsAndTrainees/connectorToServer/Core/tcpclient.cpp +++ b/LibInstructorsAndTrainees/connectorToServer/Core/tcpclient.cpp @@ -20,7 +20,7 @@ void TCPClient::initialize(RecognizeSystem *recognize,SendSystem *sendSystem) void TCPClient::setConnect(ServerSettings *serverSettings) { socket = new QTcpSocket(); - qDebug() << "TCPCLient thread: " << QThread::currentThreadId(); + qDebug() << "TCPCLient::setConnect thread ID " << QThread::currentThreadId(); if (socket != NULL && socket->state() == QTcpSocket::ConnectedState) { emit sigSendDebugLog("already connected"); diff --git a/LibInstructorsAndTrainees/connectorToServer/Core/tools.h b/LibInstructorsAndTrainees/connectorToServer/Core/tools.h index 25c1152..d42c8d5 100644 --- a/LibInstructorsAndTrainees/connectorToServer/Core/tools.h +++ b/LibInstructorsAndTrainees/connectorToServer/Core/tools.h @@ -53,6 +53,9 @@ enum PacketType{ TYPE_XMLANSWER_QUERY_TASKS_AMM_FOR_TRAINEE = 106, TYPE_XMLANSWER_QUERY_TASKS_FIM_FOR_TRAINEE = 107, + TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_ALL_TRAINEES = 108, + TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_ALL_TRAINEES = 109, + //xml-ответы на запросы AdditionalFiles TYPE_XMLANSWER_QUERY_TASKS_XML_FIM = 130, TYPE_XMLANSWER_QUERY_TASKS_XML_AMM = 131, diff --git a/LibInstructorsAndTrainees/connectorToServer/connectortoserver.cpp b/LibInstructorsAndTrainees/connectorToServer/connectortoserver.cpp index 7208aa4..b523283 100644 --- a/LibInstructorsAndTrainees/connectorToServer/connectortoserver.cpp +++ b/LibInstructorsAndTrainees/connectorToServer/connectortoserver.cpp @@ -17,14 +17,14 @@ ConnectorToServer::ConnectorToServer(QObject *parent) : ConnectorToServer::~ConnectorToServer() { + connectionThread->quit(); + connectionThread->wait(); + delete connectionThread; + delete client; delete recognizeSystem; delete sendSystem; delete dataParser; - - connectionThread->quit(); - connectionThread->wait(); - delete connectionThread; } ServerSettings ConnectorToServer::getServerSettings() @@ -41,7 +41,7 @@ void ConnectorToServer::SetConnectToServer() { serverBlockState = false; - qDebug() << "connectorToServer::SetConnectToServer() thread ID " << QThread::currentThreadId(); + qDebug() << "connectorToServer::SetConnectToServer thread ID " << QThread::currentThreadId(); serverSettings = *dataParser->getServerSettings(); emit sigSetConnect(dataParser->getServerSettings(),connectionThread); } @@ -167,6 +167,9 @@ void ConnectorToServer::bindConnection() connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListTasksAMMforTrainee,this,&ConnectorToServer::slot_AnswerQueryToDB_ListTasksAMMforTrainee); connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListTasksFIMforTrainee,this,&ConnectorToServer::slot_AnswerQueryToDB_ListTasksFIMforTrainee); + connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListsTasksAMMofAllTrainees,this,&ConnectorToServer::slot_AnswerQueryToDB_ListsTasksAMMofAllTrainees); + connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryToDB_ListsTasksFIMofAllTrainees,this,&ConnectorToServer::slot_AnswerQueryToDB_ListsTasksFIMofAllTrainees); + connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryTasksXML_FIM,this,&ConnectorToServer::slot_AnswerQueryTasksXML_FIM); connect(recognizeSystem,&RecognizeSystem::sigAnswerQueryTasksXML_AMM,this,&ConnectorToServer::slot_AnswerQueryTasksXML_AMM); @@ -199,6 +202,7 @@ void ConnectorToServer::createObjects() client->moveToThread(connectionThread); dataParser = new DataParser; + dataParser->moveToThread(connectionThread); sendSystem = new SendSystem; sendSystem->moveToThread(connectionThread); diff --git a/LibInstructorsAndTrainees/connectorToServer/connectortoserver.h b/LibInstructorsAndTrainees/connectorToServer/connectortoserver.h index d884ec9..6b2cb56 100644 --- a/LibInstructorsAndTrainees/connectorToServer/connectortoserver.h +++ b/LibInstructorsAndTrainees/connectorToServer/connectortoserver.h @@ -15,6 +15,7 @@ #include "classroom.h" #include "Datas.h" #include "streamingversiondata.h" +#include "metatypes.h" class ConnectorToServer : public QObject { @@ -97,6 +98,10 @@ public slots: void slot_AnswerQueryToDB_ListClassrooms(QList listClassrooms); void slot_AnswerQueryToDB_ListTasksAMMforTrainee(QList listTasks, int trainee_id); void slot_AnswerQueryToDB_ListTasksFIMforTrainee(QList listTasks, int trainee_id); + + void slot_AnswerQueryToDB_ListsTasksAMMofAllTrainees(MapListsTasksAllTraineeType mapOfLists); + void slot_AnswerQueryToDB_ListsTasksFIMofAllTrainees(MapListsTasksAllTraineeType mapOfLists); + void slot_AnswerQueryTasksXML_FIM(QByteArray array); void slot_AnswerQueryTasksXML_AMM(QByteArray array); void slot_AnswerQuerySubProc(QList listSubProc, QString parentTask_dmCode); diff --git a/LibInstructorsAndTrainees/connectorToServer/connectortoserver_AnswerQueryToDB.cpp b/LibInstructorsAndTrainees/connectorToServer/connectortoserver_AnswerQueryToDB.cpp index 1768373..2ed26de 100644 --- a/LibInstructorsAndTrainees/connectorToServer/connectortoserver_AnswerQueryToDB.cpp +++ b/LibInstructorsAndTrainees/connectorToServer/connectortoserver_AnswerQueryToDB.cpp @@ -95,6 +95,46 @@ void ConnectorToServer::slot_AnswerQueryToDB_ListTasksFIMforTrainee(QListsetUserLocalGUI_ID(serverAuth->Id.toInt()); + /* connectorToServer->sendQueryTasksXML("fim"); connectorToServer->sendQueryTasksXML("amm"); + */ viewerTrainees->activate(); viewerInstructors->activate(); - waitAnimationWidget->hideWithStop(); + //waitAnimationWidget->hideWithStop(); flTryLogin = false; } @@ -258,6 +266,8 @@ void InstructorsAndTraineesWidget::slot_checkLoginResult(ServerAuthorization *se { //waitAnimationWidget->hideWithStop(); //ui->btnAuthorizationInstructor->setChecked(false); + flTryReceiveFIM = false; + flTryReceiveAMM = false; } } @@ -300,6 +310,8 @@ void InstructorsAndTraineesWidget::slot_ServerBlocked() if(flTryLogin) { flTryLogin = false; + flTryReceiveFIM = false; + flTryReceiveAMM = false; waitAnimationWidget->hideWithStop(); ui->btnAuthorizationInstructor->setChecked(false); @@ -312,6 +324,8 @@ void InstructorsAndTraineesWidget::slot_ErrorAuth(QString error) if(flTryLogin) { flTryLogin = false; + flTryReceiveFIM = false; + flTryReceiveAMM = false; waitAnimationWidget->hideWithStop(); ui->btnAuthorizationInstructor->setChecked(false); @@ -441,6 +455,8 @@ void InstructorsAndTraineesWidget::slot_ConnectedToServer(bool state) updateLabelServer(); flTryLogin = false; + flTryReceiveFIM = false; + flTryReceiveAMM = false; } } @@ -501,6 +517,26 @@ void InstructorsAndTraineesWidget::slot_needShowWait(bool flNeed) waitAnimationWidget->hideWithStop(); } +void InstructorsAndTraineesWidget::slot_UpdateTasksAMM() +{ + if(flTryReceiveAMM) + { + flTryReceiveAMM = false; + if(!flTryReceiveAMM && !flTryReceiveFIM) + waitAnimationWidget->hideWithStop(); + } +} + +void InstructorsAndTraineesWidget::slot_UpdateTasksFIM() +{ + if(flTryReceiveFIM) + { + flTryReceiveFIM = false; + if(!flTryReceiveAMM && !flTryReceiveFIM) + waitAnimationWidget->hideWithStop(); + } +} + bool InstructorsAndTraineesWidget::authorizationInstructorDialog(QWidget* parent) { dlgAuthorization = new DialogAuthorization(parent); @@ -528,6 +564,8 @@ bool InstructorsAndTraineesWidget::authorizationInstructorDialog(QWidget* parent waitAnimationWidget->showWithPlay(); flTryLogin = true; + flTryReceiveFIM = true; + flTryReceiveAMM = true; connectorToServer->sendAuthorizationInstructorLocal(login, password); diff --git a/LibInstructorsAndTrainees/instructorsandtraineeswidget.h b/LibInstructorsAndTrainees/instructorsandtraineeswidget.h index c4520fa..9fb753f 100644 --- a/LibInstructorsAndTrainees/instructorsandtraineeswidget.h +++ b/LibInstructorsAndTrainees/instructorsandtraineeswidget.h @@ -72,6 +72,9 @@ public Q_SLOTS: void slot_needShowWait(bool flNeed); + void slot_UpdateTasksAMM(); + void slot_UpdateTasksFIM(); + Q_SIGNALS: //сигнал смены языка void signal_LanguageChanged(QString language); @@ -118,6 +121,8 @@ private: int cntTryConnectToServer; bool flTryLogin; + bool flTryReceiveFIM; + bool flTryReceiveAMM; QTranslator qtLanguageTranslator; QString language; diff --git a/LibInstructorsAndTrainees/metatypes.cpp b/LibInstructorsAndTrainees/metatypes.cpp index 453a61f..d2736ca 100644 --- a/LibInstructorsAndTrainees/metatypes.cpp +++ b/LibInstructorsAndTrainees/metatypes.cpp @@ -1,5 +1,6 @@ #include "metatypes.h" + void registerMetaType() { qRegisterMetaType>("QList"); @@ -9,9 +10,9 @@ void registerMetaType() qRegisterMetaType>("QList"); qRegisterMetaType>("QList"); qRegisterMetaType>("QList"); + qRegisterMetaType("MapListsTasksAllTraineeType"); qRegisterMetaType("PacketType"); qRegisterMetaType("ClientMessage"); qRegisterMetaType>("QList"); - qRegisterMetaType>("QList"); } diff --git a/LibInstructorsAndTrainees/metatypes.h b/LibInstructorsAndTrainees/metatypes.h index 68b7cd7..4334053 100644 --- a/LibInstructorsAndTrainees/metatypes.h +++ b/LibInstructorsAndTrainees/metatypes.h @@ -13,6 +13,8 @@ #include "tools.h" #include "Datas.h" +typedef QMap> MapListsTasksAllTraineeType; + void registerMetaType(); Q_DECLARE_METATYPE(QList) @@ -22,10 +24,10 @@ Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(MapListsTasksAllTraineeType) Q_DECLARE_METATYPE(PacketType) Q_DECLARE_METATYPE(ClientMessage) Q_DECLARE_METATYPE(QList) - Q_DECLARE_METATYPE(QList) #endif // METATYPES_H diff --git a/LibInstructorsAndTrainees/tasks/ammtaskswidget.cpp b/LibInstructorsAndTrainees/tasks/ammtaskswidget.cpp index 9faaa33..a5738ff 100644 --- a/LibInstructorsAndTrainees/tasks/ammtaskswidget.cpp +++ b/LibInstructorsAndTrainees/tasks/ammtaskswidget.cpp @@ -280,7 +280,7 @@ void AMMtasksWidget::slot_traineeSelected(int id_trainee) void AMMtasksWidget::slot_UpdateTasksAMMforTrainee(int trainee_id) { - qDebug() << "slot_UpdateTasksAMMforTrainee" << QThread::currentThreadId(); + qDebug() << "AMMtasksWidget::slot_UpdateTasksAMMforTrainee thread ID " << QThread::currentThreadId(); if(type == TypeListTreeAMMFIM::listForTrainee) { if(idTraineeSelected == trainee_id) diff --git a/LibInstructorsAndTrainees/tasks/fimtaskswidget.cpp b/LibInstructorsAndTrainees/tasks/fimtaskswidget.cpp index 8f7ec24..ab2e4ef 100644 --- a/LibInstructorsAndTrainees/tasks/fimtaskswidget.cpp +++ b/LibInstructorsAndTrainees/tasks/fimtaskswidget.cpp @@ -237,7 +237,7 @@ void FIMtasksWidget::slot_traineeSelected(int id_trainee) void FIMtasksWidget::slot_UpdateTasksFIMforTrainee(int trainee_id) { - qDebug() << "slot_UpdateTasksFIMforTrainee" << QThread::currentThreadId(); + qDebug() << "FIMtasksWidget::slot_UpdateTasksFIMforTrainee thread ID " << QThread::currentThreadId(); if(type == TypeListTreeAMMFIM::listForTrainee) { if(idTraineeSelected == trainee_id) diff --git a/LibInstructorsAndTrainees/trainees/personalcardtrainee.cpp b/LibInstructorsAndTrainees/trainees/personalcardtrainee.cpp index 4b254af..77b2997 100644 --- a/LibInstructorsAndTrainees/trainees/personalcardtrainee.cpp +++ b/LibInstructorsAndTrainees/trainees/personalcardtrainee.cpp @@ -134,6 +134,20 @@ void PersonalCardTrainee::slot_NeedUpdateUI(bool treeInstructor, bool treeTraine { if(treeTrainee) { + Trainee trainee = connectorToServer->getTrainee(id_trainee); + if(!trainee.getID()) + {//Обучаемый удален + SpecMsgBox::WarningClose(this, tr("The trainee was removed!")); + this->parentWidget()->close(); + return; + } + else if(trainee.getArchived()) + {//Обучаемый заархивирован + SpecMsgBox::WarningClose(this, tr("The trainee was archived!")); + this->parentWidget()->close(); + return; + } + loadInfo(); } } diff --git a/LibServer/Data/PacketType.h b/LibServer/Data/PacketType.h index 93906b7..a7ba524 100644 --- a/LibServer/Data/PacketType.h +++ b/LibServer/Data/PacketType.h @@ -37,6 +37,9 @@ enum PacketType TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE = 106, TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE = 107, + TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_ALL_TRAINEES = 108, + TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_ALL_TRAINEES = 109, + //xml-ответы на запросы AdditionalFiles TYPE_XMLANSWER_QUERY_TASKS_XML_FIM = 130, TYPE_XMLANSWER_QUERY_TASKS_XML_AMM = 131, diff --git a/LibServer/Server.qrc b/LibServer/Server.qrc index 26a6445..3600f34 100644 --- a/LibServer/Server.qrc +++ b/LibServer/Server.qrc @@ -19,5 +19,7 @@ resources/icons/save.png resources/icons/stoped.png resources/blankXML/ListCFI.xml + resources/blankXML/ListsTasksAMMofAllTrainees.xml + resources/blankXML/ListsTasksFIMofAllTrainees.xml diff --git a/LibServer/Systems/Parsers/clientanswerparser.h b/LibServer/Systems/Parsers/clientanswerparser.h index 81ed702..9aaddca 100644 --- a/LibServer/Systems/Parsers/clientanswerparser.h +++ b/LibServer/Systems/Parsers/clientanswerparser.h @@ -6,6 +6,7 @@ #include #include +class DataParser; class ClientAnswerParser : public QObject { diff --git a/LibServer/Systems/Parsers/dataparser.cpp b/LibServer/Systems/Parsers/dataparser.cpp index 5363f04..b0a6f4f 100644 --- a/LibServer/Systems/Parsers/dataparser.cpp +++ b/LibServer/Systems/Parsers/dataparser.cpp @@ -3,11 +3,12 @@ #include #include -DataParser::DataParser(AssetsManager *assetManager,ProcessingSystem *processingSystem,QObject *parent) : +DataParser::DataParser(ProcessingSystem *processingSystem,QObject *parent) : QObject(parent) { + qDebug() << "DataParser init thread ID " << QThread::currentThreadId(); + this->processingSystem = processingSystem; - this->assetsManager = assetManager; clientAnswer = new ClientAnswerParser; clientAnswer->initialize(this); @@ -21,8 +22,6 @@ QObject(parent) processParser->initialize(processingSystem); mutex = new QMutex; - - qDebug() << "ParserThread: " << QThread::currentThreadId(); } diff --git a/LibServer/Systems/Parsers/dataparser.h b/LibServer/Systems/Parsers/dataparser.h index 31f8069..8903c57 100644 --- a/LibServer/Systems/Parsers/dataparser.h +++ b/LibServer/Systems/Parsers/dataparser.h @@ -3,7 +3,6 @@ #include "Systems/processingsystem.h" #include "Systems/tools.h" -#include "Systems/assetsmanager.h" #include "Systems/logger.h" #include "Systems/Parsers/clientanswerparser.h" #include "dbanswerparser.h" @@ -21,7 +20,6 @@ class ProcessingSystem; class ClientHandler; -class AssetsManager; class ClientAnswerParser; class DBAnswerParser; class DocsAnswerParser; @@ -32,7 +30,7 @@ class DataParser : public QObject Q_OBJECT public: - DataParser(AssetsManager *assetManager,ProcessingSystem *processingSystem,QObject* parent = nullptr); + DataParser(ProcessingSystem *processingSystem,QObject* parent = nullptr); void xmlParser(ClientHandler *client, QByteArray array); void xmlFileDataParse(QByteArray array); @@ -53,7 +51,6 @@ private: QMutex *mutex; ProcessingSystem *processingSystem; - AssetsManager *assetsManager; ClientAnswerParser *clientAnswer; DBAnswerParser *dbAnswer; DocsAnswerParser* docsAnswer; diff --git a/LibServer/Systems/Parsers/dbanswerparser.cpp b/LibServer/Systems/Parsers/dbanswerparser.cpp index f730150..210eb4d 100644 --- a/LibServer/Systems/Parsers/dbanswerparser.cpp +++ b/LibServer/Systems/Parsers/dbanswerparser.cpp @@ -261,3 +261,136 @@ QByteArray DBAnswerParser::listTasksFIMofTrainee(bool result, QList return commonDOM.toByteArray(); } + +QByteArray DBAnswerParser::listsTasksAMMofAllTrainees(QMap > *mapOfLists) +{ + QDomDocument commonDOM; + if(! Tools::loadFileXMLtoDOM(":/resources/blankXML/ListsTasksAMMofAllTrainees.xml", &commonDOM)) + return QByteArray(); + + QDomNode listsAllNode = commonDOM.namedItem("ListsTasksAMMofAllTrainees"); + + for(int key : mapOfLists->keys()) + { + QList listOne = mapOfLists->value(key); + + QDomNode listOneNode = commonDOM.createElement("ListTasksAMM"); + listsAllNode.appendChild(listOneNode); + + listOneNode.toElement().setAttribute("trainee_id", QString::number(key)); + + for(TaskAmmFim task : listOne) + { + //Задача + QDomNode taskNode = commonDOM.createElement("taskAMM"); + listOneNode.appendChild(taskNode); + taskNode.toElement().setAttribute("task_id", QString::number(task.getID())); + taskNode.toElement().setAttribute("title", task.ammProcedure.title); + taskNode.toElement().setAttribute("dmCode", task.ammProcedure.dmCode); + taskNode.toElement().setAttribute("status", task.status); + + for(SubProc subProc : task.listSubProc) + {//Подпроцедура + QDomNode subProcNode = commonDOM.createElement("SubProc"); + taskNode.appendChild(subProcNode); + + subProcNode.toElement().setAttribute("dmCode", subProc.getDmCode()); + subProcNode.toElement().setAttribute("title", subProc.getTitle()); + subProcNode.toElement().setAttribute("canplay", subProc.getModeListStr()); + } + } + } + + Tools::saveDOMtoFileXML("ListsTasksAMMofAllTrainees.xml", &commonDOM); + + return commonDOM.toByteArray(); +} + +QByteArray DBAnswerParser::listsTasksFIMofAllTrainees(QMap > *mapOfLists) +{ + QDomDocument commonDOM; + if(! Tools::loadFileXMLtoDOM(":/resources/blankXML/ListsTasksFIMofAllTrainees.xml", &commonDOM)) + return QByteArray(); + + QDomNode listsAllNode = commonDOM.namedItem("ListsTasksFIMofAllTrainees"); + + for(int key : mapOfLists->keys()) + { + QList listOne = mapOfLists->value(key); + + QDomNode listOneNode = commonDOM.createElement("ListTasksFIM"); + listsAllNode.appendChild(listOneNode); + + listOneNode.toElement().setAttribute("trainee_id", QString::number(key)); + + for(TaskAmmFim task : listOne) + { + //Задача + QDomNode taskNode = commonDOM.createElement("taskFIM"); + listOneNode.appendChild(taskNode); + taskNode.toElement().setAttribute("task_id", QString::number(task.getID())); + taskNode.toElement().setAttribute("title", task.title); + taskNode.toElement().setAttribute("status", task.status); + + for(Malfunction malfunction : task.malfunctionList) + {//Неисправность + QDomNode malfunctionNode = commonDOM.createElement("malfunction"); + taskNode.appendChild(malfunctionNode); + malfunctionNode.toElement().setAttribute("dmCode", malfunction.dmCode); + malfunctionNode.toElement().setAttribute("num", malfunction.num); + malfunctionNode.toElement().setAttribute("description", malfunction.description); + malfunctionNode.toElement().setAttribute("goName", malfunction.goName); + malfunctionNode.toElement().setAttribute("objName", malfunction.objName); + + for(MalfunctionSign sign : malfunction.malfunctionSigns) + {//Сигналы + QDomNode signNode = commonDOM.createElement("malfunctionSign"); + malfunctionNode.appendChild(signNode); + signNode.toElement().setAttribute("type", sign.type); + signNode.toElement().setAttribute("description", sign.description); + } + } + + + {//FIMReport + FIMReport report = task.report; + QDomNode reportNode = commonDOM.createElement("report"); + taskNode.appendChild(reportNode); + reportNode.toElement().setAttribute("report_id", report.id); + reportNode.toElement().setAttribute("mmel", report.mmel ? "true" : "false"); + + for(FIMReportItem reportItem : task.report.itemList) + {//FIMReportItem + QDomNode reportItemNode = commonDOM.createElement("reportItem"); + reportNode.appendChild(reportItemNode); + reportItemNode.toElement().setAttribute("item_id", reportItem.id); + reportItemNode.toElement().setAttribute("text", reportItem.text); + + //ProcedureID + QDomNode procedureIDNode = commonDOM.createElement("procedureID"); + reportItemNode.appendChild(procedureIDNode); + + procedureIDNode.toElement().setAttribute("doc", reportItem.procedure.doc); + procedureIDNode.toElement().setAttribute("title", reportItem.procedure.title); + procedureIDNode.toElement().setAttribute("dmCode", reportItem.procedure.dmCode); + procedureIDNode.toElement().setAttribute("result", reportItem.procedure.result); + } + + for(FIMReportWarehouseItem reportWhItem : task.report.warehouseItemList) + {//FIMReportWarehouseItem + QDomNode reportWhItemNode = commonDOM.createElement("reportWHItem"); + reportNode.appendChild(reportWhItemNode); + reportWhItemNode.toElement().setAttribute("wh_item_id", reportWhItem.id); + reportWhItemNode.toElement().setAttribute("status", reportWhItem.status); + reportWhItemNode.toElement().setAttribute("goName", reportWhItem.goName); + reportWhItemNode.toElement().setAttribute("objName", reportWhItem.objName); + reportWhItemNode.toElement().setAttribute("code", reportWhItem.code); + } + } + } + } + + Tools::saveDOMtoFileXML("ListsTasksFIMofAllTrainees.xml", &commonDOM); + + return commonDOM.toByteArray(); +} diff --git a/LibServer/Systems/Parsers/dbanswerparser.h b/LibServer/Systems/Parsers/dbanswerparser.h index 801535c..4e5f2c4 100644 --- a/LibServer/Systems/Parsers/dbanswerparser.h +++ b/LibServer/Systems/Parsers/dbanswerparser.h @@ -23,6 +23,9 @@ public: QByteArray listTasksAMMofTrainee(bool result, QList *listTasks, int trainee_id, bool full_list); QByteArray listTasksFIMofTrainee(bool result, QList *listTasks, int trainee_id, bool full_list); + + QByteArray listsTasksAMMofAllTrainees(QMap > *mapOfLists); + QByteArray listsTasksFIMofAllTrainees(QMap > *mapOfLists); signals: private: diff --git a/LibServer/Systems/assetsmanager.cpp b/LibServer/Systems/assetsmanager.cpp index ca5afba..47f04fd 100644 --- a/LibServer/Systems/assetsmanager.cpp +++ b/LibServer/Systems/assetsmanager.cpp @@ -1,12 +1,16 @@ +#include +#include #include "assetsmanager.h" AssetsManager::AssetsManager(QObject *parent) : QObject(parent) { - + qDebug() << "AssetsManager init thread ID " << QThread::currentThreadId(); } -void AssetsManager::initialize(UpdateController* updateContoller,DataParser *dataParser) +void AssetsManager::initialize(UpdateController* updateContoller) { + qDebug() << "AssetsManager::initialize thread ID " << QThread::currentThreadId(); + this->updateController = updateContoller; //connect(this,&AssetsManager::sigSaveVersion,updateContoller,&UpdateController::saveVersionToFile); datas = new QList; @@ -110,6 +114,8 @@ QString AssetsManager::setVersion(QString versionName) currentVersionData = version; saveVersionToFile(currentVersionData); + Logger::instance().log("Set Version of materials: " + versionName); + emit signal_setVersion(versionName); return version->getAbsolutPath(); @@ -172,7 +178,7 @@ void AssetsManager::addVersion(StreamingVersionData *data) void AssetsManager::createCopyVersion(QString versionName,QString newVersionName,QString author) { - qDebug() << "assetManager thread ID " << QThread::currentThreadId(); + qDebug() << "AssetsManager::createCopyVersion thread ID " << QThread::currentThreadId(); StreamingVersionData* data = new StreamingVersionData; data->setAbsolutePath(Tools::createSharedPath("/" + newVersionName)); diff --git a/LibServer/Systems/assetsmanager.h b/LibServer/Systems/assetsmanager.h index f64dfe0..7aeab2c 100644 --- a/LibServer/Systems/assetsmanager.h +++ b/LibServer/Systems/assetsmanager.h @@ -5,13 +5,14 @@ #include #include +class UpdateController; class AssetsManager : public QObject { Q_OBJECT public: explicit AssetsManager(QObject *parent = nullptr); - void initialize(UpdateController* updateContoller,DataParser *dataParser); + void initialize(UpdateController* updateContoller); void addVersion(StreamingVersionData *data); void createCopyVersion(QString versionName,QString newName,QString author); void deleteVersion(QString version); diff --git a/LibServer/Systems/chatsystem.cpp b/LibServer/Systems/chatsystem.cpp index 315d1f7..81f7cac 100644 --- a/LibServer/Systems/chatsystem.cpp +++ b/LibServer/Systems/chatsystem.cpp @@ -2,11 +2,13 @@ ChatSystem::ChatSystem() { - + qDebug() << "ChatSystem init thread ID " << QThread::currentThreadId(); } void ChatSystem::initialize(CommonClientHandler *commonClientHandler, DataParser *dataParser, QMap *clientsMap) { + qDebug() << "ChatSystem::initialize thread ID " << QThread::currentThreadId(); + this->commonClientHandler = commonClientHandler; this->dataParser = dataParser; this->clientsMap = clientsMap; diff --git a/LibServer/Systems/chatsystem.h b/LibServer/Systems/chatsystem.h index 07b3074..88aec7b 100644 --- a/LibServer/Systems/chatsystem.h +++ b/LibServer/Systems/chatsystem.h @@ -5,6 +5,8 @@ #include #include +class CommonClientHandler; + class ChatSystem : public QObject { Q_OBJECT diff --git a/LibServer/Systems/commonclienthandler.cpp b/LibServer/Systems/commonclienthandler.cpp index fb4b93c..3b30420 100644 --- a/LibServer/Systems/commonclienthandler.cpp +++ b/LibServer/Systems/commonclienthandler.cpp @@ -2,11 +2,13 @@ CommonClientHandler::CommonClientHandler(QObject *parent) : QObject(parent) { - + qDebug() << "CommonClientHandler init thread ID " << QThread::currentThreadId(); } void CommonClientHandler::initialize(QMap *clientsMap, ProcessingSystem *processingSystem, DataParser *dataParser) { + qDebug() << "CommonClientHandler::initialize thread ID " << QThread::currentThreadId(); + this->clientsMap = clientsMap; this->processingSystem = processingSystem; this->dataParser = dataParser; @@ -36,7 +38,32 @@ void CommonClientHandler::sendCurrentVersionToAllClient() } } -void CommonClientHandler::slot_ListsInstructorsTraineesChanged() +void CommonClientHandler::slot_ListsInstructorsTraineesChanged_forUserID(int id_user) +{ + //Проходим все открытые сокеты + foreach(int idSocket, clientsMap->keys()) + { + ClientHandler *handler = clientsMap->value(idSocket); + //Проверяем, есть ли клиенты TYPE_GUI с нужным ID + if(handler->getClient()->getTypeClient() == TypeClientAutorization::TYPE_GUI && + handler->getClient()->getId() == QString::number(id_user)) + {//Отправляем этому клиенту обновление списков + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_ALL_LISTS; + processingSystem->processingClientQueryToDB(handler, queryToDB); + } + + /* + if(handler->getClient()->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT) + { + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_CONTACT_LIST; + processingSystem->processingClientQueryToDB(handler, queryToDB); + }*/ + } +} + +void CommonClientHandler::slot_ListInstructorsChanged() { //Проходим все открытые сокеты foreach(int idSocket, clientsMap->keys()) @@ -46,7 +73,53 @@ void CommonClientHandler::slot_ListsInstructorsTraineesChanged() if(handler->getClient()->getTypeClient() == TypeClientAutorization::TYPE_GUI) {//Отправляем этому клиенту обновление списков ClientQueryToDB queryToDB; - queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_ALL_LISTS; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_ALL_INSTRUCTORS; + processingSystem->processingClientQueryToDB(handler, queryToDB); + } + + if(handler->getClient()->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT) + { + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_CONTACT_LIST; + processingSystem->processingClientQueryToDB(handler, queryToDB); + } + } +} + +void CommonClientHandler::slot_ListTraineesChanged() +{ + //Проходим все открытые сокеты + foreach(int idSocket, clientsMap->keys()) + { + ClientHandler *handler = clientsMap->value(idSocket); + //Проверяем, есть ли клиенты TYPE_GUI + if(handler->getClient()->getTypeClient() == TypeClientAutorization::TYPE_GUI) + {//Отправляем этому клиенту обновление списков + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_ALL_TRAINEES; + processingSystem->processingClientQueryToDB(handler, queryToDB); + } + + if(handler->getClient()->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT) + { + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_CONTACT_LIST; + processingSystem->processingClientQueryToDB(handler, queryToDB); + } + } +} + +void CommonClientHandler::slot_ListGroupsChanged() +{ + //Проходим все открытые сокеты + foreach(int idSocket, clientsMap->keys()) + { + ClientHandler *handler = clientsMap->value(idSocket); + //Проверяем, есть ли клиенты TYPE_GUI + if(handler->getClient()->getTypeClient() == TypeClientAutorization::TYPE_GUI) + {//Отправляем этому клиенту обновление списков + ClientQueryToDB queryToDB; + queryToDB.typeQuery = TypeQueryToDB::TYPE_QUERY_GET_ALL_GROUPS; processingSystem->processingClientQueryToDB(handler, queryToDB); } diff --git a/LibServer/Systems/commonclienthandler.h b/LibServer/Systems/commonclienthandler.h index e32be8b..08321da 100644 --- a/LibServer/Systems/commonclienthandler.h +++ b/LibServer/Systems/commonclienthandler.h @@ -6,6 +6,7 @@ class ProcessingSystem; class DataParser; +class ClientHandler; class Logger; class CommonClientHandler : public QObject @@ -19,7 +20,10 @@ public: void sendNewVersionListToAllClient(); void sendCurrentVersionToAllClient(); - void slot_ListsInstructorsTraineesChanged(); + void slot_ListsInstructorsTraineesChanged_forUserID(int id_user); + void slot_ListInstructorsChanged(); + void slot_ListTraineesChanged(); + void slot_ListGroupsChanged(); void slot_StatusTasksAMMofTraineeChanged(int trainee_id); void slot_StatusTasksFIMofTraineeChanged(int trainee_id); diff --git a/LibServer/Systems/docsupdater.cpp b/LibServer/Systems/docsupdater.cpp index d3b002a..ea56f53 100644 --- a/LibServer/Systems/docsupdater.cpp +++ b/LibServer/Systems/docsupdater.cpp @@ -8,7 +8,7 @@ DocsUpdater::DocsUpdater(UpdateController* updateController, QObject *parent): updateController(updateController), flagStop(false) { - + qDebug() << "DocsUpdater init thread ID " << QThread::currentThreadId(); } DocsUpdater::~DocsUpdater() @@ -37,8 +37,10 @@ QList DocsUpdater::getListSubProcForDMcode(QString dmCode) return listSubProcMap.value(dmCode); } -bool DocsUpdater::updateDocsXML() +bool DocsUpdater::slot_updateDocsXML() { + qDebug() << "DocsUpdater::slot_updateDocsXML thread ID " << QThread::currentThreadId(); + QMutexLocker locker(&mtxAccess); QString pathDocsFile = updateController->getPathAdditionalFile(tasksAMMfileName); @@ -97,6 +99,8 @@ bool DocsUpdater::updateDocsXML() } } + emit signal_DocsChanged(); + emit signal_UpdateDocsCompleted(); return true; } diff --git a/LibServer/Systems/docsupdater.h b/LibServer/Systems/docsupdater.h index 1920bcc..401eac2 100644 --- a/LibServer/Systems/docsupdater.h +++ b/LibServer/Systems/docsupdater.h @@ -16,9 +16,10 @@ public: void lockAccessToDocsXML(); void unLockAccessToDocsXML(); - QList getListSubProcForDMcode(QString dmCode); + QList getListSubProcForDMcode(QString dmCode); - bool updateDocsXML(); +public slots: + bool slot_updateDocsXML(); private: void domElementParserAMM(QDomElement element, Module* moduleParent); @@ -27,6 +28,10 @@ private: void selectSubProc(QDomElement& modeElement, QList& listSubProc); DM* getDMmoduleByDMcode(QString dmCode); +signals: + void signal_DocsChanged(); + void signal_UpdateDocsCompleted(); + private: UpdateController* updateController; diff --git a/LibServer/Systems/processingsystem.cpp b/LibServer/Systems/processingsystem.cpp index 4a3a084..a49f8cf 100644 --- a/LibServer/Systems/processingsystem.cpp +++ b/LibServer/Systems/processingsystem.cpp @@ -2,6 +2,7 @@ #include "providerdblms.h" #include +#include ProcessingSystem::ProcessingSystem(ProviderDBLMS* providerDBLMS, UpdateController* updateController, DocsUpdater* docsUpdater, CfiController* cfiController, QObject *parent): QObject(parent), @@ -10,6 +11,8 @@ ProcessingSystem::ProcessingSystem(ProviderDBLMS* providerDBLMS, UpdateControlle cfiController(nullptr), providerDBLMS(nullptr) { + qDebug() << "ProcessingSystem init thread ID " << QThread::currentThreadId(); + this->providerDBLMS = providerDBLMS; this->updateController = updateController; this->docsUpdater = docsUpdater; @@ -21,13 +24,18 @@ void ProcessingSystem::initialize(MultiThreadServer *server, DataParser *dataPar UpdateController *updateController, ChatSystem *chatSystem) { + qDebug() << "ProcessingSystem::initialize thread ID " << QThread::currentThreadId(); + this->commonClientServer = commonClientHandler; this->dataParser = dataParser; this->server = server; this->updateController = updateController; this->chatSystem = chatSystem; - connect(this,&ProcessingSystem::sigListsInstructorsTraineesChanged,commonClientHandler, &CommonClientHandler::slot_ListsInstructorsTraineesChanged,Qt::AutoConnection); + connect(this,&ProcessingSystem::sigListsInstructorsTraineesChanged_forUserID,commonClientHandler, &CommonClientHandler::slot_ListsInstructorsTraineesChanged_forUserID,Qt::AutoConnection); + connect(this,&ProcessingSystem::sigListInstructorsChanged,commonClientHandler, &CommonClientHandler::slot_ListInstructorsChanged,Qt::AutoConnection); + connect(this,&ProcessingSystem::sigListTraineesChanged,commonClientHandler, &CommonClientHandler::slot_ListTraineesChanged,Qt::AutoConnection); + connect(this,&ProcessingSystem::sigListGroupsChanged,commonClientHandler, &CommonClientHandler::slot_ListGroupsChanged,Qt::AutoConnection); connect(this,&ProcessingSystem::sigStatusTasksAMMofTraineeChanged,commonClientHandler, &CommonClientHandler::slot_StatusTasksAMMofTraineeChanged,Qt::AutoConnection); connect(this,&ProcessingSystem::sigStatusTasksFIMofTraineeChanged,commonClientHandler, &CommonClientHandler::slot_StatusTasksFIMofTraineeChanged,Qt::AutoConnection); @@ -98,6 +106,18 @@ void ProcessingSystem::processingClientAutorization(ClientHandler *client, Clien { client->sendVersion(); + + if(clientAutorization.TypeClient == TypeClientAutorization::TYPE_GUI) + {//Отправляем этому клиенту обновление ВСЕХ списков + emit sigListsInstructorsTraineesChanged_forUserID(clientID); + + ClientQueryTasksXML clientQueryTasksXML; + clientQueryTasksXML.Type = "fim"; + processingClientQueryTasksXML(client, clientQueryTasksXML); + clientQueryTasksXML.Type = "amm"; + processingClientQueryTasksXML(client, clientQueryTasksXML); + } + //Отправляем состояние блокировки /* if(server->getStateBlockAutorization() == EStateBlockAutorization::blocked) @@ -110,7 +130,13 @@ void ProcessingSystem::processingClientAutorization(ClientHandler *client, Clien //client->sendPacketType(PacketType::FREE); //Извещаем об изменениях в авторизации - emit sigListsInstructorsTraineesChanged(); + if(client->getClient()->getAccessType() == UserType::INSTRUCTOR) + { + //emit sigListGroupsChanged(); + emit sigListInstructorsChanged(); + } + else if(client->getClient()->getAccessType() == UserType::TRAINEE) + emit sigListTraineesChanged(); } else { @@ -169,7 +195,7 @@ void ProcessingSystem::processingClientDeAutorization(ClientHandler *client, Cli client->sendXmlAnswer(arrayAnswer); //Извещаем об изменениях в авторизации - emit sigListsInstructorsTraineesChanged(); + emit sigListTraineesChanged(); } else if(providerDBLMS->deAuthorizationInstructor(clientDeAutorization.Login)) {//ДеАвторизуется инструктор @@ -187,7 +213,7 @@ void ProcessingSystem::processingClientDeAutorization(ClientHandler *client, Cli providerDBLMS->signal_BlockAutorization(false, fullName, "DeAuthorizationInstructor"); //Извещаем об изменениях в авторизации - emit sigListsInstructorsTraineesChanged(); + emit sigListInstructorsChanged(); } else {//Никто не ДеАвторизовался @@ -277,7 +303,7 @@ void ProcessingSystem::processingExitUnityClient(ClientHandler *client) void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQueryToDB clientQueryToDB, int id, void* data) { - qDebug() << "ProcessingQueryThread " << QThread::currentThreadId(); + qDebug() << "ProcessingSystem::processingClientQueryToDB thread ID " << QThread::currentThreadId(); switch (clientQueryToDB.typeQuery) { @@ -301,16 +327,53 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu //client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_TRAINEES); client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_TRAINEES); - for(Trainee trainee : listTrainees) + if(listTrainees.count()) { - //Отправка списка задач AMM этого обучаемого клиенту GUI - sendListTasksAMMofTraineetoClient(client, trainee.getID()); - //Отправка списка задач FIM этого обучаемого клиенту GUI - sendListTasksFIMofTraineetoClient(client, trainee.getID()); + //Отправка списка задач FIM всех обучаемых клиенту GUI + sendListsTasksFIMofAllTraineestoClient(client, listTrainees); + //Отправка списка задач AMM всех обучаемых клиенту GUI + sendListsTasksAMMofAllTraineestoClient(client, listTrainees); } break; } + case TypeQueryToDB::TYPE_QUERY_GET_ALL_INSTRUCTORS: + { + QList listInstructors = providerDBLMS->GetListAllInstructors(); + + QByteArray arrayAnswer; + + arrayAnswer = dataParser->DbAnswer()->listInstructors(true, &listInstructors); + //client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_INSTRUCTORS); + client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_INSTRUCTORS); + + break; + } + case TypeQueryToDB::TYPE_QUERY_GET_ALL_TRAINEES: + { + QList listTrainees = providerDBLMS->GetListAllTrainees(); + + QByteArray arrayAnswer; + + arrayAnswer = dataParser->DbAnswer()->listTrainees(true, &listTrainees); + //client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_TRAINEES); + client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_TRAINEES); + + break; + } + case TypeQueryToDB::TYPE_QUERY_GET_ALL_GROUPS: + { + QList listGroups = providerDBLMS->GetListAllGroups(); + + QByteArray arrayAnswer; + + arrayAnswer = dataParser->DbAnswer()->listGroups(true, &listGroups); + //client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_GROUPS); + client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_DB__LIST_GROUPS); + + break; + } + case TypeQueryToDB::TYPE_QUERY_NEW_INSTRUCTOR: { int id_new; @@ -320,19 +383,19 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu (*(Instructor*)data).setID(id_new); providerDBLMS->editInstructor(*(Instructor*)data); } - emit sigListsInstructorsTraineesChanged(); + emit sigListInstructorsChanged(); break; } case TypeQueryToDB::TYPE_QUERY_DEL_INSTRUCTOR: { providerDBLMS->delInstructor(id); - emit sigListsInstructorsTraineesChanged(); + emit sigListInstructorsChanged(); break; } case TypeQueryToDB::TYPE_QUERY_EDIT_INSTRUCTOR: { providerDBLMS->editInstructor(*(Instructor*)data); - emit sigListsInstructorsTraineesChanged(); + emit sigListInstructorsChanged(); break; } @@ -345,19 +408,19 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu (*(Trainee*)data).setID(id_new); providerDBLMS->editTrainee(*(Trainee*)data); } - emit sigListsInstructorsTraineesChanged(); + emit sigListTraineesChanged(); break; } case TypeQueryToDB::TYPE_QUERY_DEL_TRAINEE: { providerDBLMS->delTrainee(id); - emit sigListsInstructorsTraineesChanged(); + emit sigListTraineesChanged(); break; } case TypeQueryToDB::TYPE_QUERY_EDIT_TRAINEE: { providerDBLMS->editTrainee(*(Trainee*)data); - emit sigListsInstructorsTraineesChanged(); + emit sigListTraineesChanged(); break; } @@ -370,19 +433,19 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu (*(Group*)data).setID(id_new); providerDBLMS->editGroup(*(Group*)data); } - emit sigListsInstructorsTraineesChanged(); + emit sigListGroupsChanged(); break; } case TypeQueryToDB::TYPE_QUERY_DEL_GROUP: { providerDBLMS->delGroup(id); - emit sigListsInstructorsTraineesChanged(); + emit sigListGroupsChanged(); break; } case TypeQueryToDB::TYPE_QUERY_EDIT_GROUP: { providerDBLMS->editGroup(*(Group*)data); - emit sigListsInstructorsTraineesChanged(); + emit sigListGroupsChanged(); break; } @@ -637,8 +700,6 @@ void ProcessingSystem::processingClientNotify(ClientHandler *client, ClientNotif } else if(clientNotify.Code == commandDisableClient) { - qDebug() << "processing thread: " << QThread::currentThreadId(); - //Фиксируем время выхода Юнити-клиента if (clientData->getClientType() == TypeClientAutorization::TYPE_UNITY_CLIENT) { @@ -697,6 +758,36 @@ void ProcessingSystem::sendListTasksFIMofTraineetoClient(ClientHandler *client, client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE); } +void ProcessingSystem::sendListsTasksAMMofAllTraineestoClient(ClientHandler *client, QList listTrainees) +{ + QMap> mapOfLists; + for(Trainee trainee : listTrainees) + { + int id_trainee = trainee.getID(); + QList listTasksOneTrainee = providerDBLMS->GetListTasksAMMofTrainee(id_trainee); + if(listTasksOneTrainee.count()) + mapOfLists.insert(id_trainee, listTasksOneTrainee); + } + + QByteArray arrayAnswer = dataParser->DbAnswer()->listsTasksAMMofAllTrainees(&mapOfLists); + client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_ALL_TRAINEES); +} + +void ProcessingSystem::sendListsTasksFIMofAllTraineestoClient(ClientHandler *client, QList listTrainees) +{ + QMap> mapOfLists; + for(Trainee trainee : listTrainees) + { + int id_trainee = trainee.getID(); + QList listTasksOneTrainee = providerDBLMS->GetListTasksFIMofTrainee(id_trainee); + if(listTasksOneTrainee.count()) + mapOfLists.insert(id_trainee, listTasksOneTrainee); + } + + QByteArray arrayAnswer = dataParser->DbAnswer()->listsTasksFIMofAllTrainees(&mapOfLists); + client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_ALL_TRAINEES); +} + void ProcessingSystem::sendListTasksAMMofTraineeByIDtoClient(ClientHandler *client, int id_trainee, QList listID) { QList listTasksNeed; diff --git a/LibServer/Systems/processingsystem.h b/LibServer/Systems/processingsystem.h index 65e1ace..39337f5 100644 --- a/LibServer/Systems/processingsystem.h +++ b/LibServer/Systems/processingsystem.h @@ -5,7 +5,6 @@ #include #include -#include #include "multithreadserver.h" //#include "instructorsandtraineeswidget.h" #include "chatsystem.h" @@ -22,6 +21,7 @@ class ClientHandler; class CommonClientHandler; class MultiThreadServer; class CfiController; +class ChatSystem; class ProcessingSystem : public QObject { @@ -50,6 +50,10 @@ public: void sendListTasksAMMofTraineetoClient(ClientHandler* client, int id_trainee); void sendListTasksFIMofTraineetoClient(ClientHandler* client, int id_trainee); + void sendListsTasksAMMofAllTraineestoClient(ClientHandler *client, QList listTrainees); + void sendListsTasksFIMofAllTraineestoClient(ClientHandler* client, QList listTrainees); + + void sendListTasksAMMofTraineeByIDtoClient(ClientHandler* client, int id_trainee, QList listID); void sendListTasksFIMofTraineeByIDtoClient(ClientHandler* client, int id_trainee, QList listID); @@ -65,7 +69,10 @@ public: void processingExitUnityClient(ClientHandler *client); signals: void sigUpdateListClients(); - void sigListsInstructorsTraineesChanged(); + void sigListsInstructorsTraineesChanged_forUserID(int id_user); + void sigListInstructorsChanged(); + void sigListTraineesChanged(); + void sigListGroupsChanged(); void sigStatusTasksAMMofTraineeChanged(int trainee_id); void sigStatusTasksFIMofTraineeChanged(int trainee_id); void sigAddToMessanger(QString login,QString text); diff --git a/LibServer/Systems/recognizesystem.cpp b/LibServer/Systems/recognizesystem.cpp index c864b91..2f1ee30 100644 --- a/LibServer/Systems/recognizesystem.cpp +++ b/LibServer/Systems/recognizesystem.cpp @@ -13,12 +13,12 @@ QObject(parent) } -void RecognizeSystem::initialize(UpdateController *updateController,DataParser* dataParser, - ServerLMSWidget *server,SendSystem *sendSystem, ClientHandler *handler) +void RecognizeSystem::initialize(UpdateController *updateController,DataParser* dataParser,SendSystem *sendSystem, ClientHandler *handler) { + qDebug() << "RecognizeSystem::initialize thread ID " << QThread::currentThreadId(); + this->updateController = updateController; this->dataParser = dataParser; - this->server = server; this->clientHandler = handler; this->sendSystem = sendSystem; socket = handler->getSocket(); @@ -28,16 +28,14 @@ void RecognizeSystem::initialize(UpdateController *updateController,DataParser* connect(this,&RecognizeSystem::sigDeleteVersion,updateController,&UpdateController::deleteAssetVersion,Qt::AutoConnection); connect(this,&RecognizeSystem::sigCopyVersion,updateController,&UpdateController::createCopyVersion,Qt::AutoConnection); connect(this,&RecognizeSystem::sigXmlParser,dataParser->getProcessParser(),&ProcessParser::slot_read,Qt::AutoConnection); - connect(this,&RecognizeSystem::sigRecalculateDocs,server,&ServerLMSWidget::slot_UpdateDocs,Qt::AutoConnection); - connect(this,&RecognizeSystem::sigSendDocs,sendSystem,&SendSystem::sendDocs,Qt::AutoConnection); - - qDebug() << "Recognize init thread ID " << QThread::currentThreadId(); + //connect(this,&RecognizeSystem::sigRecalculateDocs,server,&ServerLMSWidget::slot_UpdateDocs,Qt::AutoConnection); + connect(this,&RecognizeSystem::sigSendDocs,sendSystem,&SendSystem::sendDocs,Qt::AutoConnection); } void RecognizeSystem::recognize() { - QMutexLocker locker(mutex); - qDebug() << "Recognize thread ID " << QThread::currentThreadId(); + qDebug() << "RecognizeSystem::recognize thread ID " << QThread::currentThreadId(); + QMutexLocker locker(mutex); QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); QByteArray data; @@ -448,7 +446,8 @@ void RecognizeSystem::recognize() if(packetType == PacketType::RECALCULATE_DOCS) { emit sigCalculateHash(); - emit sigRecalculateDocs(); + //emit sigRecalculateDocs(); + emit signal_updateDocsXML(); } if(packetType == PacketType::GET_DOCS) diff --git a/LibServer/Systems/recognizesystem.h b/LibServer/Systems/recognizesystem.h index 21a8a01..5dda0e6 100644 --- a/LibServer/Systems/recognizesystem.h +++ b/LibServer/Systems/recognizesystem.h @@ -12,10 +12,7 @@ #include #include -#include "serverlmswidget.h" - class UpdateController; -class ServerLMSWidget; class ClientHandler; class RecognizeSystem : public QObject @@ -25,8 +22,7 @@ class RecognizeSystem : public QObject public: RecognizeSystem(QObject *parent = nullptr); - void initialize(UpdateController *updateController,DataParser *dataParser, - ServerLMSWidget *server,SendSystem *sendSystem, ClientHandler *handler); + void initialize(UpdateController *updateController,DataParser *dataParser, SendSystem *sendSystem, ClientHandler *handler); void recognize(); ~RecognizeSystem(); @@ -37,14 +33,15 @@ signals: void sigChangeVersion(QString versionName); void sigDeleteVersion(QString versionName); void sigCopyVersion(QString versionName,QString newVersionName,QString author); - void sigRecalculateDocs(); + //void sigRecalculateDocs(); void sigSendDocs(QString docsPath); + void signal_updateDocsXML(); + private: UpdateController *updateController; SendSystem *sendSystem; DataParser *dataParser; - ServerLMSWidget *server; QString command; PacketType packetType; QString filePath; diff --git a/LibServer/Systems/sendsystem.cpp b/LibServer/Systems/sendsystem.cpp index 9df08d8..86027d9 100644 --- a/LibServer/Systems/sendsystem.cpp +++ b/LibServer/Systems/sendsystem.cpp @@ -7,12 +7,13 @@ SendSystem::SendSystem(QObject *parent) : QObject(parent) void SendSystem::initialize(DataParser *dataParser,QMutex *globalMutex) { - this->dataParser = dataParser; - connect(this,&SendSystem::sigSendXMLmessage,dataParser->ClientAnswer(),&ClientAnswerParser::message,Qt::AutoConnection); - connect(this,&SendSystem::sigSendNotify,dataParser->ClientAnswer(),&ClientAnswerParser::notify,Qt::DirectConnection); //потому что возвращает значение - connect(this,&SendSystem::sigSendVersion,dataParser->ClientAnswer(),&ClientAnswerParser::currentVersion,Qt::AutoConnection); + qDebug() << "SendSystem::initialize thread ID " << QThread::currentThreadId(); + + this->dataParser = dataParser; + //connect(this,&SendSystem::sigSendXMLmessage,dataParser->ClientAnswer(),&ClientAnswerParser::message,Qt::AutoConnection); //сигнал не используется + connect(this,&SendSystem::sigSendNotify,dataParser->ClientAnswer(),&ClientAnswerParser::notify,Qt::DirectConnection); //потому что возвращает значение + //connect(this,&SendSystem::sigSendVersion,dataParser->ClientAnswer(),&ClientAnswerParser::currentVersion,Qt::AutoConnection); //сигнал не используется - qDebug() << "SendSystem thread: " << QThread::currentThreadId(); mutex = globalMutex; } @@ -26,7 +27,8 @@ void SendSystem::setClient(Client *client,QTcpSocket *socket) void SendSystem::sendNotify(QString notify) { - qDebug() << "SendNotify thread: " << QThread::currentThreadId(); + qDebug() << "SendSystem::sendNotify thread ID " << QThread::currentThreadId(); + auto answer = emit sigSendNotify(notify); sendXmlAnswer(answer); } @@ -85,7 +87,7 @@ void SendSystem::sendFileBlockByteArray(QByteArray array, PacketType packetType) QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); - quint64 size = array.size(); + qint64 size = array.size(); qint64 bytesSended = 0; if (size == 0) @@ -97,19 +99,18 @@ void SendSystem::sendFileBlockByteArray(QByteArray array, PacketType packetType) stream << packetType; //Отправляем тип блока stream << size; - while (size > 0) + while (bytesSended < size) { QByteArray chunk = array.mid(bytesSended,sendFileBlockSize); stream << chunk; bytesSended += chunk.length(); - size -= bytesSended; } } else { sendPacketType(packetType); - quint64 size = array.size(); + qint64 size = array.size(); qint64 bytesSended = 0; if (size == 0) @@ -141,7 +142,7 @@ void SendSystem::sendVersion() void SendSystem::sendFileBlockWithRename(QString path, QString newName) { - qDebug() << "sendFileBlockWithRename thread: " << QThread::currentThreadId(); + qDebug() << "SendSystem::sendFileBlockWithRename thread ID " << QThread::currentThreadId(); QDataStream stream(socket); stream.setVersion(QDataStream::Qt_DefaultCompiledVersion); @@ -233,7 +234,8 @@ void SendSystem::sendPacketType(PacketType packetType) void SendSystem::sendXmlAnswer(QByteArray array, PacketType packetType) { - qDebug() << "SendSystemThread: " << QThread::currentThreadId(); + qDebug() << "SendSystem::sendXmlAnswer thread ID " << QThread::currentThreadId(); + Logger::instance().log("SEND TO: "+ client->getLogin() + " " + enumToString(packetType) + "\n Text: " + QString(array),LogLevel::DEBUG); @@ -316,11 +318,6 @@ void SendSystem::socketClose() socket->close(); } -bool SendSystem::socketFlush() //TODO: проверить использование -{ - return socket->flush(); -} - void SendSystem::sendStop() { isSendStopped = true; diff --git a/LibServer/Systems/sendsystem.h b/LibServer/Systems/sendsystem.h index 96cba97..30d79e5 100644 --- a/LibServer/Systems/sendsystem.h +++ b/LibServer/Systems/sendsystem.h @@ -35,7 +35,6 @@ public: void sendXmlAnswer(QByteArray array, PacketType packetType = PacketType::TYPE_XMLANSWER); void sendNeedUpdate(bool flag,quint64 size,quint64 fileCount,quint64 deleteCount); void updateFiles(QList fileSendList, QList deleteList); - bool socketFlush(); bool getIsSendStopped() const; @@ -49,9 +48,9 @@ public slots: signals: void sigLoadHash(); - QByteArray sigSendXMLmessage(QString loginFrom, QString loginTo, QString text, QString userType); + //QByteArray sigSendXMLmessage(QString loginFrom, QString loginTo, QString text, QString userType); //сигнал не используется QByteArray sigSendNotify(QString message); - QByteArray sigSendVersion(); + //QByteArray sigSendVersion(); //сигнал не используется private: Client *client; diff --git a/LibServer/Systems/updatecontroller.cpp b/LibServer/Systems/updatecontroller.cpp index d0c07c0..f5d88a6 100644 --- a/LibServer/Systems/updatecontroller.cpp +++ b/LibServer/Systems/updatecontroller.cpp @@ -1,3 +1,4 @@ +#include #include "updatecontroller.h" @@ -5,16 +6,19 @@ UpdateController::UpdateController(QObject *parent) : QObject(parent), commonClientHandler(nullptr) { + qDebug() << "UpdateController init thread ID " << QThread::currentThreadId(); + buildPath = QDir::currentPath() + "/" + applicationFolderName; sharedDataPath = QDir::currentPath() + "/" + sharedDataFolderName; Logger::instance().log(buildPath); qDebug() << hashFileName; } -void UpdateController::initialize(CommonClientHandler *commonClientHandler,DataParser *dataParser,AssetsManager *assetManager) +void UpdateController::initialize(CommonClientHandler *commonClientHandler,AssetsManager *assetManager) { + qDebug() << "UpdateController::initialize thread ID " << QThread::currentThreadId(); + this->commonClientHandler = commonClientHandler; - this->dataParser = dataParser; this->assetManager = assetManager; hashCalculator = new FastHashCalculator; @@ -24,7 +28,7 @@ void UpdateController::initialize(CommonClientHandler *commonClientHandler,DataP } sizeToSend = 0; - assetManager->initialize(this,dataParser); + assetManager->initialize(this); if (!checkRequiredFolder()) { @@ -37,19 +41,20 @@ void UpdateController::initialize(CommonClientHandler *commonClientHandler,DataP setUpCurrentServerHash(); mutex = new QMutex; - qDebug() << "UpdateController init thread ID " << QThread::currentThreadId(); emit sigInitializeFinished(); } void UpdateController::changeAssetVersion(QString versionName) { + qDebug() << "UpdateController::changeAssetVersion thread ID " << QThread::currentThreadId(); + //commonClientHandler->slot_sendPacketToAllClients(PacketType::BUSY); bool res = emit signal_BlockAutorization(true, "SERVER", "ChangeAssetVersion"); - qDebug() << "UpdateController thread ID " << QThread::currentThreadId(); + currentStreamingPath = assetManager->setVersion(versionName); setUpCurrentServerHash(); - emit sigUpdateDocs(); + emit sigUpdateDocsXML(); commonClientHandler->slot_sendPacketToAllClients(PacketType::HASH_READY, false); commonClientHandler->sendCurrentVersionToAllClient(); diff --git a/LibServer/Systems/updatecontroller.h b/LibServer/Systems/updatecontroller.h index b8d1ff0..71d169c 100644 --- a/LibServer/Systems/updatecontroller.h +++ b/LibServer/Systems/updatecontroller.h @@ -10,14 +10,14 @@ #include #include #include -#include #include #include #include "fasthashcalculator.h" +#include "assetsmanager.h" +#include "commonclienthandler.h" class TCPServer; class SendSystem; -class DataParser; class ClientHandler; class AssetsManager; class ServerLMSWidget; @@ -30,7 +30,7 @@ class UpdateController : public QObject public: explicit UpdateController(QObject *parent = 0); - void initialize(CommonClientHandler* commonClientHandler,DataParser *dataParser,AssetsManager *assetManager); + void initialize(CommonClientHandler* commonClientHandler,AssetsManager *assetManager); void compareFiles(ClientHandler* handler, QByteArray array); void showHash(); void calculateFullHash(); @@ -67,7 +67,7 @@ public slots: signals: void sigErrorRequired(int code); - void sigUpdateDocs(); + void sigUpdateDocsXML(); void sigInitializeFinished(); @@ -85,7 +85,6 @@ private: QString sharedDataPath; CommonClientHandler *commonClientHandler; FastHashCalculator *hashCalculator; - DataParser *dataParser; AssetsManager *assetManager; quint64 sizeToSend; QMutex *mutex; diff --git a/LibServer/cficontroller/cficontroller.cpp b/LibServer/cficontroller/cficontroller.cpp index 3a8a6a1..9a1ef24 100644 --- a/LibServer/cficontroller/cficontroller.cpp +++ b/LibServer/cficontroller/cficontroller.cpp @@ -5,6 +5,8 @@ CfiController::CfiController(UpdateController* updateController, QObject *parent updateController(updateController), germanLocale(nullptr) { + qDebug() << "CfiController init thread ID " << QThread::currentThreadId(); + germanLocale = new QLocale(QLocale::German); } diff --git a/LibServer/clienthandler/clienthandler.cpp b/LibServer/clienthandler/clienthandler.cpp index 8e74f23..4eeb7e1 100644 --- a/LibServer/clienthandler/clienthandler.cpp +++ b/LibServer/clienthandler/clienthandler.cpp @@ -1,4 +1,5 @@ #include "clienthandler.h" +#include "recognizesystem.h" #include @@ -7,10 +8,11 @@ ClientHandler::ClientHandler( QObject *parent): QObject(parent) { + qDebug() << "ClientHandler init thread ID " << QThread::currentThreadId(); } -void ClientHandler::initialize(int descriptor,ServerLMSWidget *serverWidget, - UpdateController *updateController,DataParser *dataParser) +void ClientHandler::initialize(int descriptor, + UpdateController *updateController,DataParser *dataParser, QMutex *mutex) { this->socket = new QTcpSocket; this->thread = new QThread; @@ -18,7 +20,7 @@ void ClientHandler::initialize(int descriptor,ServerLMSWidget *serverWidget, socket->setParent(nullptr); socket->setSocketDescriptor(descriptor); - qDebug() << "Client thread: " << QThread::currentThreadId(); + qDebug() << "ClientHandler::initialize thread ID " << QThread::currentThreadId(); sendSystem = new SendSystem; recognizeSystem = new RecognizeSystem; @@ -30,7 +32,6 @@ void ClientHandler::initialize(int descriptor,ServerLMSWidget *serverWidget, recognizeSystem->moveToThread(thread); this->updateController = updateController; - this->server = serverWidget; QString peerName = socket->peerName(); QString peerAddress = socket->peerAddress().toString(); @@ -38,28 +39,30 @@ void ClientHandler::initialize(int descriptor,ServerLMSWidget *serverWidget, client = new Client(peerName,peerAddress,peerPort,socket); + connect(recognizeSystem,&RecognizeSystem::signal_updateDocsXML,this,&ClientHandler::signal_updateDocsXML); + connect(this,&ClientHandler::sigSendXmlAnswer,sendSystem,&SendSystem::sendXmlAnswer,Qt::AutoConnection); connect(this,&ClientHandler::sigInitSender,sendSystem,&SendSystem::initialize,Qt::AutoConnection/*Qt::DirectConnection*/); connect(this,&ClientHandler::sigFileBlock,sendSystem,&SendSystem::sendFileBlock,Qt::AutoConnection); connect(this,&ClientHandler::sigFileBlockByteArray,sendSystem,&SendSystem::sendFileBlockByteArray,Qt::AutoConnection); connect(this,&ClientHandler::sigFolderBlock,sendSystem,&SendSystem::sendFolderBlock,Qt::AutoConnection); - connect(this,&ClientHandler::sigGetIsSendStopped,sendSystem,&SendSystem::getIsSendStopped,Qt::AutoConnection); + connect(this,&ClientHandler::sigGetIsSendStopped,sendSystem,&SendSystem::getIsSendStopped,/*Qt::AutoConnection*/Qt::DirectConnection); //Возвращает значение connect(this,&ClientHandler::sigSendDeleteBlock,sendSystem,&SendSystem::sendDeleteBlock,Qt::AutoConnection); connect(this,&ClientHandler::sigNeedUpdate,sendSystem,&SendSystem::sendNeedUpdate,Qt::AutoConnection); connect(this,&ClientHandler::sigSendNotify,sendSystem,&SendSystem::sendNotify,Qt::AutoConnection); connect(this,&ClientHandler::sigSendFileBlockWithRename,sendSystem,&SendSystem::sendFileBlockWithRename,Qt::AutoConnection); connect(this,&ClientHandler::sigSendVersion,sendSystem,&SendSystem::sendVersion,Qt::AutoConnection); connect(this,&ClientHandler::sigSocketClose,sendSystem,&SendSystem::socketClose,Qt::AutoConnection); - connect(this,&ClientHandler::sigSocketFlush,sendSystem,&SendSystem::socketFlush,Qt::AutoConnection); + //connect(this,&ClientHandler::sigSocketFlush,sendSystem,&SendSystem::socketFlush,Qt::AutoConnection); //не используется connect(this,&ClientHandler::sigSendPacketType,sendSystem,&SendSystem::sendPacketType,Qt::AutoConnection); connect(this,&ClientHandler::sigSendStop,sendSystem,&SendSystem::sendStop,Qt::DirectConnection); connect(socket,&QTcpSocket::readyRead,this,&ClientHandler::initClientType,Qt::AutoConnection); initClientType(); - recognizeSystem->initialize(updateController,dataParser,serverWidget,sendSystem, this); + recognizeSystem->initialize(updateController,dataParser,sendSystem, this); sendSystem->setClient(client,socket); - emit sigInitSender(dataParser,serverWidget->getMutex()); + emit sigInitSender(dataParser, mutex); Logger::instance().log("SERVER: Client connected"); } diff --git a/LibServer/clienthandler/clienthandler.h b/LibServer/clienthandler/clienthandler.h index dbfa812..f7c08f5 100644 --- a/LibServer/clienthandler/clienthandler.h +++ b/LibServer/clienthandler/clienthandler.h @@ -64,17 +64,19 @@ signals: void sigSendNotify(QString notify); void sigSendFileBlockWithRename (QString path,QString newName); void sigSocketClose(); - bool sigSocketFlush(); + //bool sigSocketFlush(); //не используется void sigSendVersion(); void sigSendPacketType(PacketType packetType); - void sigSendStop(); + void sigSendStop(); + + void signal_updateDocsXML(); public : QThread *thread; QTcpSocket *socket; - void initialize(int descriptor, ServerLMSWidget *serverWidget, - UpdateController *updateController, DataParser *dataParser); + void initialize(int descriptor, + UpdateController *updateController, DataParser *dataParser, QMutex *mutex); void setClient(Client *value); private: UpdateController *updateController; @@ -82,7 +84,6 @@ private: Client *client; SendSystem *sendSystem; - ServerLMSWidget *server; void initClientType(); void packetTypeInit(PacketType packet, Client *client); diff --git a/LibServer/metatypes.cpp b/LibServer/metatypes.cpp index 74a7b98..f39f2e1 100644 --- a/LibServer/metatypes.cpp +++ b/LibServer/metatypes.cpp @@ -6,4 +6,11 @@ void registerMetaType() qRegisterMetaType("PacketType"); qRegisterMetaType("UserType"); qRegisterMetaType("LogLevel"); + qRegisterMetaType("QStringList"); + qRegisterMetaType("DataBaseSettings"); + + qRegisterMetaType("EStateServer"); + qRegisterMetaType("EStateBlockAutorization"); + + qRegisterMetaType("CheckResult"); } diff --git a/LibServer/metatypes.h b/LibServer/metatypes.h index ef63681..de977bd 100644 --- a/LibServer/metatypes.h +++ b/LibServer/metatypes.h @@ -4,11 +4,20 @@ #include "Data/PacketType.h" #include "Data/typesDataServerClient.h" #include "Systems/logger.h" +#include "databaselms.h" +#include "providerdblms.h" void registerMetaType(); Q_DECLARE_METATYPE(PacketType) Q_DECLARE_METATYPE(UserType) Q_DECLARE_METATYPE(LogLevel) +Q_DECLARE_METATYPE(QStringList) +Q_DECLARE_METATYPE(DataBaseSettings) + +Q_DECLARE_METATYPE(EStateServer) +Q_DECLARE_METATYPE(EStateBlockAutorization) + +Q_DECLARE_METATYPE(CheckResult) #endif // METATYPES_H diff --git a/LibServer/multithreadserver/multithreadserver.cpp b/LibServer/multithreadserver/multithreadserver.cpp index ed9cf31..84d1541 100644 --- a/LibServer/multithreadserver/multithreadserver.cpp +++ b/LibServer/multithreadserver/multithreadserver.cpp @@ -1,27 +1,41 @@ #include "multithreadserver.h" -MultiThreadServer::MultiThreadServer(ServerLMSWidget *widget,UpdateController *updateController,ProcessingSystem *processingSystem, +MultiThreadServer::MultiThreadServer(UpdateController *updateController, DocsUpdater *docsUpdater,ProcessingSystem *processingSystem, DataParser *dataParser,qint16 hostPort, QObject *parent ): QTcpServer(parent), - serverLmsWidget(widget), + mutex(nullptr), hostPort(hostPort), processingSystem(processingSystem), updateController(updateController), + docsUpdater(docsUpdater), dataParser(dataParser), stateServer(stoped), stateBlockAutorization(blocked) { + qDebug() << "MultiThreadServer init thread ID " << QThread::currentThreadId(); + clientsMap = new QMap; + mutex = new QMutex; + + connect(this, &MultiThreadServer::signal_updateDocsXML, docsUpdater, &DocsUpdater::slot_updateDocsXML); +} + +MultiThreadServer::~MultiThreadServer() +{ + delete mutex; } void MultiThreadServer::incomingConnection(qintptr socketDesriptor) { ClientHandler* newClient = new ClientHandler; - connect(this,&MultiThreadServer::sigInitClient,newClient,&ClientHandler::initialize, Qt::AutoConnection/*Qt::DirectConnection*/); + connect(newClient,&ClientHandler::signal_updateDocsXML,this,&MultiThreadServer::slot_UpdateDocs); + + //connect(this,&MultiThreadServer::sigInitClient,newClient,&ClientHandler::initialize, Qt::AutoConnection/*Qt::DirectConnection*/); connect(newClient,&ClientHandler::sigClientDisconnected,this,&MultiThreadServer::slotDisconnectClient,Qt::AutoConnection); - emit sigInitClient(socketDesriptor,serverLmsWidget,updateController,dataParser); - disconnect(this,&MultiThreadServer::sigInitClient,newClient,&ClientHandler::initialize); + //emit sigInitClient(socketDesriptor,serverLmsWidget,updateController,dataParser, getMutex()); + newClient->initialize(socketDesriptor,updateController,dataParser, getMutex()); + //disconnect(this,&MultiThreadServer::sigInitClient,newClient,&ClientHandler::initialize); addClient(socketDesriptor,newClient); @@ -40,19 +54,18 @@ bool MultiThreadServer::startServer() { if(stateServer == stoped) { - //connect(tcpServer, &QTcpServer::newConnection, this, &ServerLMSWidget::slotNewConnection,Qt::AutoConnection); - if(!listen(QHostAddress::Any, hostPort)) { stateServer = stoped; + emit signal_StateServer(stateServer, stateBlockAutorization); Logger::instance().log("SERVER: start ERROR"); return false; } else { - - stateServer = started; + stateServer = started; slot_BlockAutorization(false, "SERVER", "StopServer"); + emit signal_StateServer(stateServer, stateBlockAutorization); Logger::instance().log("SERVER: start OK"); return true; } @@ -71,6 +84,7 @@ bool MultiThreadServer::stopServer() close(); stateServer = stoped; slot_BlockAutorization(true, "SERVER", "StopServer"); + emit signal_StateServer(stateServer, stateBlockAutorization); Logger::instance().log("SERVER: stop OK"); return true; } @@ -83,9 +97,20 @@ QMap *MultiThreadServer::getClientsMap() const return clientsMap; } +QStringList MultiThreadServer::getClientFullNameList() +{ + QStringList list; + for(ClientHandler* handler : *getClientsMap()) + { + QString clientFullName = handler->getClient()->getFullName(); + list.append(clientFullName); + } + return list; +} + void MultiThreadServer::updateClientList() { - serverLmsWidget->slot_UpdateListClients(); + emit signal_UpdateListClients(getClientFullNameList()); } void MultiThreadServer::disableClients() @@ -151,8 +176,8 @@ void MultiThreadServer::slotDisconnectClient(QString peerAddress, QString peerPo emit signalStopSendFile(); Logger::instance().log("SERVER: Client " + login + " disconnected"); - serverLmsWidget->slot_UpdateListClients(); - serverLmsWidget->getProcessingSystem()->processingClientDeAutorization(login); + emit signal_UpdateListClients(getClientFullNameList()); + processingSystem->processingClientDeAutorization(login); } bool MultiThreadServer::slot_BlockAutorization(bool block, QString whoFullName, QString type) @@ -259,15 +284,30 @@ bool MultiThreadServer::slot_BlockAutorization(bool block, QString whoFullName, return res; } +void MultiThreadServer::slot_StartServer() +{ + startServer(); +} + +void MultiThreadServer::slot_StopServer() +{ + stopServer(); +} + +void MultiThreadServer::slot_UpdateDocs() +{ + emit signal_updateDocsXML(); +} + void MultiThreadServer::removeClient(int idSocket) { clientsMap->remove(idSocket); - serverLmsWidget->slot_UpdateListClients(); + emit signal_UpdateListClients(getClientFullNameList()); } void MultiThreadServer::addClient(qintptr descriptor, ClientHandler *client) { (*clientsMap)[descriptor] = client; - serverLmsWidget->slot_UpdateListClients(); + emit signal_UpdateListClients(getClientFullNameList()); } diff --git a/LibServer/multithreadserver/multithreadserver.h b/LibServer/multithreadserver/multithreadserver.h index ca206c8..8bf4771 100644 --- a/LibServer/multithreadserver/multithreadserver.h +++ b/LibServer/multithreadserver/multithreadserver.h @@ -1,27 +1,34 @@ #ifndef MULTITHREADSERVER_H #define MULTITHREADSERVER_H -#include "serverlmswidget.h" #include "Systems/processingsystem.h" +#include "clienthandler.h" +#include "Data/PacketType.h" +#include "updatecontroller.h" +#include "Parsers/dataparser.h" #include class ProcessingSystem; +class ClientHandler; +class DocsUpdater; +class DataParser; +class UpdateController; + class MultiThreadServer : public QTcpServer { Q_OBJECT public: - MultiThreadServer(ServerLMSWidget *widget,UpdateController *updateController,ProcessingSystem *processingSystem, + MultiThreadServer(UpdateController *updateController, DocsUpdater *docsUpdater,ProcessingSystem *processingSystem, DataParser *dataParser, qint16 hostPort, QObject *parent = nullptr); + ~MultiThreadServer(); QMap *getClientsMap() const; + QStringList getClientFullNameList(); void updateClientList(); void disableClients(); - bool startServer(); - bool stopServer(); - EStateBlockAutorization getStateBlockAutorization() const { return stateBlockAutorization; @@ -30,38 +37,60 @@ public: { return stateServer; } + QMutex *getMutex() const + { + return mutex; + } private: + + bool startServer(); + bool stopServer(); + void blockAutorization() { stateBlockAutorization = blocked; + emit signal_StateServer(stateServer, stateBlockAutorization); } void unBlockAutorization() { stateBlockAutorization = unblocked; + emit signal_StateServer(stateServer, stateBlockAutorization); } signals: - void sigInitClient(int descriptor, ServerLMSWidget *serverWidget, - UpdateController *updateController, DataParser *dataParser); + //void sigInitClient(int descriptor, ServerLMSWidget *serverWidget, + // UpdateController *updateController, DataParser *dataParser, QMutex *mutex); void signalStopSendFile(); void signal_BlockAutorizationIndicate(bool block, QString blocker, QString types); void signal_sendPacketToAllClients(PacketType packetType, bool flOnlyGUI); + void signal_StateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization); + + void signal_UpdateListClients(QStringList listFullName); + + void signal_updateDocsXML(); + public slots: void slotDisconnectClient(QString peerAddress, QString peerPort); bool slot_BlockAutorization(bool block, QString whoFullName, QString type); + + void slot_StartServer(); + void slot_StopServer(); + + void slot_UpdateDocs(); protected: void incomingConnection(qintptr handle) override; private: - ServerLMSWidget *serverLmsWidget; + QMutex *mutex; QMap *clientsMap; qint16 hostPort; ProcessingSystem *processingSystem; UpdateController *updateController; + DocsUpdater *docsUpdater; DataParser *dataParser; EStateServer stateServer; diff --git a/LibServer/providerdblms/providerdblms.cpp b/LibServer/providerdblms/providerdblms.cpp index 8353ff4..c57fa83 100644 --- a/LibServer/providerdblms/providerdblms.cpp +++ b/LibServer/providerdblms/providerdblms.cpp @@ -2,13 +2,15 @@ #include #include +#include "specialmessagebox.h" -ProviderDBLMS::ProviderDBLMS(QWidget *parentWidget, QObject *parent) : +ProviderDBLMS::ProviderDBLMS(QObject *parent) : QObject(parent), - dbLMS(nullptr), - parentWidget(parentWidget) + dbLMS(nullptr) { - dbLMS = new InterfaceDataBaseLMS(parentWidget); + qDebug() << "ProviderDBLMS init thread ID " << QThread::currentThreadId(); + + dbLMS = new InterfaceDataBaseLMS(); connect(dbLMS, &InterfaceDataBaseLMS::signal_ErrorPostgreSQL, this, &ProviderDBLMS::signal_ErrorPostgreSQL); } @@ -17,6 +19,55 @@ ProviderDBLMS::~ProviderDBLMS() DisConnectionFromDB(); } +void ProviderDBLMS::slot_TryConnectionToDB() +{ + ConnectionToDB(); +} +void ProviderDBLMS::slot_TryDisConnectionFromDB() +{ + DisConnectionFromDB(); +} + +void ProviderDBLMS::slot_CheckDB() +{ + CheckResult result; + + result.resDriver = ProviderDBLMS::checkDriverQPSQLavailable(); + + result.resUser = this->checkUserLMSexist(); + + result.resDB = this->checkDataBaseLMSexist(); + + emit signal_CheckDBResult(result); +} + +void ProviderDBLMS::slot_RepareDB(CheckResult result) +{ + if(!result.resUser) + { + if(!this->createUser()) + { + result.resUser = false; + emit signal_RepareDBResult(result); + } + else + result.resUser = true; + } + + if(!result.resDB) + { + if(!this->createDB()) + { + result.resDB = false; + emit signal_RepareDBResult(result); + } + else + result.resDB = true; + } + + emit signal_RepareDBResult(result); +} + bool ProviderDBLMS::ConnectionToDB() { mtxAccess.lock(); @@ -26,15 +77,31 @@ bool ProviderDBLMS::ConnectionToDB() { bool res = Q_EMIT signal_BlockAutorization(false, "SERVER", "DisConnectionDB"); + bool res1 = dbLMS->deAuthorizationAllTrainees(); + bool res2 = dbLMS->deAuthorizationAllInstructors(); + + emit signal_StateConnectionToDB(true, getDBSettings()); + emit signal_ResultTryConnectDb(true); + mtxAccess.unlock(); return true; } else - { + { + emit signal_StateConnectionToDB(false, getDBSettings()); + emit signal_ResultTryConnectDb(false); + mtxAccess.unlock(); return false; } - } + } + + bool res1 = dbLMS->deAuthorizationAllTrainees(); + bool res2 = dbLMS->deAuthorizationAllInstructors(); + + emit signal_StateConnectionToDB(true, getDBSettings()); + emit signal_ResultTryConnectDb(true); + mtxAccess.unlock(); return true; } @@ -46,7 +113,19 @@ void ProviderDBLMS::DisConnectionFromDB() { bool res = Q_EMIT signal_BlockAutorization(true, "SERVER", "DisConnectionDB"); - dbLMS->disConnectionFromDB(); + bool res1 = dbLMS->deAuthorizationAllTrainees(); + bool res2 = dbLMS->deAuthorizationAllInstructors(); + + if(dbLMS->disConnectionFromDB()) + { + emit signal_ResultTryDisConnectDb(true); + emit signal_StateConnectionToDB(false, getDBSettings()); + } + } + else + { + emit signal_ResultTryDisConnectDb(true); + emit signal_StateConnectionToDB(false, getDBSettings()); } mtxAccess.unlock(); } @@ -62,17 +141,17 @@ bool ProviderDBLMS::DBisConnected() DataBaseSettings ProviderDBLMS::getDBSettings() { - return dbLMS->getDataBaseSettings(); + return InterfaceDataBaseLMS::getDataBaseSettings(); } bool ProviderDBLMS::setUserPasswordPostgres(QString userName, QString password) { - return dbLMS->setUserPasswordPostgres(userName, password); + return InterfaceDataBaseLMS::setUserPasswordPostgres(userName, password); } bool ProviderDBLMS::checkDriverQPSQLavailable() { - return dbLMS->checkDriverQPSQLavailable(); + return InterfaceDataBaseLMS::checkDriverQPSQLavailable(); } bool ProviderDBLMS::checkUserLMSexist() diff --git a/LibServer/providerdblms/providerdblms.h b/LibServer/providerdblms/providerdblms.h index 5e9c298..830e3db 100644 --- a/LibServer/providerdblms/providerdblms.h +++ b/LibServer/providerdblms/providerdblms.h @@ -6,11 +6,19 @@ #include "interfacedatabaselms.h" #include "tasksAmmFim.h" +class CheckResult +{ +public: + bool resDriver = false; + bool resUser = false; + bool resDB = false; +}; + class ProviderDBLMS : public QObject { Q_OBJECT public: - explicit ProviderDBLMS(QWidget *parentWidget, QObject *parent = nullptr); + explicit ProviderDBLMS(QObject *parent = nullptr); ~ProviderDBLMS(); public: QString getMainInstructorName(); @@ -75,16 +83,32 @@ Q_SIGNALS: bool signal_BlockAutorization(bool block, QString whoFullName, QString type); signals: void signal_ErrorPostgreSQL(QString text); + void signal_StateConnectionToDB(bool dbIsConnected, DataBaseSettings dbSettings); -public: + void signal_ResultTryConnectDb(bool result); + void signal_ResultTryDisConnectDb(bool result); + + void signal_CheckDBResult(CheckResult result); + void signal_RepareDBResult(CheckResult result); + +public slots: + void slot_TryConnectionToDB(); + void slot_TryDisConnectionFromDB(); + + void slot_CheckDB(); + void slot_RepareDB(CheckResult result); + +private: bool ConnectionToDB(); void DisConnectionFromDB(); + +public: bool DBisConnected(); - DataBaseSettings getDBSettings(); + static DataBaseSettings getDBSettings(); //PostgreSQL - bool setUserPasswordPostgres(QString userName, QString password); - bool checkDriverQPSQLavailable(); + static bool checkDriverQPSQLavailable(); + static bool setUserPasswordPostgres(QString userName, QString password); bool checkUserLMSexist(); bool checkDataBaseLMSexist(); @@ -94,7 +118,6 @@ public: private: InterfaceDataBaseLMS* dbLMS; QMutex mtxAccess; - QWidget *parentWidget; }; #endif // PROVIDERDBLMS_H diff --git a/LibServer/resources/blankXML/ListsTasksAMMofAllTrainees.xml b/LibServer/resources/blankXML/ListsTasksAMMofAllTrainees.xml new file mode 100644 index 0000000..ea388a5 --- /dev/null +++ b/LibServer/resources/blankXML/ListsTasksAMMofAllTrainees.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LibServer/resources/blankXML/ListsTasksFIMofAllTrainees.xml b/LibServer/resources/blankXML/ListsTasksFIMofAllTrainees.xml new file mode 100644 index 0000000..dc95b25 --- /dev/null +++ b/LibServer/resources/blankXML/ListsTasksFIMofAllTrainees.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LibServer/serverlmswidget.cpp b/LibServer/serverlmswidget.cpp index 1cc0851..1fad2d7 100644 --- a/LibServer/serverlmswidget.cpp +++ b/LibServer/serverlmswidget.cpp @@ -1,40 +1,43 @@ -#include -#include -#include -#include #include -#include + #include "serverlmswidget.h" #include "dialogsettingstray.h" #include "specialmessagebox.h" -#include "ui_serverlmswidget.h" #include "metatypes.h" +#include "ui_serverlmswidget.h" + const QString ServerLMSWidget::languageENG = "en_EN"; const QString ServerLMSWidget::languageRUS = "ru_RU"; + ServerLMSWidget::ServerLMSWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ServerLMSWidget), - waitAnimationWidget(nullptr), - server(nullptr), + waitAnimationWidget(nullptr), updateThread(nullptr), loggerThread(nullptr), - mutex(nullptr), + serverThread(nullptr), + server(nullptr), dataParser(nullptr), processingSystem(nullptr), - updateController(nullptr), - assetsManager(nullptr), commonClientHandler(nullptr), chatSystem(nullptr), + providerDBLMS(nullptr), + updateController(nullptr), + assetsManager(nullptr), docsUpdater(nullptr), - cfiController(nullptr), - providerDBLMS(nullptr), - first (true), + cfiController(nullptr), language(languageENG), errorCode(0), - versionStr("..."), - flStartInitialization(false) + state_VersionMaterials("..."), + state_dbIsConnected(false), + state_Server(EStateServer::stoped), + state_BlockAutorization(EStateBlockAutorization::unblocked), + flStartInitialization(false), + flTryConnectionToDB(false), + flNeedReconnectDB(false), + flTryUpdateDocs(false) { ui->setupUi(this); @@ -49,53 +52,88 @@ ServerLMSWidget::ServerLMSWidget(QWidget *parent) : updateMyStyleSheet(); - setLanguageInterfase(); + initLanguageInterfase(); waitAnimationWidget = new WaitAnimationWidget; QMovie *movie = new QMovie(":/resources/icons/762.gif"); waitAnimationWidget->setParent(this); waitAnimationWidget->initialize(movie,this); - - waitAnimationWidget->showWithPlay(); - - updateStateOnlyVersion(); } ServerLMSWidget::~ServerLMSWidget() { - if(flStartInitialization) - { - server->stopServer(); + if(server) + emit signal_StopServer(); + if(updateThread) + { updateThread->quit(); updateThread->wait(); delete updateThread; + } + if(serverThread) + { + serverThread->quit(); + serverThread->wait(); + delete serverThread; + } + + if(server) delete server; + if(commonClientHandler) delete commonClientHandler; + if(dataParser) delete dataParser; + if(processingSystem) delete processingSystem; + if(updateController) delete updateController; + if(cfiController) delete cfiController; + if(docsUpdater) delete docsUpdater; + if(assetsManager) delete assetsManager; + if(chatSystem) delete chatSystem; - delete mutex; - + if(loggerThread) + { loggerThread->quit(); loggerThread->wait(); delete loggerThread; - - delete providerDBLMS; } - waitAnimationWidget->hideWithStop(); - delete waitAnimationWidget; + if(providerDBLMS) + delete providerDBLMS; + + + if(waitAnimationWidget) + { + waitAnimationWidget->hideWithStop(); + delete waitAnimationWidget; + } delete ui; } + +//INTERFACE + +void ServerLMSWidget::startInitialization() +{ + startInitialization_step0(); +} + +QString ServerLMSWidget::getLanguage() +{ + return language; +} + + +//EVENT + void ServerLMSWidget::changeEvent(QEvent *event) { // В случае получения события изменения языка приложения @@ -103,9 +141,10 @@ void ServerLMSWidget::changeEvent(QEvent *event) { ui->retranslateUi(this); // переведём окно заново + //И все состояния updateStateOnlyServer(); updateStateOnlyDB(); - updateStateOnlyVersion(); + updateStateOnlyVersionMaterials(); } } @@ -115,218 +154,8 @@ void ServerLMSWidget::resizeEvent(QResizeEvent *event) waitAnimationWidget->resize(size); } -void ServerLMSWidget::slot_UpdateListClients() -{ - //Очищаем список - ui->listWidget_Clients->clear(); - for (const ClientHandler *handler : server->getClientsMap()->values()) - { - QString strClient = handler->getClient()->getFullName(); - - ui->listWidget_Clients->addItem(strClient); - ui->listWidget_Clients->scrollToBottom(); - ui->listWidget_Clients->setCurrentRow(ui->listWidget_Clients->count() - 1); - } - - int countClients = (*server->getClientsMap()).count(); - Logger::instance().log("SERVER: countClients = " + QString::number(countClients)); -} - -void ServerLMSWidget::slot_AddMessageToLog(QString message) -{ - //ui->loggerTextField->appendPlainText(message); - ui->loggerTextField->appendHtml(message); -} - -void ServerLMSWidget::slot_ErrorPostgreSQL(QString text) -{ - emit signal_Menu_ShowWindow(); - SpecMsgBox::CriticalClose(this, tr("Error PostgreSQL!") + "\n" + text); -} - -void ServerLMSWidget::slot_UpdateDocs() -{ - QApplication::setOverrideCursor(Qt::WaitCursor); - - if(docsUpdater->updateDocsXML()) - emit signal_DocsChanged(); - - QApplication::restoreOverrideCursor(); - - //TODO для теста - //cfiController->test(); -} - -void ServerLMSWidget::slot_startInitialization_step1() -{ - Logger::instance().log("Update docs.xml..."); - slot_UpdateDocs(); - Logger::instance().log("Update docs.xml completed!"); - - ui->btnStopServer->setEnabled(false); - ui->btnStartServer->setEnabled(true); - - flStartInitialization = true; - - updateStateOnlyServer(); - updateStateOnlyDB(); - updateStateOnlyVersion(); - - QApplication::restoreOverrideCursor(); - - if(hasError() == 100) - return; - - Logger::instance().log("Try connection to DB..."); - tryConnectionToDB(); - - waitAnimationWidget->hideWithStop(); -} - -void ServerLMSWidget::slot_setVersion(QString versionStr) -{ - this->versionStr = versionStr; - Logger::instance().log("Set Version: " + versionStr); - updateStateOnlyVersion(); -} - -void ServerLMSWidget::start() -{ - startInitialization_step0(); -} - -void ServerLMSWidget::slot_BlockAutorizationIndicate(bool block, QString blocker, QString types) -{ - if(block) - { - //server->blockAutorization(); - Logger::instance().log(QString("BLOCK from: %1").arg(blocker), LogLevel::INFO); - //if(type != "") - Logger::instance().log(QString("Blockers: %1").arg(types), LogLevel::DEBUG); - } - else - { - //server->unBlockAutorization(); - Logger::instance().log(QString("UNBLOCK from: %1").arg(blocker), LogLevel::INFO); - //if(type != "") - Logger::instance().log(QString("Blockers: %1").arg(types), LogLevel::DEBUG); - } - updateStateOnlyServer(); -} - -void ServerLMSWidget::slot_LanguageChanged(QString language) -{ - qtLanguageTranslator.load(QString("translations/RRJServer_") + language, "."); - qApp->installTranslator(&qtLanguageTranslator); - - emit signal_LanguageChanged(language); -} - -void ServerLMSWidget::on_btnStartServer_clicked() -{ - if(server->startServer()) - { - QApplication::setOverrideCursor(Qt::WaitCursor); - - ui->btnStartServer->setEnabled(false); - ui->btnStopServer->setEnabled(true); - //slot_BlockAutorizationIndicate(false, "SERVER"); - - //updateStateOnlyServer(); - - emit signal_Tray_ShowMessage(tr("Server is started!")); - - QApplication::restoreOverrideCursor(); - } -} - -void ServerLMSWidget::on_btnStopServer_clicked() -{ - if(server->stopServer()) - { - QApplication::setOverrideCursor(Qt::WaitCursor); - - ui->btnStopServer->setEnabled(false); - ui->btnStartServer->setEnabled(true); - //slot_BlockAutorizationIndicate(true, "SERVER"); - - //updateStateOnlyServer(); - - emit signal_Tray_ShowMessage(tr("Server is stoped!")); - - QApplication::restoreOverrideCursor(); - } -} - -void ServerLMSWidget::on_btnSettings_clicked() -{ - ServerDBSettings settingsTemp; - if(!DialogSettingsTray::loadSettings(&settingsTemp)) - { - SpecMsgBox::CriticalClose(this, tr("Settings file could not be opened:") + "'config/settings.xml'"); - return; - } - - DialogSettingsTray dlg(providerDBLMS, this); - dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint); - - connect(&dlg, &DialogSettingsTray::signal_LanguageChanged, this, &ServerLMSWidget::slot_LanguageChanged); - //connect(&dlg, &DialogSettingsTray::signal_UpdateStyleSheet, this, &ServerLMSWidget::slot_UpdateStyleSheet); - - connect(&dlg, &DialogSettingsTray::signal_UpdateDocs, this, &ServerLMSWidget::slot_UpdateDocs); - - - switch( dlg.exec() ) - { - case QDialog::Accepted: - { - language = dlg.getSettings().Language; - - if(dlg.settingsDBisChanged()) - { - on_btnStopServer_clicked(); - - providerDBLMS->deAuthorizationAll(); - - providerDBLMS->DisConnectionFromDB(); - - updateStateOnlyDB(); - - SpecMsgBox::WarningClose(this, tr("Database settings have been changed.\nThe server will be restarted.")); - - tryConnectionToDB(); - } - - break; - } - case QDialog::Rejected: - break; - default: - break; - } -} - -void ServerLMSWidget::setLanguageInterfase() -{ - ServerDBSettings settings; - DialogSettingsTray::loadSettings(&settings); - - if(settings.Language == "ENG") - { - qtLanguageTranslator.load(QString("translations/RRJServer_") + languageENG, "."); - language = languageENG; - } - else - { - qtLanguageTranslator.load(QString("translations/RRJServer_") + languageRUS, "."); - language = languageRUS; - } - - qApp->installTranslator(&qtLanguageTranslator); - - emit signal_LanguageChanged(language); -} +//STYLESHEET void ServerLMSWidget::updateMyStyleSheet() { @@ -355,49 +184,390 @@ QString ServerLMSWidget::loadStyleSheet() } } + +//LANGUAGE + +void ServerLMSWidget::initLanguageInterfase() +{ + ServerDBSettings settings; + DialogSettingsTray::loadSettings(&settings); + + if(settings.Language == "ENG") + { + qtLanguageTranslator.load(QString("translations/RRJServer_") + languageENG, "."); + language = languageENG; + } + else + { + qtLanguageTranslator.load(QString("translations/RRJServer_") + languageRUS, "."); + language = languageRUS; + } + + qApp->installTranslator(&qtLanguageTranslator); + + emit signal_LanguageChanged(language); +} + + +//UPDATE STATES + +void ServerLMSWidget::updateStateOnlyServer() +{ + if(state_Server == EStateServer::started) + { + if(state_BlockAutorization == EStateBlockAutorization::unblocked) + { + ui->lblOnOffText->setText(tr("started")); + ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); + } + else + { + ui->lblOnOffText->setText(tr("started") + ", " + tr("locked")); + ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/lock.png"))); + } + } + else + { + ui->lblOnOffText->setText(tr("stoped")); + ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/stoped.png"))); + } + + emit signal_Tray_UpdateStateServer(state_Server, state_BlockAutorization); +} + +void ServerLMSWidget::updateStateOnlyDB() +{ + if(state_dbIsConnected) + { + //Настройки БД + QString strDBsettings = tr("connected") + QString(" [%1 (%2) %3 : %4]").arg(state_dbSettings.dbName, + state_dbSettings.dbType, + state_dbSettings.dbHostName, + QString::number(state_dbSettings.dbPort)); + ui->lblDBsettings->setText(strDBsettings); + ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); + } + else + { + ui->lblDBsettings->setText(tr("not connected")); + ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGray.png"))); + + ui->btnStopServer->setEnabled(false); + ui->btnStartServer->setEnabled(false); + } +} + +void ServerLMSWidget::updateStateOnlyVersionMaterials() +{ + ui->lblVersionText->setText(state_VersionMaterials); +} + + +//SLOTS + +void ServerLMSWidget::slot_UpdateListClients(QStringList listFullName) +{ + //Очищаем список + ui->listWidget_Clients->clear(); + + for (const QString clientFullName : listFullName) + { + ui->listWidget_Clients->addItem(clientFullName); + ui->listWidget_Clients->scrollToBottom(); + ui->listWidget_Clients->setCurrentRow(ui->listWidget_Clients->count() - 1); + } + + int countClients = listFullName.count(); + Logger::instance().log("SERVER: countClients = " + QString::number(countClients)); +} + +void ServerLMSWidget::slot_AddMessageToLog(QString message) +{ + ui->loggerTextField->appendHtml(message); +} + +void ServerLMSWidget::slot_ErrorPostgreSQL(QString text) +{ + emit signal_Menu_ShowWindow(); + SpecMsgBox::CriticalClose(this, tr("Error PostgreSQL!") + "\n" + text); +} + +void ServerLMSWidget::slot_StateConnectionToDB(bool dbIsConnected, DataBaseSettings dbSettings) +{ + this->state_dbIsConnected = dbIsConnected; + this->state_dbSettings = dbSettings; + updateStateOnlyDB(); +} + +void ServerLMSWidget::slot_StateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization) +{ + if(this->state_Server != stateServer) + { + this->state_Server = stateServer; + this->state_BlockAutorization = stateBlockAutorization; + updateStateOnlyServer(); + + if(stateServer == EStateServer::started) + { + ui->btnStartServer->setEnabled(false); + ui->btnStopServer->setEnabled(true); + emit signal_Tray_ShowMessage(tr("Server is started!")); + } + else + { + ui->btnStopServer->setEnabled(false); + ui->btnStartServer->setEnabled(true); + emit signal_Tray_ShowMessage(tr("Server is stoped!")); + } + } + else + { + this->state_Server = stateServer; + this->state_BlockAutorization = stateBlockAutorization; + updateStateOnlyServer(); + } +} + +void ServerLMSWidget::slot_StateVersionMaterials(QString versionStr) +{ + this->state_VersionMaterials = versionStr; + updateStateOnlyVersionMaterials(); +} + +void ServerLMSWidget::slot_ResultTryConnectDb(bool result) +{ + if(flTryConnectionToDB) + { + flTryConnectionToDB = false; + + if(result) + { + //Настройки БД + DataBaseSettings dbSettings = ProviderDBLMS::getDBSettings(); + QString strDBsettings = QString("%1 (%2) %3 : %4").arg(dbSettings.dbName, + dbSettings.dbType, + dbSettings.dbHostName, + QString::number(dbSettings.dbPort)); + + Logger::instance().log("Connection to DB completed!"); + + emit signal_Tray_ShowMessage(tr("Database connection OK!") + "\n" + strDBsettings); + + on_btnStartServer_clicked(); + + if(flStartInitialization) + { + flStartInitialization = false; + startInitialization_step3(); + } + } + else + { + Logger::instance().log("Database connection error!"); + + emit signal_Tray_ShowMessage(tr("Database connection error!"), QSystemTrayIcon::Critical); + + emit signal_Menu_ShowWindow(); + + SpecMsgBox::CriticalClose(this, tr("Database connection error!")); + + on_btnSettings_clicked(); + } + } +} + +void ServerLMSWidget::slot_ResultTryDisConnectDb(bool result) +{ + if(flNeedReconnectDB) + { + flNeedReconnectDB = false; + + SpecMsgBox::WarningClose(this, tr("Database settings have been changed.\nThe server will be restarted.")); + + tryConnectionToDB(); + } +} + +void ServerLMSWidget::slot_SetError(int code) +{ + if(code == 100) + { + QString textError = tr("No Client files found!") + "\n\n" + + tr("* check Application for the presence of a folder with a build \n" + "* check SharedData for a folder with the base version and the name base"); + + SpecMsgBox::CriticalClose(this, textError); + } + errorCode = code; + emit signal_StartInitHasError(code); +} + +void ServerLMSWidget::slot_UpdateDocsCompleted() +{ + if(flTryUpdateDocs) + { + flTryUpdateDocs = false; + startInitialization_step2(); + } +} + +void ServerLMSWidget::slot_UpdateControllerInitializeFinished() +{ + startInitialization_step1(); +} + +void ServerLMSWidget::slot_BlockAutorizationIndicate(bool block, QString blocker, QString types) +{ + if(block) + { + Logger::instance().log(QString("BLOCK from: %1").arg(blocker), LogLevel::INFO); + Logger::instance().log(QString("Blockers: %1").arg(types), LogLevel::DEBUG); + } + else + { + Logger::instance().log(QString("UNBLOCK from: %1").arg(blocker), LogLevel::INFO); + Logger::instance().log(QString("Blockers: %1").arg(types), LogLevel::DEBUG); + } + updateStateOnlyServer(); +} + +void ServerLMSWidget::slot_LanguageChanged(QString language) +{ + qtLanguageTranslator.load(QString("translations/RRJServer_") + language, "."); + qApp->installTranslator(&qtLanguageTranslator); + + emit signal_LanguageChanged(language); +} + + +//ON_BTN + +void ServerLMSWidget::on_btnStartServer_clicked() +{ + emit signal_StartServer(); + + ui->btnStartServer->setEnabled(false); + ui->btnStopServer->setEnabled(true); +} + +void ServerLMSWidget::on_btnStopServer_clicked() +{ + emit signal_StopServer(); + + ui->btnStopServer->setEnabled(false); + ui->btnStartServer->setEnabled(true); +} + +void ServerLMSWidget::on_btnSettings_clicked() +{ + ServerDBSettings settingsTemp; + if(!DialogSettingsTray::loadSettings(&settingsTemp)) + { + SpecMsgBox::CriticalClose(this, tr("Settings file could not be opened:") + "'config/settings.xml'"); + return; + } + + DialogSettingsTray dlg(providerDBLMS, this); + dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(&dlg, &DialogSettingsTray::signal_LanguageChanged, this, &ServerLMSWidget::slot_LanguageChanged); + connect(&dlg, &DialogSettingsTray::signal_UpdateDocs, docsUpdater, &DocsUpdater::slot_updateDocsXML); + + switch( dlg.exec() ) + { + case QDialog::Accepted: + { + language = dlg.getSettings().Language; + + if(dlg.settingsDBisChanged()) + { + on_btnStopServer_clicked(); + + flNeedReconnectDB = true; + flTryConnectionToDB = false; + + emit signal_TryDisConnectionFromDB(); + + break; + } + + break; + } + case QDialog::Rejected: + break; + default: + break; + } +} + + +//INIT + void ServerLMSWidget::startInitialization_step0() { - QApplication::setOverrideCursor(Qt::WaitCursor); + emit signal_Tray_ShowMessage(tr("Starting the server...")); - providerDBLMS = new ProviderDBLMS(this); - connect(providerDBLMS, &ProviderDBLMS::signal_ErrorPostgreSQL, this, &ServerLMSWidget::slot_ErrorPostgreSQL); - //connect(providerDBLMS, &ProviderDBLMS::signal_BlockAutorization, this, &ServerLMSWidget::slot_BlockAutorizationIndicate); - - mutex = new QMutex; + waitAnimationWidget->showWithPlay(); updateThread = new QThread; loggerThread = new QThread; + serverThread = new QThread; + + providerDBLMS = new ProviderDBLMS(); + providerDBLMS->moveToThread(serverThread); + + connect(providerDBLMS, &ProviderDBLMS::signal_ErrorPostgreSQL, this, &ServerLMSWidget::slot_ErrorPostgreSQL); + connect(providerDBLMS, &ProviderDBLMS::signal_StateConnectionToDB, this, &ServerLMSWidget::slot_StateConnectionToDB); + connect(this, &ServerLMSWidget::signal_TryConnectionToDB, providerDBLMS, &ProviderDBLMS::slot_TryConnectionToDB); + connect(this, &ServerLMSWidget::signal_TryDisConnectionFromDB, providerDBLMS, &ProviderDBLMS::slot_TryDisConnectionFromDB); + connect(providerDBLMS, &ProviderDBLMS::signal_ResultTryConnectDb, this, &ServerLMSWidget::slot_ResultTryConnectDb); + connect(providerDBLMS, &ProviderDBLMS::signal_ResultTryDisConnectDb, this, &ServerLMSWidget::slot_ResultTryDisConnectDb); chatSystem = new ChatSystem(); + chatSystem->moveToThread(serverThread); - assetsManager = new AssetsManager; + assetsManager = new AssetsManager(); assetsManager->moveToThread(updateThread); - updateController = new UpdateController; + updateController = new UpdateController(); updateController->moveToThread(updateThread); - docsUpdater = new DocsUpdater(updateController/*, this*/); + docsUpdater = new DocsUpdater(updateController); docsUpdater->moveToThread(updateThread); - cfiController = new CfiController(updateController/*, this*/); + connect(docsUpdater, &DocsUpdater::signal_UpdateDocsCompleted, this, &ServerLMSWidget::slot_UpdateDocsCompleted); + + cfiController = new CfiController(updateController); cfiController->moveToThread(updateThread); processingSystem = new ProcessingSystem(providerDBLMS, updateController, docsUpdater, cfiController); + processingSystem->moveToThread(serverThread); - dataParser = new DataParser(assetsManager, processingSystem); + dataParser = new DataParser(processingSystem); + dataParser->moveToThread(serverThread); - commonClientHandler = new CommonClientHandler; - connect(this, &ServerLMSWidget::signal_DocsChanged, commonClientHandler, &CommonClientHandler::slot_DocsChanged); - //connect(commonClientHandler, &CommonClientHandler::sigSetServerState, this, &ServerLMSWidget::slot_trySetServerState); + commonClientHandler = new CommonClientHandler(); + commonClientHandler->moveToThread(serverThread); + + connect(docsUpdater, &DocsUpdater::signal_DocsChanged, commonClientHandler, &CommonClientHandler::slot_DocsChanged); + + server = new MultiThreadServer(updateController, docsUpdater, processingSystem, dataParser, 6000); + server->moveToThread(serverThread); + + connect(server, &MultiThreadServer::signal_StateServer, this, &ServerLMSWidget::slot_StateServer); + connect(server, &MultiThreadServer::signal_UpdateListClients, this, &ServerLMSWidget::slot_UpdateListClients); + + connect(this, &ServerLMSWidget::signal_StartServer, server, &MultiThreadServer::slot_StartServer); + connect(this, &ServerLMSWidget::signal_StopServer, server, &MultiThreadServer::slot_StopServer); - server = new MultiThreadServer(this, updateController, processingSystem, dataParser, 6000); connect(server, &MultiThreadServer::signal_BlockAutorizationIndicate, this, &ServerLMSWidget::slot_BlockAutorizationIndicate); - connect(providerDBLMS, &ProviderDBLMS::signal_BlockAutorization, server, &MultiThreadServer::slot_BlockAutorization/*, Qt::DirectConnection*/); - connect(updateController, &UpdateController::signal_BlockAutorization, server, &MultiThreadServer::slot_BlockAutorization/*, Qt::DirectConnection*/); + connect(providerDBLMS, &ProviderDBLMS::signal_BlockAutorization, server, &MultiThreadServer::slot_BlockAutorization, Qt::DirectConnection /*Тут именно DirectConnection! Не менять!*/); + connect(updateController, &UpdateController::signal_BlockAutorization, server, &MultiThreadServer::slot_BlockAutorization, Qt::DirectConnection /*Тут именно DirectConnection! Не менять!*/); connect(server, &MultiThreadServer::signal_sendPacketToAllClients, commonClientHandler, &CommonClientHandler::slot_sendPacketToAllClients); loggerThread->start(); updateThread->start(); + serverThread->start(); commonClientHandler->initialize(server->getClientsMap(), processingSystem, dataParser); processingSystem->initialize(server, dataParser, commonClientHandler, updateController, chatSystem); @@ -407,107 +577,60 @@ void ServerLMSWidget::startInitialization_step0() Logger::instance().setLoggingType(LoggingType::WIDGET); Logger::instance().setLogToFile(true); - connect(this, &ServerLMSWidget::sigUpdateControllerInitialize, updateController, &UpdateController::initialize); - connect(updateController, &UpdateController::sigInitializeFinished, this, &ServerLMSWidget::slot_startInitialization_step1); - connect(this, &ServerLMSWidget::sigCalculateFullHash, updateController, &UpdateController::calculateFullHash, Qt::AutoConnection); - connect(updateController, &UpdateController::sigErrorRequired, this, &ServerLMSWidget::setError); - connect(updateController, &UpdateController::sigUpdateDocs, this, &ServerLMSWidget::slot_UpdateDocs, Qt::AutoConnection); + connect(this, &ServerLMSWidget::signal_UpdateControllerInitialize, updateController, &UpdateController::initialize); + connect(updateController, &UpdateController::sigInitializeFinished, this, &ServerLMSWidget::slot_UpdateControllerInitializeFinished); + connect(updateController, &UpdateController::sigErrorRequired, this, &ServerLMSWidget::slot_SetError); + connect(updateController, &UpdateController::sigUpdateDocsXML, docsUpdater, &DocsUpdater::slot_updateDocsXML); connect(&Logger::instance(), &Logger::sigLogToWidget, this, &ServerLMSWidget::slot_AddMessageToLog, Qt::QueuedConnection); - connect(assetsManager, &AssetsManager::signal_setVersion, this, &ServerLMSWidget::slot_setVersion); + connect(assetsManager, &AssetsManager::signal_setVersion, this, &ServerLMSWidget::slot_StateVersionMaterials); - emit sigUpdateControllerInitialize(commonClientHandler, dataParser, assetsManager); + connect(this, &ServerLMSWidget::signal_UpdateDocsXML, docsUpdater, &DocsUpdater::slot_updateDocsXML); + + emit signal_UpdateControllerInitialize(commonClientHandler, assetsManager); } +void ServerLMSWidget::startInitialization_step1() +{ + if(errorCode == 100) + return; + + Logger::instance().log("Update docs.xml..."); + flTryUpdateDocs = true; + emit signal_UpdateDocsXML(); +} + +void ServerLMSWidget::startInitialization_step2() +{ + Logger::instance().log("Update docs.xml completed!"); + + ui->btnStopServer->setEnabled(false); + ui->btnStartServer->setEnabled(true); + + flStartInitialization = true; + + updateStateOnlyServer(); + updateStateOnlyDB(); + updateStateOnlyVersionMaterials(); + + Logger::instance().log("Try connection to DB..."); + tryConnectionToDB(); +} + +void ServerLMSWidget::startInitialization_step3() +{ + waitAnimationWidget->hideWithStop(); + + emit signal_StartInitFinished(); +} + + +//CONNECT DB + void ServerLMSWidget::tryConnectionToDB() { - if(! providerDBLMS->ConnectionToDB()) - { - Logger::instance().log("Database connection error!"); - - emit signal_Tray_ShowMessage(tr("Database connection error!"), QSystemTrayIcon::Critical); - - emit signal_Menu_ShowWindow(); - - SpecMsgBox::CriticalClose(this, tr("Database connection error!")); - - on_btnSettings_clicked(); - } - else - { - providerDBLMS->deAuthorizationAll(); - - //Настройки БД - DataBaseSettings dbSettings = providerDBLMS->getDBSettings(); - QString strDBsettings = QString("%1 (%2) %3 : %4").arg(dbSettings.dbName, - dbSettings.dbType, - dbSettings.dbHostName, - QString::number(dbSettings.dbPort)); - - Logger::instance().log("Connection to DB completed!"); - - emit signal_Tray_ShowMessage(tr("Database connection OK!") + "\n" + strDBsettings); - - on_btnStartServer_clicked(); - } - - updateStateOnlyDB(); -} - -void ServerLMSWidget::updateStateOnlyServer() -{ - if(server) - { - if(server->getStateServer() == EStateServer::started) - { - if(server->getStateBlockAutorization() == EStateBlockAutorization::unblocked) - { - ui->lblOnOffText->setText(tr("started")); - ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); - } - else - { - ui->lblOnOffText->setText(tr("started") + ", " + tr("locked")); - ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/lock.png"))); - } - } - else - { - ui->lblOnOffText->setText(tr("stoped")); - ui->lblOnOff->setPixmap(QPixmap(QStringLiteral(":/resources/icons/stoped.png"))); - } - - emit signal_updateStateServer(server->getStateServer(), server->getStateBlockAutorization()); - } -} - -void ServerLMSWidget::updateStateOnlyDB() -{ - if(providerDBLMS) - { - if(providerDBLMS->DBisConnected()) - { - //Настройки БД - DataBaseSettings dbSettings = providerDBLMS->getDBSettings(); - QString strDBsettings = tr("connected") + QString(" [%1 (%2) %3 : %4]").arg(dbSettings.dbName, - dbSettings.dbType, - dbSettings.dbHostName, - QString::number(dbSettings.dbPort)); - ui->lblDBsettings->setText(strDBsettings); - ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); - } - else - { - ui->lblDBsettings->setText(tr("not connected")); - ui->lblDBisConnected->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGray.png"))); - - ui->btnStopServer->setEnabled(false); - ui->btnStartServer->setEnabled(false); - } - } -} - -void ServerLMSWidget::updateStateOnlyVersion() -{ - ui->lblVersionText->setText(versionStr); + flTryConnectionToDB = true; + flNeedReconnectDB = false; + emit signal_TryConnectionToDB(); + return; } diff --git a/LibServer/serverlmswidget.h b/LibServer/serverlmswidget.h index 4ba16e2..49071ff 100644 --- a/LibServer/serverlmswidget.h +++ b/LibServer/serverlmswidget.h @@ -1,36 +1,25 @@ #ifndef SERVERLMSWIDGET_H #define SERVERLMSWIDGET_H -#include "ServerLMS_global.h" - #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "multithreadserver.h" -#include "providerdblms.h" -#include "docsupdater.h" +#include "ServerLMS_global.h" +#include "logger.h" #include "waitanimationwidget.h" #include "specialmessagebox.h" +#include "Parsers/dataparser.h" +#include "processingsystem.h" +#include "updatecontroller.h" +#include "assetsmanager.h" +#include "commonclienthandler.h" +#include "assetsmanager.h" +#include "multithreadserver.h" +#include "providerdblms.h" +#include "docsupdater.h" #include "cficontroller.h" @@ -39,11 +28,9 @@ class ServerLMSWidget; } class DataParser; -class SendSystem; class ProcessingSystem; class Logger; class UpdateController; -class RecognizeSystem; class ClientHandler; class MultiThreadServer; class AssetsManager; @@ -51,114 +38,99 @@ class ChatSystem; class DocsUpdater; class CfiController; + class SERVERLMS_EXPORT ServerLMSWidget : public QWidget { Q_OBJECT -public: - explicit ServerLMSWidget(QWidget *parent = nullptr); - ~ServerLMSWidget(); - - void start(); - public: static const QString languageENG; static const QString languageRUS; -protected: - // Метод получения событий - // В нём будет производиться проверка события смены перевода приложения - void changeEvent(QEvent * event) override; +public: + explicit ServerLMSWidget(QWidget *parent = nullptr); + ~ServerLMSWidget(); +public: + //INTERFACE + void startInitialization(); + QString getLanguage(); + +protected: + //EVENT + void changeEvent(QEvent * event) override; void resizeEvent(QResizeEvent *event) override; signals: + //MAINWINDOW, ТРЕЙ //сигнал смены языка void signal_LanguageChanged(QString language); - //сигнал вывода сообщения из трея void signal_Tray_ShowMessage(QString textMsg, QSystemTrayIcon::MessageIcon iconMsg = QSystemTrayIcon::Information); - + //синал обновления состояния сервера (иконка в трее) + void signal_Tray_UpdateStateServer(EStateServer state_Server, EStateBlockAutorization state_BlockAutorization); + //сигналы меню трея void signal_Menu_ShowWindow(); void signal_Menu_HideWindow(); + //сигнал о наличии ошибок начальной инициализации + void signal_StartInitHasError(int code); + //сигнал об окончании начальной инициализации + void signal_StartInitFinished(); - void sigRecognize(); - void sigCalculateFullHash(); - void sigUpdateControllerInitialize(CommonClientHandler* commonClientHandler,DataParser *dataParser,AssetsManager *assetManager); + //Для инициализации + void signal_UpdateControllerInitialize(CommonClientHandler* commonClientHandler,AssetsManager *assetManager); + void signal_UpdateDocsXML(); - void signal_DocsChanged(); - void signal_hasError(int code); + //Соединение с БД + void signal_TryConnectionToDB(); + void signal_TryDisConnectionFromDB(); - void signal_updateStateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization); + //Сервер + void signal_StartServer(); + void signal_StopServer(); public slots: + //ИНДИКАЦИЯ void slot_LanguageChanged(QString language); - void slot_UpdateListClients(); + void slot_UpdateListClients(QStringList listFullName); void slot_BlockAutorizationIndicate(bool block, QString blocker, QString types); void slot_AddMessageToLog(QString message); - void slot_ErrorPostgreSQL(QString text); + void slot_StateConnectionToDB(bool state_dbIsConnected, DataBaseSettings state_dbSettings); + void slot_StateServer(EStateServer state_Server, EStateBlockAutorization state_BlockAutorization); + void slot_StateVersionMaterials(QString state_VersionMaterials); - void slot_UpdateDocs(); + //Для инициализации + void slot_UpdateControllerInitializeFinished(); + void slot_UpdateDocsCompleted(); + void slot_SetError(int code); - void slot_startInitialization_step1(); - - void slot_setVersion(QString versionStr); - -public: - QString getLanguage() - { - return language; - } - - void setError(int code) - { - if(code == 100) - { - QString textError = tr("No Client files found!") + "\n\n" + - tr("* check Application for the presence of a folder with a build \n" - "* check SharedData for a folder with the base version and the name base"); - - SpecMsgBox::CriticalClose(this, textError); - } - errorCode = code; - emit signal_hasError(code); - } - - int hasError() const - { - return errorCode; - } - - ProcessingSystem* getProcessingSystem() - { - return processingSystem; - } - - QMutex *getMutex() const - { - return mutex; - } - - void removeClient(int socketId); + //Соединение с БД + void slot_ResultTryConnectDb(bool result); + void slot_ResultTryDisConnectDb(bool result); private slots: void on_btnStartServer_clicked(); void on_btnStopServer_clicked(); void on_btnSettings_clicked(); -private: - void setLanguageInterfase(); +private: void updateMyStyleSheet(); QString loadStyleSheet(); + void initLanguageInterfase(); - void startInitialization_step0(); - - void tryConnectionToDB(); - +private: void updateStateOnlyServer(); void updateStateOnlyDB(); - void updateStateOnlyVersion(); + void updateStateOnlyVersionMaterials(); + +private: + //Для инициализации + void startInitialization_step0(); + void startInitialization_step1(); + void startInitialization_step2(); + void startInitialization_step3(); + void tryConnectionToDB(); private: Ui::ServerLMSWidget *ui; @@ -166,31 +138,37 @@ private: private: WaitAnimationWidget *waitAnimationWidget; - MultiThreadServer *server; QThread *updateThread; QThread *loggerThread; - QMutex *mutex; + QThread *serverThread; - DataParser *dataParser; - ProcessingSystem *processingSystem; - UpdateController *updateController; - AssetsManager *assetsManager; - CommonClientHandler *commonClientHandler; - ChatSystem *chatSystem; + MultiThreadServer *server; //serverThread + DataParser *dataParser; //serverThread + ProcessingSystem *processingSystem; //serverThread + CommonClientHandler *commonClientHandler; //serverThread + ChatSystem *chatSystem; //serverThread + ProviderDBLMS* providerDBLMS; //serverThread - DocsUpdater* docsUpdater; - CfiController* cfiController; - ProviderDBLMS* providerDBLMS; - - bool first = true; // для тестов Unity + UpdateController *updateController; //updateThread + AssetsManager *assetsManager; //updateThread + DocsUpdater* docsUpdater; //updateThread + CfiController* cfiController; //updateThread QTranslator qtLanguageTranslator; QString language; + int errorCode; - QString versionStr; + QString state_VersionMaterials; + bool state_dbIsConnected; + DataBaseSettings state_dbSettings; + EStateServer state_Server; + EStateBlockAutorization state_BlockAutorization; bool flStartInitialization; + bool flTryConnectionToDB; + bool flNeedReconnectDB; + bool flTryUpdateDocs; }; #endif // SERVERLMSWIDGET_H diff --git a/LibServer/settings/dialogcheckdb.cpp b/LibServer/settings/dialogcheckdb.cpp index 5a3810b..6d1c159 100644 --- a/LibServer/settings/dialogcheckdb.cpp +++ b/LibServer/settings/dialogcheckdb.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "specialmessagebox.h" #include "dialogcheckdb.h" #include "ui_dialogcheckdb.h" @@ -8,33 +9,78 @@ DialogCheckDB::DialogCheckDB(ProviderDBLMS* providerDBLMS, QWidget *parent) : QDialog(parent), ui(new Ui::DialogCheckDB), - providerDBLMS(providerDBLMS), - resDriver(false), - resUser(false), - resDB(false) + waitAnimationWidget(nullptr), + providerDBLMS(providerDBLMS) { ui->setupUi(this); + connect(this, &DialogCheckDB::signal_CheckDB, providerDBLMS, &ProviderDBLMS::slot_CheckDB); + connect(providerDBLMS, &ProviderDBLMS::signal_CheckDBResult, this, &DialogCheckDB::slot_CheckDBResult); + + connect(this, &DialogCheckDB::signal_RepareDB, providerDBLMS, &ProviderDBLMS::slot_RepareDB); + connect(providerDBLMS, &ProviderDBLMS::signal_RepareDBResult, this, &DialogCheckDB::slot_RepareDBResult); + + + waitAnimationWidget = new WaitAnimationWidget; + QMovie *movie = new QMovie(":/resources/icons/762.gif"); + waitAnimationWidget->setParent(this); + waitAnimationWidget->initialize(movie,this); + ui->btnRepare->setObjectName("btnRepare"); - ui->btnRepare->setEnabled(false); - - check(); + ui->btnRepare->setEnabled(false); } DialogCheckDB::~DialogCheckDB() { + if(waitAnimationWidget) + { + waitAnimationWidget->hideWithStop(); + delete waitAnimationWidget; + } + delete ui; } +void DialogCheckDB::initialize() +{ + check(); +} + +void DialogCheckDB::resizeEvent(QResizeEvent *event) +{ + QSize size = event->size(); + waitAnimationWidget->resize(size); +} + void DialogCheckDB::check() { - resDriver = false; - resUser = false; - resDB = false; + waitAnimationWidget->showWithPlay(); - resDriver = providerDBLMS->checkDriverQPSQLavailable(); - if(resDriver) + emit signal_CheckDB(); + + return; +} + +void DialogCheckDB::on_btnRepare_clicked() +{ + waitAnimationWidget->showWithPlay(); + + if(!checkResult.resDriver) + { + SpecMsgBox::CriticalClose(this, tr("Install PostgreSQL.")); + this->reject(); + return; + } + + emit signal_RepareDB(checkResult); +} + +void DialogCheckDB::slot_CheckDBResult(CheckResult result) +{ + checkResult = result; + + if(result.resDriver) { ui->lblDriverRes->setText(tr("Installed")); ui->lblDriverResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); @@ -45,8 +91,7 @@ void DialogCheckDB::check() ui->lblDriverResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleRed.png"))); } - resUser = providerDBLMS->checkUserLMSexist(); - if(resUser) + if(result.resUser) { ui->lblUserRes->setText(tr("Exist")); ui->lblUserResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); @@ -57,8 +102,7 @@ void DialogCheckDB::check() ui->lblUserResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleRed.png"))); } - resDB = providerDBLMS->checkDataBaseLMSexist(); - if(resDB) + if(result.resDB) { ui->lblDBRes->setText(tr("Exist")); ui->lblDBResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleGreen.png"))); @@ -69,48 +113,39 @@ void DialogCheckDB::check() ui->lblDBResIco->setPixmap(QPixmap(QStringLiteral(":/resources/icons/circleRed.png"))); } - if(!resDriver || !resUser || !resDB) + if(!result.resDriver || !result.resUser || !result.resDB) { ui->btnRepare->setEnabled(true); } else ui->btnRepare->setEnabled(false); + + waitAnimationWidget->hideWithStop(); } -void DialogCheckDB::on_btnRepare_clicked() +void DialogCheckDB::slot_RepareDBResult(CheckResult result) { - if(!resDriver) + checkResult = result; + + if(!checkResult.resUser) { - SpecMsgBox::CriticalClose(this, tr("Install PostgreSQL.")); + slot_CheckDBResult(checkResult); + SpecMsgBox::CriticalClose(this, tr("Failed to create user!")); this->reject(); return; } - if(!resUser) + if(!checkResult.resDB) { - if(!providerDBLMS->createUser()) - { - check(); - SpecMsgBox::CriticalClose(this, tr("Failed to create user!")); - this->reject(); - return; - } - } - - if(!resDB) - { - if(!providerDBLMS->createDB()) - { - check(); - SpecMsgBox::CriticalClose(this, tr("Failed to create Database!")); - this->reject(); - return; - } + slot_CheckDBResult(checkResult); + SpecMsgBox::CriticalClose(this, tr("Failed to create Database!")); + this->reject(); + return; } check(); - if(resDriver && resUser && resDB) + if(checkResult.resDriver && checkResult.resUser && checkResult.resDB) { SpecMsgBox::InfoOk(this, tr("The database has been successfully restored!")); this->accept(); diff --git a/LibServer/settings/dialogcheckdb.h b/LibServer/settings/dialogcheckdb.h index 5eeef36..80720f7 100644 --- a/LibServer/settings/dialogcheckdb.h +++ b/LibServer/settings/dialogcheckdb.h @@ -3,6 +3,7 @@ #include #include "providerdblms.h" +#include "waitanimationwidget.h" namespace Ui { class DialogCheckDB; @@ -16,9 +17,22 @@ public: explicit DialogCheckDB(ProviderDBLMS* providerDBLMS, QWidget *parent = nullptr); ~DialogCheckDB(); + void initialize(); + +protected: + void resizeEvent(QResizeEvent *event) override; + private slots: void on_btnRepare_clicked(); +signals: + void signal_CheckDB(); + void signal_RepareDB(CheckResult result); + +public slots: + void slot_CheckDBResult(CheckResult result); + void slot_RepareDBResult(CheckResult result); + private: void check(); void prepareRestoreDBscript(); @@ -26,11 +40,11 @@ private: private: Ui::DialogCheckDB *ui; + WaitAnimationWidget *waitAnimationWidget; + ProviderDBLMS* providerDBLMS; - bool resDriver; - bool resUser; - bool resDB; + CheckResult checkResult; }; #endif // DIALOGCHECKDB_H diff --git a/LibServer/settings/dialogsettingstray.cpp b/LibServer/settings/dialogsettingstray.cpp index 07250f9..67a44a8 100644 --- a/LibServer/settings/dialogsettingstray.cpp +++ b/LibServer/settings/dialogsettingstray.cpp @@ -24,7 +24,13 @@ DialogSettingsTray::DialogSettingsTray(ProviderDBLMS* providerDBLMS, QWidget *pa #ifndef PROJECT_TYPE_DEBUG ui->checkLocalhost->setEnabled(false); ui->btnUpdateDocs->setVisible(false); -#endif +#endif + +#ifdef PROJECT_TYPE_DEBUG + ui->editNameDB->setEnabled(true); + ui->editUserName->setEnabled(true); + ui->editPassword->setEnabled(true); +#endif /* Создаем строку для регулярного выражения */ QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])"; @@ -298,7 +304,7 @@ void DialogSettingsTray::on_checkLocalhost_stateChanged(int arg1) void DialogSettingsTray::on_btnCheckDB_clicked() { //Проверяем, установлен ли PostgreSQL - if(!providerDBLMS->checkDriverQPSQLavailable()) + if(!ProviderDBLMS::checkDriverQPSQLavailable()) { SpecMsgBox::CriticalClose(this, tr("Driver PostgreSQL is not installed!")); return; @@ -332,10 +338,11 @@ void DialogSettingsTray::on_btnCheckDB_clicked() return; } - if(providerDBLMS->setUserPasswordPostgres(UserNamePostgres, PasswordPostgres)) + if(ProviderDBLMS::setUserPasswordPostgres(UserNamePostgres, PasswordPostgres)) { DialogCheckDB dlgCheckDB(providerDBLMS, this); dlgCheckDB.setWindowFlags(dlgCheckDB.windowFlags() & ~Qt::WindowContextHelpButtonHint); + dlgCheckDB.initialize(); switch( dlgCheckDB.exec() ) { diff --git a/ProgramServerMTD/CMakeLists.txt b/ProgramServerMTD/CMakeLists.txt index a8c2a74..cbd2254 100644 --- a/ProgramServerMTD/CMakeLists.txt +++ b/ProgramServerMTD/CMakeLists.txt @@ -51,3 +51,9 @@ target_include_directories(ServerMTD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../LibIn target_include_directories(ServerMTD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../LibInstructorsAndTrainees/tasks) target_include_directories(ServerMTD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../LibInstructorsAndTrainees/widgets) target_include_directories(ServerMTD PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../LibInstructorsAndTrainees/specialmessagebox) +if(PROJECT_TYPE_DEBUG) + target_link_directories(ServerMTD PUBLIC ${REPO_PATH}/BUILDS/Debug64/LibInstructorsAndTrainees) +else() + target_link_directories(ServerMTD PUBLIC ${REPO_PATH}/BUILDS/Release64/LibInstructorsAndTrainees) +endif() +target_link_libraries(ServerMTD PRIVATE libInstructorsAndTrainees.dll) diff --git a/ProgramServerMTD/main.cpp b/ProgramServerMTD/main.cpp index 231509a..e2c6c53 100644 --- a/ProgramServerMTD/main.cpp +++ b/ProgramServerMTD/main.cpp @@ -1,11 +1,109 @@ #include "mainwindow.h" #include +#include + +#include "specialmessagebox.h" + + +bool appIsRunningAlready(QSharedMemory& sharedMemory); +QString getLanguageFromSettings(); + int main(int argc, char *argv[]) { QApplication a(argc, argv); + + // Уникальное имя для идентификации процесса + const QString sharedMemKey = "ServerMTD_sharedMemKey"; + // Создание объекта общей памяти + QSharedMemory sharedMemory(sharedMemKey); + + if(appIsRunningAlready(sharedMemory)) + {//Приложение уже запущено + return 1; + } + MainWindow w; + w.initialize(); w.show(); //Закоментировать, если нужно, чтобы по-умолчанию было свернуто в трее! return a.exec(); } + + +bool appIsRunningAlready(QSharedMemory& sharedMemory) +{ + // Попытка прикрепления к существующему сегменту + if (sharedMemory.attach(QSharedMemory::ReadWrite)) + { + qWarning() << "Application is running already!"; + + QTranslator qtLanguageTranslator; + QString language; + language = getLanguageFromSettings(); + if(language == "RUS") + qtLanguageTranslator.load(QString("translations/RRJServer_") + "ru_RU", "."); + qApp->installTranslator(&qtLanguageTranslator); + SpecMsgBox::CriticalClose(nullptr, QObject::tr("Application ") + QObject::tr("Maintenance training device RRJ-95NEW-100 Server") + QObject::tr(" is running already!")); + + return true; + } + else + { + // Приложения ещё нет, создаём сегмент памяти + if (!sharedMemory.create(1)) + { + qCritical() << "Application launch error! Error create shared memory."; + + QTranslator qtLanguageTranslator; + QString language; + language = getLanguageFromSettings(); + if(language == "RUS") + qtLanguageTranslator.load(QString("translations/RRJServer_") + "ru_RU", "."); + qApp->installTranslator(&qtLanguageTranslator); + SpecMsgBox::CriticalClose(nullptr, QObject::tr("Application ") + QObject::tr("Maintenance training device RRJ-95NEW-100 Server") + QObject::tr(" launch error! ") + QObject::tr(" Error create shared memory.") + + QObject::tr(" Contact your system administrator.")); + + return true; + } + } + + // Освобождаем общую память при завершении работы приложения + QObject::connect(qApp, &QCoreApplication::aboutToQuit, + [&]() { sharedMemory.detach(); }); + + return false; +} + +QString getLanguageFromSettings() +{ + QFile file(settingsName); + if(! file.open(QIODevice::ReadOnly)) + return ""; + + QXmlStreamReader xmlReader(&file); + + while (!xmlReader.atEnd()) + { + if(xmlReader.isStartElement()) + { + if(xmlReader.name() == "DataBaseSettings") + { + foreach(const QXmlStreamAttribute &attr, xmlReader.attributes()) + { + QString name = attr.name().toString(); + QString value = attr.value().toString(); + + if(name == "Language") + { + file.close(); + return value; + } + } + } + } + xmlReader.readNext(); + } + file.close(); + return ""; +} diff --git a/ProgramServerMTD/mainwindow.cpp b/ProgramServerMTD/mainwindow.cpp index dd8c82c..56947c9 100644 --- a/ProgramServerMTD/mainwindow.cpp +++ b/ProgramServerMTD/mainwindow.cpp @@ -14,41 +14,44 @@ MainWindow::MainWindow(QWidget *parent) : trayMenu(nullptr), action_ShowWindow(nullptr), action_HideWindow(nullptr), - action_Exit(nullptr) + action_Exit(nullptr), + flInitServerLMSWidget(false) { ui->setupUi(this); + + qDebug() << "MainWindow init thread ID " << QThread::currentThreadId(); + setWindowFlags(windowFlags() & ~Qt::WindowMinimizeButtonHint); serverLMSWidget = new ServerLMSWidget(this); - ui->verticalLayout_Main->addWidget(serverLMSWidget); - - connect(serverLMSWidget, &ServerLMSWidget::signal_hasError, this, &MainWindow::slot_hasError); + connect(serverLMSWidget, &ServerLMSWidget::signal_StartInitFinished, this, &MainWindow::slot_InitializeFinished); + connect(serverLMSWidget, &ServerLMSWidget::signal_StartInitHasError, this, &MainWindow::slot_InitializeHasError); connect(serverLMSWidget, &ServerLMSWidget::signal_LanguageChanged, this, &MainWindow::slot_LanguageChanged); + connect(serverLMSWidget, &ServerLMSWidget::signal_Tray_UpdateStateServer, this, &MainWindow::slot_UpdateStateServer); connect(serverLMSWidget, &ServerLMSWidget::signal_Tray_ShowMessage, this, &MainWindow::slot_Tray_ShowMessage); connect(serverLMSWidget, &ServerLMSWidget::signal_Menu_ShowWindow, this, &MainWindow::slot_TrayMenu_ShowWindow); connect(serverLMSWidget, &ServerLMSWidget::signal_Menu_HideWindow, this, &MainWindow::slot_TrayMenu_HideWindow); - connect(serverLMSWidget, &ServerLMSWidget::signal_updateStateServer, this, &MainWindow::slot_updateStateServer); - qtLanguageTranslator.load(QString("translations/RRJServer_") + serverLMSWidget->getLanguage(), "."); qApp->installTranslator(&qtLanguageTranslator); - /* Инициализируем иконку трея, устанавливаем иконку, - * а также задаем всплывающую подсказку - * */ + /* Инициализируем иконку трея, устанавливаем иконку*/ trayIcon = new QSystemTrayIcon(this); - //trayIcon->setIcon(this->style()->standardIcon(QStyle::SP_ComputerIcon)); trayIcon->setIcon(QPixmap(":/resources/PngServerRRJ_stop.png")); - /* После чего создаем контекстное меню для иконки трея*/ + /* Подключаем сигнал нажатия на иконку*/ + connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::slot_TrayIconActivated); + /* Подключаем сигнал нажатия на всплывающее сообщение*/ + connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &MainWindow::slot_TrayMessageClicked); + + /* Создаем контекстное меню для иконки трея*/ trayMenu = new QMenu(this); action_ShowWindow = new QAction(this); action_HideWindow = new QAction(this); action_Exit = new QAction(this); - /* подключаем сигналы нажатий на пункты меню к соответсвующим слотам. - * */ + /* Подключаем сигналы нажатий на пункты меню к соответсвующим слотам.*/ connect(action_ShowWindow, &QAction::triggered, this, &MainWindow::slot_TrayMenu_ShowWindow); connect(action_HideWindow, &QAction::triggered, this, &MainWindow::slot_TrayMenu_HideWindow); connect(action_Exit, &QAction::triggered, this, &MainWindow::slot_TrayMenu_Exit); @@ -65,9 +68,7 @@ MainWindow::MainWindow(QWidget *parent) : trayIcon->setContextMenu(trayMenu); trayIcon->show(); - slot_Tray_ShowMessage(tr("Starting the server...")); - - QTimer::singleShot(1000, this, &MainWindow::slot_LazyInitialization); + ui->verticalLayout_Main->addWidget(serverLMSWidget); } MainWindow::~MainWindow() @@ -81,8 +82,6 @@ MainWindow::~MainWindow() delete ui; } -/* Метод, который обрабатывает событие закрытия окна приложения - * */ void MainWindow::closeEvent(QCloseEvent * event) { /* Если окно видимо, то завершение приложения @@ -91,7 +90,11 @@ void MainWindow::closeEvent(QCloseEvent * event) if(this->isVisible()) { event->ignore(); - slot_TrayMenu_HideWindow(); + + if(flInitServerLMSWidget) + {//Не даем свернуть окно, пока не прошла инициализация serverLMSWidget + slot_TrayMenu_HideWindow(); + } } } @@ -107,51 +110,64 @@ void MainWindow::changeEvent(QEvent *event) } } -/* Метод, который обрабатывает нажатие на иконку приложения в трее - * */ +void MainWindow::initialize() +{ + serverLMSWidget->startInitialization(); +} + void MainWindow::slot_TrayIconActivated(QSystemTrayIcon::ActivationReason reason) { - switch (reason){ - case QSystemTrayIcon::Trigger: - /* если окно видимо, то оно скрывается, - * и наоборот, если скрыто, то разворачивается на экран - * */ + if(flInitServerLMSWidget) + { + switch (reason){ + case QSystemTrayIcon::Trigger: + /* если окно видимо, то оно скрывается, + * и наоборот, если скрыто, то разворачивается на экран + * */ + if(!this->isVisible()) + { + slot_TrayMenu_ShowWindow(); + } + else + { + slot_TrayMenu_HideWindow(); + } + break; + default: + break; + } + } +} + +void MainWindow::slot_TrayMessageClicked() +{ + if(flInitServerLMSWidget) + { if(!this->isVisible()) { slot_TrayMenu_ShowWindow(); } - else - { - slot_TrayMenu_HideWindow(); - } - break; - default: - break; - } -} - -/* Метод, который обрабатывает нажатие на сообщение из трея - * */ -void MainWindow::slot_TrayMessageClicked() -{ - if(!this->isVisible()) - { - slot_TrayMenu_ShowWindow(); } } void MainWindow::slot_TrayMenu_ShowWindow() { - this->show(); - action_ShowWindow->setEnabled(false); - action_HideWindow->setEnabled(true); + if(flInitServerLMSWidget) + { + this->show(); + action_ShowWindow->setEnabled(false); + action_HideWindow->setEnabled(true); + } } void MainWindow::slot_TrayMenu_HideWindow() { - this->hide(); - action_ShowWindow->setEnabled(true); - action_HideWindow->setEnabled(false); + if(flInitServerLMSWidget) + { + this->hide(); + action_ShowWindow->setEnabled(true); + action_HideWindow->setEnabled(false); + } } void MainWindow::slot_TrayMenu_Exit() @@ -166,7 +182,7 @@ void MainWindow::slot_Tray_ShowMessage(QString textMsg, QSystemTrayIcon::Message trayIcon->showMessage(tr("Server MTD"), textMsg, icon, 100); } -void MainWindow::slot_updateStateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization) +void MainWindow::slot_UpdateStateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization) { if(stateServer == EStateServer::started) { @@ -185,23 +201,18 @@ void MainWindow::slot_updateStateServer(EStateServer stateServer, EStateBlockAut } } -void MainWindow::slot_LazyInitialization() +void MainWindow::slot_InitializeHasError(int code) { - serverLMSWidget->start(); - - /* Также подключаем сигнал нажатия на иконку к обработчику - * данного нажатия - * */ - connect(trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::slot_TrayIconActivated); - /* Также подключаем сигнал нажатия на всплывающее сообщение к обработчику - * данного нажатия - * */ - connect(trayIcon, &QSystemTrayIcon::messageClicked, this, &MainWindow::slot_TrayMessageClicked); + if(code == 100) + { + slot_TrayMenu_ShowWindow(); + slot_TrayMenu_Exit(); + } } -void MainWindow::slot_hasError(int code) +void MainWindow::slot_InitializeFinished() { - errorCheck(); + flInitServerLMSWidget = true; } void MainWindow::slot_LanguageChanged(QString language) @@ -210,21 +221,6 @@ void MainWindow::slot_LanguageChanged(QString language) qApp->installTranslator(&qtLanguageTranslator); } -void MainWindow::exit() -{ - QApplication::exit(0); -} - -void MainWindow::errorCheck() -{ - if(serverLMSWidget->hasError() == 100) - { - slot_TrayMenu_ShowWindow(); - - //выключение с задержкой, так как eventLoop инициализируется позже - QTimer::singleShot(1000, this, &MainWindow::slot_TrayMenu_Exit); - } -} void MainWindow::updateTrayTitles() { diff --git a/ProgramServerMTD/mainwindow.h b/ProgramServerMTD/mainwindow.h index 191d9ff..38f795c 100644 --- a/ProgramServerMTD/mainwindow.h +++ b/ProgramServerMTD/mainwindow.h @@ -24,16 +24,10 @@ public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); -protected: - /* Метод получения событий в главном окне приложения - * В нём будет производиться проверка события смены перевода приложения - */ - void changeEvent(QEvent * event) override; + void initialize(); - /* Виртуальная функция родительского класса в нашем классе - * переопределяется для изменения поведения приложения, - * чтобы оно сворачивалось в трей, когда мы этого хотим - */ +protected: + void changeEvent(QEvent * event) override; void closeEvent(QCloseEvent * event) override; public slots: @@ -52,17 +46,14 @@ public slots: //Слот вывода сообщения из трея void slot_Tray_ShowMessage(QString textMsg, QSystemTrayIcon::MessageIcon iconMsg = QSystemTrayIcon::Information); + //Слот изменения иконки трея о статусе Сервера - void slot_updateStateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization); + void slot_UpdateStateServer(EStateServer stateServer, EStateBlockAutorization stateBlockAutorization); - //Слот отложенной инициализации - void slot_LazyInitialization(); - - void slot_hasError(int code); + void slot_InitializeHasError(int code); + void slot_InitializeFinished(); private: - void exit(); - void errorCheck(); void updateTrayTitles(); private: @@ -76,5 +67,7 @@ private: QAction * action_ShowWindow; QAction * action_HideWindow; QAction * action_Exit; + + bool flInitServerLMSWidget; }; #endif // MAINWINDOW_H diff --git a/translations/RRJServer_ru_RU.qm b/translations/RRJServer_ru_RU.qm index 76bba9d..0622911 100644 Binary files a/translations/RRJServer_ru_RU.qm and b/translations/RRJServer_ru_RU.qm differ diff --git a/translations/RRJServer_ru_RU.ts b/translations/RRJServer_ru_RU.ts index f5ab72f..48d6dfa 100644 --- a/translations/RRJServer_ru_RU.ts +++ b/translations/RRJServer_ru_RU.ts @@ -34,56 +34,56 @@ Удалить - + actual актуально - + update required требуется обновление - - + + DM code DM код - - + + ID ID - - + + Procedure AMM Процедура AMM - - + + Canplay Режимы - - + + Status Статус - + The deletion will be irrevocable. Delete it anyway? Удаление будет безвозвратным. Всё равно удалить? - - + + Assign this task? Назначить эту задачу? @@ -119,7 +119,7 @@ Delete it anyway? AssetsManager - + LLC Constanta-Design ООО Константа-Дизайн @@ -238,67 +238,67 @@ The status will be set: CommonView - + Name Имя - + Login Логин - + Password Пароль - + Class Класс - + Computer Компьютер - + IP address IP адрес - + Administrator Администратор - + Archived Архивный - + Tasks AMM Задачи AMM - + Tasks FIM Задачи FIM - + Online В сети - + ID ID - + Messages Сообщения @@ -413,44 +413,44 @@ The status will be set: Восстановить - + Installed Установлен - + Not installed Не установлен - - + + Exist Существует - - + + Not exist Не существует - + Install PostgreSQL. Установите PostgreSQL. - + Failed to create user! Ошибка создания пользователя! - + Failed to create Database! Ошибка создания Базы данных! - + The database has been successfully restored! База данных успешно восстановлена! @@ -804,47 +804,47 @@ Please try again later. Обновить Docs - + Driver PostgreSQL is not installed! Драйвер PostgreSQL не установлен! - + Superuser PostgreSQL authorization Авторизация суперпользователя PostgreSQL - - + + Error connecting to PostgreSQL! Ошибка соединения с PostgreSQL! - - + + Possible reasons: Возможные причины: - - + + superuser PostgreSQL login or password is incorrect; неверный логин или пароль суперпользователя PostgreSQL; - - + + port is incorrect; порт некорректен; - - + + PostgreSQL is not installed. PostgreSQL не установлен. - + file 'pg_hba.conf' does not contain an entry for the IP address: файл 'pg_hba.conf' не содержит запись для IP-адреса: @@ -1188,38 +1188,38 @@ The changes will not be accepted. Удалить - - + + ID ID - - + + Status Статус - - + + Procedure FIM Процедура FIM - - + + Device Устройство - + The deletion will be irrevocable. Delete it anyway? Удаление будет безвозвратным. Всё равно удалить? - + Assign this task? Назначить эту задачу? @@ -1304,100 +1304,100 @@ Delete it anyway? - + none нет - + The file could not be opened Файл не может быть открыт - + Instructor authorization. Авторизация инструктора. - + Instructor deauthorization Деавторизация инструктора - + Error! Ошибка! - + Server blocked! Сервер заблокирован! - + Instructor authorization is temporarily unavailable. Авторизация инструктора временно недоступна. - + Try again later. Попробуйте позже. - + Database error! Ошибка базы данных! - + The user is archived! Пользователь является архивным! - + The user is already logged in! Пользователь уже в сети! - + Login or password error! Ошибка логина или пароля! - + The server is not available! Сервер недоступен! - + Connection attempt Попытка соединения - - + + connected подключен - + blocked заблокирован - + not connected не подключен - + Server settings have been changed. Please reconnect to the server. Настройки сервера были изменены. Пожалуйста, переподключитесь к серверу. - + Instructor authorization Авторизация инструктора @@ -1431,7 +1431,7 @@ Please reconnect to the server. - + DM code DM код @@ -1446,12 +1446,12 @@ Please reconnect to the server. Назначить - + Subprocedure Подпроцедура - + Canplay Режимы @@ -1459,31 +1459,26 @@ Please reconnect to the server. MainWindow - - + + Server MTD Сервер ТПТО - + Expand window Развернуть окно - + Minimize window Свернуть окно - + Exit Выход - - - Starting the server... - Запуск сервера... - Maintenance training device RRJ-95NEW-100 Instructor's workstation @@ -1638,26 +1633,71 @@ Please reconnect to the server. FIM + + + The trainee was removed! + Обучаемый удален! + + + + The trainee was archived! + Обучаемый заархивирован! + + + + QObject + + + + Maintenance training device RRJ-95NEW-100 Server + Сервер Тренажёра процедур технического обслуживания RRJ-95NEW-100 + + + + is running already! + уже запущена! + + + + + Application + Программа + + + + launch error! + ошибка запуска! + + + + Error create shared memory. + Ошибка создания разделяемой памяти. + + + + Contact your system administrator. + Свяжитесь с вашим системным администратором. + RecognizeSystem - + The file could not be opened Файл не может быть открыт - + You cannot delete the basic version! Вы не можете удалить базовую версию! - + You cannot delete the active version Вы не можете удалить активную версию - + This name already exists Это имя уже существует @@ -1745,86 +1785,91 @@ Please reconnect to the server. Версия материалов: - + Error PostgreSQL! Ошибка PostgreSQL! - + Server is started! Сервер запущен! - + Server is stoped! Сервер остановлен! - + Settings file could not be opened: Файл настроек не открыт: - + Database settings have been changed. The server will be restarted. Настройки Базы Данных были изменены. Сервер будет перезапущен. - + The file could not be opened Файл не может быть открыт - - + + Database connection error! Ошибка подключения Базы данных! - + Database connection OK! База данных подключена! - - + + started запущен - + locked заблокирован - + stoped остановлен - + connected подключена - + not connected не подключен - + No Client files found! Файлы клиента не найдены! - + * check Application for the presence of a folder with a build * check SharedData for a folder with the base version and the name base * проверьте Application на наличие папки со сборкой * проверьте SharedData на наличие папки с базовой версией и именем base + + + Starting the server... + Запуск сервера... + SpecMsgBox