8 changed files with 320 additions and 12 deletions
@ -0,0 +1,204 @@
|
||||
// databasesettingspage.cpp — Database maintenance page in settings
|
||||
#include "databasesettingspage.h" |
||||
#include "../db/db_manager.h" |
||||
#include <QVBoxLayout> |
||||
#include <QHBoxLayout> |
||||
#include <QFormLayout> |
||||
#include <QLabel> |
||||
#include <QFrame> |
||||
#include <QFileInfo> |
||||
#include <QTimer> |
||||
|
||||
DatabaseSettingsPage::DatabaseSettingsPage(DbManager* db, QWidget* parent) |
||||
: QWidget(parent) |
||||
, m_db(db) |
||||
{ |
||||
auto* layout = new QVBoxLayout(this); |
||||
layout->setSpacing(10); |
||||
layout->setContentsMargins(0, 0, 0, 0); |
||||
|
||||
auto* title = new QLabel("Database Maintenance", this); |
||||
title->setStyleSheet("font-weight: bold; font-size: 13px;"); |
||||
layout->addWidget(title); |
||||
|
||||
// --- DB info ---
|
||||
auto* infoLayout = new QFormLayout(); |
||||
infoLayout->setSpacing(4); |
||||
|
||||
QString dbPath = "—"; |
||||
QString dbSize = "—"; |
||||
QString walSize = "—"; |
||||
if (m_db && m_db->m_db) { |
||||
const char* fname = sqlite3_db_filename(m_db->m_db, "main"); |
||||
if (fname && fname[0]) { |
||||
dbPath = QString::fromUtf8(fname); |
||||
QFileInfo fi(dbPath); |
||||
if (fi.exists()) { |
||||
qint64 sz = fi.size(); |
||||
if (sz < 1024) dbSize = QString("%1 B").arg(sz); |
||||
else if (sz < 1024 * 1024) dbSize = QString("%1 KB").arg(sz / 1024); |
||||
else dbSize = QString("%1 MB").arg(sz / (1024.0 * 1024.0), 0, 'f', 2); |
||||
} |
||||
QFileInfo walFi(dbPath + "-wal"); |
||||
if (walFi.exists()) { |
||||
qint64 wsz = walFi.size(); |
||||
if (wsz < 1024) walSize = QString("%1 B").arg(wsz); |
||||
else if (wsz < 1024 * 1024) walSize = QString("%1 KB").arg(wsz / 1024); |
||||
else walSize = QString("%1 MB").arg(wsz / (1024.0 * 1024.0), 0, 'f', 2); |
||||
} else { |
||||
walSize = "n/a"; |
||||
} |
||||
} |
||||
} |
||||
m_filePathLabel = new QLabel(dbPath, this); |
||||
m_filePathLabel->setStyleSheet("font-size: 11px; color: gray;"); |
||||
m_filePathLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); |
||||
infoLayout->addRow("File:", m_filePathLabel); |
||||
|
||||
m_fileSizeLabel = new QLabel(dbSize, this); |
||||
m_fileSizeLabel->setStyleSheet("font-size: 11px;"); |
||||
infoLayout->addRow("Size:", m_fileSizeLabel); |
||||
|
||||
m_walSizeLabel = new QLabel(walSize, this); |
||||
m_walSizeLabel->setStyleSheet("font-size: 11px;"); |
||||
infoLayout->addRow("WAL:", m_walSizeLabel); |
||||
|
||||
layout->addLayout(infoLayout); |
||||
|
||||
// --- Separator ---
|
||||
auto* sep = new QFrame(this); |
||||
sep->setFrameShape(QFrame::HLine); |
||||
sep->setFrameShadow(QFrame::Sunken); |
||||
layout->addWidget(sep); |
||||
|
||||
// --- Buttons ---
|
||||
auto* btnLayout = new QVBoxLayout(); |
||||
btnLayout->setSpacing(6); |
||||
|
||||
auto* quickRow = new QHBoxLayout(); |
||||
m_quickBtn = new QPushButton("Quick Check", this); |
||||
m_quickBtn->setStyleSheet( |
||||
"QPushButton { border: 1px solid palette(mid); border-radius: 4px;" |
||||
" padding: 5px 14px; font-size: 12px; background: palette(button); }" |
||||
"QPushButton:hover { background: palette(light); }"); |
||||
connect(m_quickBtn, &QPushButton::clicked, this, &DatabaseSettingsPage::onQuickCheck); |
||||
quickRow->addWidget(m_quickBtn); |
||||
auto* quickDesc = new QLabel("Scans structure without verifying indexes (fast)", this); |
||||
quickDesc->setStyleSheet("color: gray; font-size: 11px;"); |
||||
quickRow->addWidget(quickDesc, 1); |
||||
btnLayout->addLayout(quickRow); |
||||
|
||||
auto* fullRow = new QHBoxLayout(); |
||||
m_fullBtn = new QPushButton("Full Check", this); |
||||
m_fullBtn->setStyleSheet(m_quickBtn->styleSheet()); |
||||
connect(m_fullBtn, &QPushButton::clicked, this, &DatabaseSettingsPage::onFullCheck); |
||||
fullRow->addWidget(m_fullBtn); |
||||
auto* fullDesc = new QLabel("Verifies all data structures and indexes (thorough)", this); |
||||
fullDesc->setStyleSheet("color: gray; font-size: 11px;"); |
||||
fullRow->addWidget(fullDesc, 1); |
||||
btnLayout->addLayout(fullRow); |
||||
|
||||
auto* optRow = new QHBoxLayout(); |
||||
m_optimizeBtn = new QPushButton("Optimize", this); |
||||
m_optimizeBtn->setStyleSheet(m_quickBtn->styleSheet()); |
||||
connect(m_optimizeBtn, &QPushButton::clicked, this, &DatabaseSettingsPage::onOptimize); |
||||
optRow->addWidget(m_optimizeBtn); |
||||
auto* optDesc = new QLabel("Update query planner statistics for better performance", this); |
||||
optDesc->setStyleSheet("color: gray; font-size: 11px;"); |
||||
optRow->addWidget(optDesc, 1); |
||||
btnLayout->addLayout(optRow); |
||||
|
||||
layout->addLayout(btnLayout); |
||||
|
||||
// --- Status ---
|
||||
m_statusLabel = new QLabel("", this); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; margin-top: 4px;"); |
||||
layout->addWidget(m_statusLabel); |
||||
|
||||
// --- Results ---
|
||||
m_resultText = new QPlainTextEdit(this); |
||||
m_resultText->setReadOnly(true); |
||||
m_resultText->setMaximumHeight(120); |
||||
m_resultText->setStyleSheet( |
||||
"QPlainTextEdit { font-family: monospace; font-size: 11px;" |
||||
" background: palette(base); border: 1px solid palette(mid); border-radius: 4px;" |
||||
" padding: 4px; }"); |
||||
m_resultText->setPlaceholderText("Run a check to see results..."); |
||||
layout->addWidget(m_resultText); |
||||
|
||||
layout->addStretch(); |
||||
} |
||||
|
||||
void DatabaseSettingsPage::setBusy(bool busy) { |
||||
m_quickBtn->setEnabled(!busy); |
||||
m_fullBtn->setEnabled(!busy); |
||||
m_optimizeBtn->setEnabled(!busy); |
||||
if (busy) { |
||||
m_statusLabel->setText("Checking..."); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; margin-top: 4px; color: gray;"); |
||||
} |
||||
} |
||||
|
||||
void DatabaseSettingsPage::onQuickCheck() { |
||||
if (!m_db || !m_db->m_db) { |
||||
m_statusLabel->setText("Database not open"); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; color: red;"); |
||||
return; |
||||
} |
||||
setBusy(true); |
||||
QTimer::singleShot(50, this, [this]() { |
||||
IntegrityResult r = m_db->integrityCheckQuick(); |
||||
showResult("Quick Check", r); |
||||
}); |
||||
} |
||||
|
||||
void DatabaseSettingsPage::onFullCheck() { |
||||
if (!m_db || !m_db->m_db) { |
||||
m_statusLabel->setText("Database not open"); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; color: red;"); |
||||
return; |
||||
} |
||||
setBusy(true); |
||||
QTimer::singleShot(50, this, [this]() { |
||||
IntegrityResult r = m_db->integrityCheckFull(); |
||||
showResult("Full Check", r); |
||||
}); |
||||
} |
||||
|
||||
void DatabaseSettingsPage::onOptimize() { |
||||
if (!m_db || !m_db->m_db) { |
||||
m_statusLabel->setText("Database not open"); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; color: red;"); |
||||
return; |
||||
} |
||||
setBusy(true); |
||||
QTimer::singleShot(50, this, [this]() { |
||||
IntegrityResult r = m_db->integrityOptimize(); |
||||
showResult("Optimize", r); |
||||
}); |
||||
} |
||||
|
||||
void DatabaseSettingsPage::showResult(const QString& checkName, const IntegrityResult& result) { |
||||
m_quickBtn->setEnabled(true); |
||||
m_fullBtn->setEnabled(true); |
||||
m_optimizeBtn->setEnabled(true); |
||||
|
||||
if (result.ok) { |
||||
m_statusLabel->setText(QString("%1: OK (%2 ms)") |
||||
.arg(checkName).arg(result.elapsedMs)); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; font-weight: bold; color: green;"); |
||||
} else { |
||||
m_statusLabel->setText(QString("%1: FAILED (%2 ms)") |
||||
.arg(checkName).arg(result.elapsedMs)); |
||||
m_statusLabel->setStyleSheet("font-size: 12px; font-weight: bold; color: red;"); |
||||
} |
||||
|
||||
if (result.errors.isEmpty()) { |
||||
m_resultText->setPlainText(result.message.isEmpty() ? "ok" : result.message); |
||||
} else { |
||||
QStringList lines; |
||||
lines.append(result.message); |
||||
lines.append(result.errors); |
||||
m_resultText->setPlainText(lines.join('\n')); |
||||
} |
||||
} |
||||
@ -0,0 +1,34 @@
|
||||
// databasesettingspage.h — Database maintenance page in settings
|
||||
#pragma once |
||||
|
||||
#include <QWidget> |
||||
#include <QPushButton> |
||||
#include <QLabel> |
||||
#include <QPlainTextEdit> |
||||
|
||||
class DbManager; |
||||
|
||||
class DatabaseSettingsPage : public QWidget { |
||||
Q_OBJECT |
||||
public: |
||||
explicit DatabaseSettingsPage(DbManager* db, QWidget* parent = nullptr); |
||||
|
||||
private slots: |
||||
void onQuickCheck(); |
||||
void onFullCheck(); |
||||
void onOptimize(); |
||||
|
||||
private: |
||||
void showResult(const QString& checkName, const struct IntegrityResult& result); |
||||
void setBusy(bool busy); |
||||
|
||||
DbManager* m_db; |
||||
QLabel* m_filePathLabel; |
||||
QLabel* m_fileSizeLabel; |
||||
QLabel* m_walSizeLabel; |
||||
QPushButton* m_quickBtn; |
||||
QPushButton* m_fullBtn; |
||||
QPushButton* m_optimizeBtn; |
||||
QLabel* m_statusLabel; |
||||
QPlainTextEdit* m_resultText; |
||||
}; |
||||
Loading…
Reference in new issue