/* * @RDE_HEADER@ * * $Id$ * $HeadURL$ * $Author$ * Created by Malte Schröder, SLSE, 2016-06-08 */ #include "aar_application.h" #include "ui_aarApp.h" #include "databases_model.h" #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_DB "lts_ets_pro" namespace AARApplication { AarApplication::AarApplication(QWidget *parent) : QMainWindow(parent) , m_ui(new Ui::AarApplication) , m_stopping(false) , m_proc(nullptr) , m_progressDialog(nullptr) , m_logger(getLogger("AarApplication")) { setAttribute(Qt::WA_DeleteOnClose); m_ui->setupUi(this); const QList &screenList = QGuiApplication::screens(); m_widgets.reserve(screenList.size()); for (QScreen *s : qAsConst(screenList)) { QWidget *w = new QWidget(); // no parent w->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); w->setGeometry(s->geometry()); w->activateWindow(); w->show(); m_widgets.append(w); } m_databasesModel = new DatabasesModel(this); m_proxyModel = new DatabasesProxyModel(this); m_proxyModel->setSourceModel(m_databasesModel); m_ui->tableViewDatabases->setModel(m_proxyModel); connect(m_ui->pbClose, &QPushButton::clicked, this, &AarApplication::onClosedClicked); connect(m_ui->pbRemove, &QPushButton::clicked, this, &AarApplication::onRemoveClicked); connect(m_ui->pbActivate, &QPushButton::clicked, this, &AarApplication::onActivateClicked); connect(m_ui->pbActivateNetwork, &QPushButton::clicked, this, &AarApplication::onActivateNetworkClicked); connect(m_ui->tableViewDatabases->selectionModel(), &QItemSelectionModel::selectionChanged, this, &AarApplication::enaDisa); setWindowTitle(QLatin1String("AarApplication")); enaDisa(); m_progressDialog = new QProgressDialog(this); m_progressDialog->setLabelText(tr("Stopping server software ...")); m_progressDialog->setMinimum(0); m_progressDialog->setMaximum(0); m_progressDialog->show(); onStopApp(); } AarApplication::~AarApplication() { delete m_ui; delete m_databasesModel; delete m_progressDialog; for (QSqlDatabase db : qAsConst(m_dbMap)) db.close(); m_dbPostgres.close(); if (m_proc) m_proc->deleteLater(); qDeleteAll(m_widgets); } bool AarApplication::init() { m_ui->lblStatus->setText(tr("No active database")); m_dbPostgres = DBConnection::open(m_logger, QStringLiteral("postgres"), QStringLiteral("postgres"), QStringLiteral("QPSQL"), QStringLiteral("localhost"), QStringLiteral("postgres"), QString(), QStringLiteral("localhost_postgres")); if (!m_dbPostgres.open()) { ERROR_LOG(m_logger) << "Error opening postgres database" << m_dbPostgres.lastError().databaseText(); return false; } NSqlQuery q(m_dbPostgres); QString stmt = QStringLiteral("SELECT datname FROM pg_database WHERE datname = '") + QStringLiteral(DEFAULT_DB) + QStringLiteral("'"); if (!q.execAndFetch(stmt)) { NOTICE_LOG(m_logger) << "Database does not exist: " << DEFAULT_DB; } else { QSqlDatabase db_lts = DBConnection::open(m_logger, QStringLiteral("ctc_sv"), QStringLiteral("ctc11de"), QStringLiteral("QPSQL"), QStringLiteral("localhost"), QStringLiteral(DEFAULT_DB), QString(), QStringLiteral("localhost_")+QStringLiteral(DEFAULT_DB)); if (!db_lts.open()) { ERROR_LOG(m_logger) << "Error opening database " << DEFAULT_DB << " : "<< db_lts.lastError().databaseText(); m_dbPostgres.close(); return false; } NSqlQuery ql(db_lts); stmt = QStringLiteral("SELECT id FROM exm.exercise"); if (!ql.execAndFetch(stmt)) { ERROR_LOG(m_logger) << "No entry for exercise found in database " << DEFAULT_DB; } else { int dbId = ql.value(0).toInt(); db_lts.close(); QString dbName = QStringLiteral("lts_db_") + QString::number(dbId); INFO_LOG(m_logger) << "New dbName for " << DEFAULT_DB << ": " << dbName; stmt = QStringLiteral("ALTER DATABASE ") + QStringLiteral(DEFAULT_DB) + QStringLiteral(" RENAME TO ") + dbName; if (!q.exec(stmt)) { ERROR_LOG(m_logger) << "Error renaming database " << DEFAULT_DB << " : " << db_lts.lastError().databaseText(); m_dbPostgres.close(); return false; } } } stmt = QStringLiteral("SELECT datname FROM pg_database WHERE datname ilike 'lts_db_%';"); if (!q.exec(stmt)) { ERROR_LOG(m_logger) << "Error while reading dbnames from database"; return false; } while (q.next()) { QString dbName = q.value(0).toString(); QSqlDatabase db = DBConnection::open(m_logger, QStringLiteral("ctc_sv"), QStringLiteral("ctc11de"), QStringLiteral("QPSQL"), QStringLiteral("localhost"), dbName, QString(), QStringLiteral("localhost_") + dbName); if (!db.open()) { ERROR_LOG(m_logger) << "Error while opening database " << dbName << ", error: " << db.lastError().databaseText(); continue; } m_databasesModel->initModel(db); m_dbMap.insert(dbName, db); } m_ui->tableViewDatabases->resizeColumnsToContents(); return true; } void AarApplication::onClosedClicked() { handleProcInit(QStringLiteral("/usr/bin/openbox"), {QStringLiteral("--exit")}); m_proc->start(); m_proc->waitForFinished(); QThread::sleep(2); close(); } void AarApplication::onRemoveClicked() { disableButtons(); m_databaseToRemove = m_databasesModel->getRowData(m_ui->tableViewDatabases->currentIndex().row()); QString strMsg = QStringLiteral("Do you really want to remove the database '%1'?").arg (m_databaseToRemove.dbName); int result = QMessageBox::question(this, tr("Remove Database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (result == QMessageBox::No) { enableButtons(); return; } DEBUG_LOG(m_logger) << "onRemoveClicked: dbName = " << m_databaseToRemove.dbName; QSqlDatabase db = m_dbMap.value(m_databaseToRemove.dbName); db.close(); const QStringList args({QStringLiteral("-U"), QStringLiteral("postgres"), QStringLiteral("-h"), QStringLiteral("localhost"), m_databaseToRemove.dbName }); QString errStr; const QString exePath = NGL::postgresExecutablePath(QStringLiteral("dropdb"), errStr); if (!errStr.isEmpty()) WARNING_LOG(m_logger) << errStr; handleProcInit(exePath, args); connect(m_proc, QOverload::of(&QProcess::finished), this, &AarApplication::onDropDbFinished); // start process m_proc->start(); } void AarApplication::onActivateClicked() { const QString fileName = QStringLiteral("/shd/CTC/WS/lts-cc.conf.org"); WARNING_LOG(m_logger) << "FileName: " << fileName; QFile ltsConfig(fileName); if (ltsConfig.exists()) ltsConfig.rename(QStringLiteral("/shd/CTC/WS/lts-cc.conf.org"), QStringLiteral("/shd/CTC/WS/lts-cc.conf")); Exercise ex = m_databasesModel->getRowData(m_ui->tableViewDatabases->currentIndex().row()); QString strMsg = tr("Do you really want to activate database '%1'?").arg(ex.name); int result = QMessageBox::question(this, tr("Activate local database"), strMsg, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (result == QMessageBox::No) return; INFO_LOG(m_logger) << "onActivateClicked: dbName = " << ex.dbName; QSqlDatabase db = m_dbMap.value(ex.dbName); db.close(); NSqlQuery q(m_dbPostgres); QString stmt = QStringLiteral("ALTER DATABASE ") + ex.dbName + QStringLiteral(" RENAME TO ") + QStringLiteral(DEFAULT_DB); if (!q.exec(stmt)) ERROR_LOG(m_logger) << "Error renaming " << ex.dbName << " to " << DEFAULT_DB << " "<< m_dbPostgres.lastError().databaseText(); else INFO_LOG(m_logger) << "Database " << ex.dbName << " renamed to " << DEFAULT_DB; QString status = ex.name + QStringLiteral(" (") + ex.dbName + QStringLiteral(") ") + tr("active"); m_ui->lblStatus->setText(status); onStartApp(); } void AarApplication::onActivateNetworkClicked() { onStopApp(); //const QString fileName = QDir::homePath()+ QStringLiteral("/lts-cc.conf"); const QString fileName = QStringLiteral("/shd/CTC/WS") + QStringLiteral("/lts-cc.conf"); WARNING_LOG(m_logger) << "FileName: " << fileName; QFile ltsConfig(fileName); if (!ltsConfig.exists()) { QMessageBox::critical(this, tr ("Activate network database"), tr("Network database active"), QMessageBox::Ok); m_ui->lblStatus->setText(tr("Network database active")); return; } ltsConfig.rename(QStringLiteral("/shd/CTC/WS/lts-cc.conf"), QStringLiteral("/shd/CTC/WS/lts-cc.conf.org")); m_ui->lblStatus->setText(tr("Network database active")); } void AarApplication::enaDisa() { if (!m_ui) return; int selected = m_ui->tableViewDatabases->selectionModel()->selectedRows().size(); m_ui->pbRemove->setEnabled(selected > 0); m_ui->pbActivate->setEnabled(selected > 0); } void AarApplication::onDropDbFinished(int exitCode, QProcess::ExitStatus exitStatus) { INFO_LOG(m_logger) << "onDropDbFinished: exitCode: " << exitCode << ", exitStatus: " << exitStatus; static const QString s_title = tr("Remove Database"); static const QString s_msgFailure = tr("Removing database failed."); static const QString s_msgSuccess = tr("Removing database successful."); if (exitCode > 0) { const QString str = QString::fromLocal8Bit(m_proc->readAllStandardError()) + QLatin1Char('\n') + QString::fromLocal8Bit(m_proc->readAllStandardOutput()); ERROR_LOG(m_logger) << "Cannot drop database: " << str; QString msg = s_msgFailure; QString db0 = QLatin1String("ERROR: database \"") + m_databaseToRemove.dbName + QLatin1String("\" does not exist"); if (!str.contains(db0)) msg += tr(" Database cannot be removed:\n%1.").arg(str); QMessageBox::critical(this, s_title, msg, QMessageBox::Ok); } else { m_databasesModel->onDataChanged(m_databaseToRemove, DataModification::eRemoved); QMessageBox::information(this, s_title, s_msgSuccess); } enableButtons(); } void AarApplication::onErrorOccured(QProcess::ProcessError error) { ERROR_LOG(m_logger) << "error: " << error; } void AarApplication::onStartApp() { handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")}); connect(m_proc, QOverload::of(&QProcess::finished), this, &AarApplication::onPsauxFinished); m_proc->start(); } void AarApplication::onPsauxFinished() { enableButtons(); QByteArray output = m_proc->readAllStandardOutput(); if (output.contains("svcServiceManagement")) { ERROR_LOG(m_logger) << "ServiceManagement already started"; } else { ERROR_LOG(m_logger) << "Start svcServiceManagement"; handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-z")}); connect(m_proc, QOverload::of(&QProcess::finished), this, &AarApplication::onStartAppFinished); m_proc->start(); m_proc->waitForFinished(); } } void AarApplication::onStartAppFinished(int exitCode, QProcess::ExitStatus exitStatus) { handleProcFinished(exitCode, exitStatus); } void AarApplication::onStopApp() { disableButtons(); handleProcInit(QStringLiteral("ps"), {QStringLiteral("aux")}); m_proc->start(); if (m_proc->waitForFinished()) onPsauxStopFinished(); } void AarApplication::onPsauxStopFinished() { DEBUG_LOG(m_logger) << "IN onPsauxStopFinished"; enableButtons(); QByteArray output = m_proc->readAllStandardOutput(); if (output.contains("svcServiceManagement")) { if (m_stopping) { QThread::sleep(3); onStopApp(); } else { ERROR_LOG(m_logger) << "ServiceManagement started - stopping"; handleProcInit(QCoreApplication::applicationDirPath() + QStringLiteral("/svcServiceManagement"), {QStringLiteral("-s")}); connect(m_proc, QOverload::of(&QProcess::finished), this, &AarApplication::onStopAppFinished); m_proc->start(); m_stopping = true; } } else { INFO_LOG(m_logger) << "ServiceManagement already stopped"; m_stopping = false; m_progressDialog->hide(); } m_proc->waitForFinished(); } void AarApplication::onStopAppFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (m_stopping) onPsauxStopFinished(); handleProcFinished(exitCode, exitStatus); } void AarApplication::handleProcInit(const QString &program, const QStringList &args) { if (m_proc) { m_proc->disconnect(this); m_proc->deleteLater(); } m_proc = new QProcess(this); NOTICE_LOG(m_logger) << "Starting process '" << program << "' with args '" << args.join(QLatin1Char(' ')) << "'"; m_proc->setProgram(program); m_proc->setArguments(args); connect(m_proc, &QProcess::errorOccurred, this, &AarApplication::onErrorOccured); disableButtons(); } void AarApplication::handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) { enableButtons(); if (!m_proc) return; if (exitCode != 0 || exitStatus != 0) { QByteArray out = m_proc->readAllStandardError(); if (!out.isEmpty()) out += '\n'; out += m_proc->readAllStandardOutput(); ERROR_LOG(m_logger) << "Process finished - exitCode: " << exitCode << ", exitStatus = " << exitStatus << ", " << out; QMessageBox::critical(this, tr ("Execute process"), tr("Error executing process, exitCode: %1, exitStatus: %2, output: %3") .arg(exitCode).arg(exitStatus).arg(QString::fromLocal8Bit(out)), QMessageBox::Ok); } m_proc->disconnect(this); m_proc->deleteLater(); m_proc = nullptr; if (m_progressDialog) m_progressDialog->hide(); } void AarApplication::enaDisaButtons(bool bEnable) { { const QList l = findChildren(); for (QPushButton *pb : l) pb->setEnabled(bEnable); } { const QList l = findChildren(); for (QAction *a : l) a->setEnabled(bEnable); } if (bEnable) enaDisa(); } } // namespace AarApplication