/
imurzich
/
shulte
Обзор
Документация
Войти
/
imurzich
/
shulte
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Settings.cpp
465 строк
13 KB
Igor Murzich
Выбор ключа (сетка × поле) в окне статистики
18 июл 2026, 12:50
18 июл 2026, 12:50
eab7fad
Код
Авторство
О чём код?
#include "Settings.h" #include <QStandardPaths> #include <QDir> #include <QDateTime> #include <QVariantMap> #include <QLocale> #include <QHash> #include <QCoreApplication> #include <QTranslator> #include <sqlite3.h> Settings::Settings(QObject *parent) : QObject(parent) , m_settings("KDE", "Schulte Table") { loadGridSize(); openDatabase(); m_settings.beginGroup("General"); m_language = m_settings.value("language", QString()).toString(); m_statsPeriod = m_settings.value("statsPeriod", "all").toString(); m_toolbarOnSide = m_settings.value("toolbarOnSide", false).toBool(); m_fieldSizeCm = m_settings.value("fieldSizeCm", 20.0).toDouble(); m_showSizeControls = m_settings.value("showSizeControls", true).toBool(); m_showGridSizeControls = m_settings.value("showGridSizeControls", true).toBool(); m_showFieldSizeControls = m_settings.value("showFieldSizeControls", true).toBool(); m_toolbarVisible = m_settings.value("toolbarVisible", true).toBool(); m_settings.endGroup(); m_statsGridSize = m_gridSize; m_statsFieldSizeCm = m_fieldSizeCm; m_settings.beginGroup("StatsWindow"); m_statsWinX = m_settings.value("X", -1).toInt(); m_statsWinY = m_settings.value("Y", -1).toInt(); m_statsWinW = m_settings.value("Width", 800).toInt(); m_statsWinH = m_settings.value("Height", 600).toInt(); m_settings.endGroup(); } Settings::~Settings() { if (m_db) sqlite3_close(m_db); } void Settings::openDatabase() { QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/shulte"; QDir().mkpath(dir); QString path = dir + "/stats.db"; int rc = sqlite3_open(path.toUtf8().constData(), &m_db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(m_db)); sqlite3_close(m_db); m_db = nullptr; return; } const char *sql = "CREATE TABLE IF NOT EXISTS results (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "grid_size INTEGER NOT NULL," "timestamp TEXT NOT NULL," "seconds INTEGER NOT NULL)"; char *err = nullptr; rc = sqlite3_exec(m_db, sql, nullptr, nullptr, &err); if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err); sqlite3_free(err); } const char *alterSql = "ALTER TABLE results ADD COLUMN field_size_cm REAL DEFAULT 20.0"; rc = sqlite3_exec(m_db, alterSql, nullptr, nullptr, &err); if (rc != SQLITE_OK) { sqlite3_free(err); } } int Settings::gridSize() const { return m_gridSize; } void Settings::setGridSize(int size) { if (size == m_gridSize) return; m_gridSize = size; saveGridSize(); emit gridSizeChanged(); } int Settings::bestTime() const { if (!m_db) return 0; sqlite3_stmt *stmt; QString sql = "SELECT MIN(seconds) FROM results WHERE grid_size = ? AND field_size_cm = ?"; sql += periodWhere(); QByteArray sqlBa = sql.toUtf8(); if (sqlite3_prepare_v2(m_db, sqlBa.constData(), -1, &stmt, nullptr) != SQLITE_OK) return 0; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); int result = 0; if (sqlite3_step(stmt) == SQLITE_ROW) result = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); return result; } double Settings::avgTime() const { if (!m_db) return 0.0; sqlite3_stmt *stmt; QString sql = "SELECT AVG(seconds) FROM results WHERE grid_size = ? AND field_size_cm = ?"; sql += periodWhere(); QByteArray sqlBa = sql.toUtf8(); if (sqlite3_prepare_v2(m_db, sqlBa.constData(), -1, &stmt, nullptr) != SQLITE_OK) return 0.0; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); double result = 0.0; if (sqlite3_step(stmt) == SQLITE_ROW) result = sqlite3_column_double(stmt, 0); sqlite3_finalize(stmt); return result; } int Settings::trainCount() const { if (!m_db) return 0; sqlite3_stmt *stmt; QString sql = "SELECT COUNT(*) FROM results WHERE grid_size = ? AND field_size_cm = ?"; sql += periodWhere(); QByteArray sqlBa = sql.toUtf8(); if (sqlite3_prepare_v2(m_db, sqlBa.constData(), -1, &stmt, nullptr) != SQLITE_OK) return 0; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); int result = 0; if (sqlite3_step(stmt) == SQLITE_ROW) result = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); return result; } QVariantList Settings::history() const { QVariantList list; if (!m_db) return list; sqlite3_stmt *stmt; QString sql = "SELECT seconds, timestamp FROM results WHERE grid_size = ? AND field_size_cm = ?"; sql += periodWhere(); sql += " ORDER BY id DESC LIMIT 100"; QByteArray sqlBa = sql.toUtf8(); if (sqlite3_prepare_v2(m_db, sqlBa.constData(), -1, &stmt, nullptr) != SQLITE_OK) return list; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); while (sqlite3_step(stmt) == SQLITE_ROW) { QVariantMap item; item["seconds"] = sqlite3_column_int(stmt, 0); item["date"] = QString::fromUtf8(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1))); list.append(item); } sqlite3_finalize(stmt); return list; } QVariantList Settings::chartData() const { QVariantList list; if (!m_db) return list; sqlite3_stmt *stmt; QString sql = "SELECT timestamp, seconds FROM results WHERE grid_size = ? AND field_size_cm = ?"; sql += periodWhere(); sql += " ORDER BY id ASC"; QByteArray sqlBa = sql.toUtf8(); if (sqlite3_prepare_v2(m_db, sqlBa.constData(), -1, &stmt, nullptr) != SQLITE_OK) return list; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); while (sqlite3_step(stmt) == SQLITE_ROW) { QVariantMap item; item["date"] = QString::fromUtf8(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0))); item["seconds"] = sqlite3_column_int(stmt, 1); list.append(item); } sqlite3_finalize(stmt); return list; } QString Settings::statsPeriod() const { return m_statsPeriod; } void Settings::setStatsPeriod(const QString &period) { if (period == m_statsPeriod) return; m_statsPeriod = period; m_settings.beginGroup("General"); m_settings.setValue("statsPeriod", m_statsPeriod); m_settings.endGroup(); m_settings.sync(); emit statsPeriodChanged(); emit statsChanged(); } bool Settings::toolbarOnSide() const { return m_toolbarOnSide; } void Settings::setToolbarOnSide(bool side) { if (side == m_toolbarOnSide) return; m_toolbarOnSide = side; m_settings.beginGroup("General"); m_settings.setValue("toolbarOnSide", m_toolbarOnSide); m_settings.endGroup(); m_settings.sync(); emit toolbarOnSideChanged(); } double Settings::fieldSizeCm() const { return m_fieldSizeCm; } void Settings::setFieldSizeCm(double cm) { if (qFuzzyCompare(cm, m_fieldSizeCm)) return; m_fieldSizeCm = cm; m_settings.beginGroup("General"); m_settings.setValue("fieldSizeCm", m_fieldSizeCm); m_settings.endGroup(); m_settings.sync(); emit fieldSizeCmChanged(); } bool Settings::showSizeControls() const { return m_showSizeControls; } void Settings::setShowSizeControls(bool show) { if (show == m_showSizeControls) return; m_showSizeControls = show; m_settings.beginGroup("General"); m_settings.setValue("showSizeControls", m_showSizeControls); m_settings.endGroup(); m_settings.sync(); emit showSizeControlsChanged(); } bool Settings::showGridSizeControls() const { return m_showGridSizeControls; } void Settings::setShowGridSizeControls(bool show) { if (show == m_showGridSizeControls) return; m_showGridSizeControls = show; m_settings.beginGroup("General"); m_settings.setValue("showGridSizeControls", m_showGridSizeControls); m_settings.endGroup(); m_settings.sync(); emit showGridSizeControlsChanged(); } bool Settings::showFieldSizeControls() const { return m_showFieldSizeControls; } void Settings::setShowFieldSizeControls(bool show) { if (show == m_showFieldSizeControls) return; m_showFieldSizeControls = show; m_settings.beginGroup("General"); m_settings.setValue("showFieldSizeControls", m_showFieldSizeControls); m_settings.endGroup(); m_settings.sync(); emit showFieldSizeControlsChanged(); } bool Settings::toolbarVisible() const { return m_toolbarVisible; } void Settings::setToolbarVisible(bool visible) { if (visible == m_toolbarVisible) return; m_toolbarVisible = visible; m_settings.beginGroup("General"); m_settings.setValue("toolbarVisible", m_toolbarVisible); m_settings.endGroup(); m_settings.sync(); emit toolbarVisibleChanged(); } QString Settings::periodWhere() const { if (m_statsPeriod == "all") return QString(); bool ok; int days = m_statsPeriod.toInt(&ok); if (ok && days > 0) return QString(" AND timestamp >= datetime('now', '-%1 days')").arg(days); return QString(); } void Settings::addResult(int seconds) { if (!m_db) return; QString ts = QDateTime::currentDateTime().toString(Qt::ISODate); sqlite3_stmt *stmt; const char *sql = "INSERT INTO results (grid_size, field_size_cm, timestamp, seconds) VALUES (?, ?, ?, ?)"; if (sqlite3_prepare_v2(m_db, sql, -1, &stmt, nullptr) != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, m_gridSize); sqlite3_bind_double(stmt, 2, m_fieldSizeCm); sqlite3_bind_text(stmt, 3, ts.toUtf8().constData(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 4, seconds); sqlite3_step(stmt); sqlite3_finalize(stmt); emit statsChanged(); } void Settings::clearStats() { if (!m_db) return; sqlite3_stmt *stmt; const char *sql = "DELETE FROM results WHERE grid_size = ? AND field_size_cm = ?"; if (sqlite3_prepare_v2(m_db, sql, -1, &stmt, nullptr) != SQLITE_OK) return; sqlite3_bind_int(stmt, 1, m_statsGridSize); sqlite3_bind_double(stmt, 2, m_statsFieldSizeCm); sqlite3_step(stmt); sqlite3_finalize(stmt); emit statsChanged(); } void Settings::saveStatsWindowGeometry(int x, int y, int w, int h) { m_settings.beginGroup("StatsWindow"); m_settings.setValue("X", x); m_settings.setValue("Y", y); m_settings.setValue("Width", w); m_settings.setValue("Height", h); m_settings.endGroup(); m_settings.sync(); } int Settings::statsGridSize() const { return m_statsGridSize; } void Settings::setStatsGridSize(int size) { if (size == m_statsGridSize) return; m_statsGridSize = size; emit statsGridSizeChanged(); emit statsChanged(); } double Settings::statsFieldSizeCm() const { return m_statsFieldSizeCm; } void Settings::setStatsFieldSizeCm(double cm) { if (qFuzzyCompare(cm, m_statsFieldSizeCm)) return; m_statsFieldSizeCm = cm; emit statsFieldSizeCmChanged(); emit statsChanged(); } QVariantList Settings::availableStatsKeys() const { QVariantList list; if (!m_db) return list; sqlite3_stmt *stmt; const char *sql = "SELECT DISTINCT grid_size, field_size_cm FROM results ORDER BY grid_size, field_size_cm"; if (sqlite3_prepare_v2(m_db, sql, -1, &stmt, nullptr) != SQLITE_OK) return list; while (sqlite3_step(stmt) == SQLITE_ROW) { QVariantMap item; item["gridSize"] = sqlite3_column_int(stmt, 0); item["fieldSizeCm"] = sqlite3_column_double(stmt, 1); list.append(item); } sqlite3_finalize(stmt); return list; } void Settings::loadGridSize() { m_settings.beginGroup("General"); m_gridSize = m_settings.value("gridSize", 5).toInt(); m_settings.endGroup(); } void Settings::saveGridSize() { m_settings.beginGroup("General"); m_settings.setValue("gridSize", m_gridSize); m_settings.endGroup(); m_settings.sync(); } QString Settings::language() const { return m_language; } void Settings::setLanguage(const QString &lang) { if (lang == m_language) return; m_language = lang; m_settings.beginGroup("General"); m_settings.setValue("language", m_language); m_settings.endGroup(); m_settings.sync(); emit languageChanged(); } QVariantList Settings::availableLanguages() const { QVariantList result; QVariantMap sys; sys["code"] = QString(""); sys["name"] = tr("Системный"); result.append(sys); QHash<QString, QString> nativeNames = { {"ru", QString::fromUtf8("\320\240\321\203\321\201\321\201\320\272\320\270\320\271")}, {"en", QString::fromUtf8("English")} }; QString localeDir = QCoreApplication::applicationDirPath() + "/locale"; QDir dir(localeDir); if (dir.exists()) { QStringList subdirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); for (const QString &code : subdirs) { QVariantMap entry; entry["code"] = code; QLocale loc(code); QString name = nativeNames.value(code, loc.nativeLanguageName()); if (name.isEmpty()) name = code; entry["name"] = name; result.append(entry); } } return result; }