修复数据库切换连接异常问题

This commit is contained in:
taocong
2026-09-17 08:49:06 +08:00
committed by taocong45644
parent 903d805f31
commit 14880cc6ad
11 changed files with 372 additions and 245 deletions
+3 -2
View File
@@ -20,9 +20,10 @@ int main(int argc, char *argv[])
QCoreApplication::addLibraryPath(basePath);
QCoreApplication::addLibraryPath(basePath + "/sqldrivers");
ConfigManager::instance()->loadConfig(basePath);
// 配置文件位于 程序目录/config/config.ini(loadConfig 内部使用 appConfigDir())
ConfigManager::instance()->loadConfig();
MainWindow w;
w.show();
w.showMaximized();
return a.exec();
}
+10 -9
View File
@@ -5,6 +5,7 @@
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSettings>
#include "utils/configmanager.h"
// 连接参数结构体
struct ConnectionParams {
@@ -18,15 +19,15 @@ struct ConnectionParams {
// 从 QSettings group 加载
static ConnectionParams fromSettings(const QString& connectionKey) {
ConnectionParams p;
QSettings settings("Omnitool", "DatabaseConnections");
settings.beginGroup(connectionKey);
p.dbType = settings.value("dbType", "MySQL").toString();
p.host = settings.value("host").toString();
p.port = settings.value("port").toString();
p.database = settings.value("database").toString();
p.username = settings.value("username").toString();
p.password = settings.value("password").toString();
settings.endGroup();
QSettings* settings = appConnectionsSettings();
settings->beginGroup(connectionKey);
p.dbType = settings->value("dbType", "MySQL").toString();
p.host = settings->value("host").toString();
p.port = settings->value("port").toString();
p.database = settings->value("database").toString();
p.username = settings->value("username").toString();
p.password = settings->value("password").toString();
settings->endGroup();
return p;
}
};
+37 -8
View File
@@ -9,11 +9,14 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QShowEvent>
#include <QSettings>
#include <QMessageBox>
#include <QLabel>
#include <QDateTime>
#include <QDir>
#include "utils/logmanager.h"
#include "utils/configmanager.h"
DatabaseConnectionConfigDialog::DatabaseConnectionConfigDialog(QWidget* parent)
: QDialog(parent)
{
@@ -121,7 +124,7 @@ void DatabaseConnectionConfigDialog::loadConnections()
{
_connectionTable->setRowCount(0);
QSettings settings("Omnitool", "DatabaseConnections");
QSettings settings(QDir(appConfigDir()).filePath("config.ini"), QSettings::IniFormat);
QStringList groups = settings.childGroups();
for (const QString& group : groups) {
@@ -231,13 +234,34 @@ void DatabaseConnectionConfigDialog::loadConnections()
_connectionTable->setCellWidget(0, 0, emptyWidget);
}
resizeTableColumns();
}
void DatabaseConnectionConfigDialog::resizeTableColumns()
{
if (!_connectionTable) return;
// 控件布局完成后重新计算,确保 "默认"、"操作" 列自适应内容宽度
_connectionTable->resizeColumnsToContents();
// 为按钮列预留最小宽度,避免被压缩或计算为 0
if (_connectionTable->columnCount() > 3)
_connectionTable->setColumnWidth(3, qMax(_connectionTable->columnWidth(3), 70));
if (_connectionTable->columnCount() > 4)
_connectionTable->setColumnWidth(4, qMax(_connectionTable->columnWidth(4), 160));
}
void DatabaseConnectionConfigDialog::showEvent(QShowEvent* event)
{
QDialog::showEvent(event);
// 首次显示后控件几何已完成,重新自适应列宽
resizeTableColumns();
}
void DatabaseConnectionConfigDialog::addConnection()
{
ElaDatabaseConnectionDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
QSettings settings("Omnitool", "DatabaseConnections");
QSettings settings(QDir(appConfigDir()).filePath("config.ini"), QSettings::IniFormat);
QString key = "connection_" + QString::number(QDateTime::currentMSecsSinceEpoch());
settings.beginGroup(key);
@@ -245,7 +269,8 @@ void DatabaseConnectionConfigDialog::addConnection()
settings.setValue("dbType", dialog.getDatabaseType());
settings.setValue("host", dialog.getHostName());
settings.setValue("port", dialog.getPort());
settings.setValue("database", dialog.getDatabaseName());
// SQLite 类型为文件路径
settings.setValue("database", dialog.getDatabaseType() == "SQLite" ? dialog.getDatabaseFileName() : dialog.getDatabaseName());
settings.setValue("username", dialog.getUserName());
settings.setValue("password", dialog.getPassword());
settings.endGroup();
@@ -266,7 +291,7 @@ void DatabaseConnectionConfigDialog::editConnection(int row)
return;
}
QSettings settings("Omnitool", "DatabaseConnections");
QSettings settings(QDir(appConfigDir()).filePath("config.ini"), QSettings::IniFormat);
settings.beginGroup(key);
QString dbType = settings.value("dbType", "MySQL").toString();
QString connectionName = settings.value("name", key).toString();
@@ -282,7 +307,11 @@ void DatabaseConnectionConfigDialog::editConnection(int row)
dialog.setConnectionName(connectionName);
dialog.setHostName(host);
dialog.setPort(port);
dialog.setDatabaseName(database);
if (dbType == "SQLite") {
dialog.setDatabaseFileName(database);
} else {
dialog.setDatabaseName(database);
}
dialog.setUserName(username);
dialog.setPassword(password);
@@ -292,7 +321,7 @@ void DatabaseConnectionConfigDialog::editConnection(int row)
settings.setValue("dbType", dialog.getDatabaseType());
settings.setValue("host", dialog.getHostName());
settings.setValue("port", dialog.getPort());
settings.setValue("database", dialog.getDatabaseName());
settings.setValue("database", dialog.getDatabaseType() == "SQLite" ? dialog.getDatabaseFileName() : dialog.getDatabaseName());
settings.setValue("username", dialog.getUserName());
settings.setValue("password", dialog.getPassword());
settings.endGroup();
@@ -312,7 +341,7 @@ void DatabaseConnectionConfigDialog::deleteConnection(int row)
if (QMessageBox::question(this, "确认删除", "确定要删除此连接吗?",
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
if (!key.isEmpty()) {
QSettings settings("Omnitool", "DatabaseConnections");
QSettings settings(QDir(appConfigDir()).filePath("config.ini"), QSettings::IniFormat);
settings.remove(key);
}
@@ -348,7 +377,7 @@ void DatabaseConnectionConfigDialog::setDefault(int row)
return;
}
QSettings settings("Omnitool", "DatabaseConnections");
QSettings settings(QDir(appConfigDir()).filePath("config.ini"), QSettings::IniFormat);
QStringList groups = settings.childGroups();
for (const QString& group : groups) {
@@ -3,6 +3,7 @@
#include <QDialog>
#include <QTableWidget>
#include <QShowEvent>
class ElaLineEdit;
class ElaPushButton;
@@ -18,6 +19,9 @@ public:
QString getSelectedConnectionKey() const { return _selectedConnectionKey; }
protected:
void showEvent(QShowEvent* event) override;
private:
QString _selectedConnectionKey;
void initUI();
@@ -30,6 +34,7 @@ private:
void setDefault(int row);
void exportConfig();
void importConfig();
void resizeTableColumns();
private:
ElaLineEdit* _searchEdit;
+205 -202
View File
@@ -2,11 +2,8 @@
#include "ElaLineEdit.h"
#include "ElaComboBox.h"
#include "ElaPushButton.h"
#include "ElaToolButton.h"
#include "ElaText.h"
#include "ElaMessageBar.h"
#include "ElaIcon.h"
#include "connectors/DatabaseConnector.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
@@ -14,31 +11,37 @@
#include <QSqlDatabase>
#include <QSqlError>
#include <QFileDialog>
#include <QDir>
ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle("数据库连接");
setMinimumWidth(500);
// 固定宽度,高度随显示的控件数量自适应
setFixedWidth(500);
setWindowFlags(windowFlags() & ~Qt::WindowMinMaxButtonsHint);
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(30, 30, 30, 30);
mainLayout->setSpacing(24);
mainLayout->setContentsMargins(30, 24, 30, 24);
mainLayout->setSpacing(10);
ElaText* titleText = new ElaText("数据库连接配置");
titleText->setTextStyle(ElaTextType::Body);
titleText->setStyleSheet("font-size: 20px;");
titleText->setContentsMargins(0, 0, 0, 4);
titleText->setFixedHeight(28);
mainLayout->addWidget(titleText, 0, Qt::AlignCenter);
_formLayout = new QGridLayout();
_formLayout->setVerticalSpacing(12);
_formLayout->setHorizontalSpacing(15);
_formLayout->setColumnStretch(0, 1);
_formLayout->setColumnStretch(3, 1);
_formLayout->setVerticalSpacing(14);
_formLayout->setHorizontalSpacing(12);
// 标签列固定最小宽度(容纳"数据库文件""节点名称"),输入列伸展
_formLayout->setColumnStretch(1, 0);
_formLayout->setColumnStretch(2, 1);
_formLayout->setColumnMinimumWidth(1, 92);
// 先将布局挂到主布局(让 layout 有 parent),否则 addWidget 时 widget 不会跟随 dialog
mainLayout->addLayout(_formLayout);
// Row 0: 连接名称(所有类型都显示)
// ---- Row 0: 连接名称(所有类型都显示) ----
_connectionNameLabel = new ElaText("连接名称");
_connectionNameLabel->setStyleSheet("font-size: 13px;");
_connectionNameLineEdit = new ElaLineEdit();
@@ -46,15 +49,15 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_connectionNameLabel, 0, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_connectionNameLineEdit, 0, 2);
// Row 1: 数据库类型
ElaText* dbTypeLabel = new ElaText("数据库类型");
dbTypeLabel->setStyleSheet("font-size: 13px;");
// ---- Row 1: 数据库类型(所有类型都显示) ----
_dbTypeLabel = new ElaText("数据库类型");
_dbTypeLabel->setStyleSheet("font-size: 13px;");
_dbTypeComboBox = new ElaComboBox();
_dbTypeComboBox->addItems({"MySQL", "SQLite", "Oracle", "MDB-SQL"});
_formLayout->addWidget(dbTypeLabel, 1, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_dbTypeLabel, 1, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_dbTypeComboBox, 1, 2);
// Row 2: 主机地址
// ---- Row 2: 主机地址(MySQL/Oracle) ----
_hostLabel = new ElaText("<font color='red'>*</font>主机地址");
_hostLabel->setStyleSheet("font-size: 13px;");
_hostLineEdit = new ElaLineEdit();
@@ -62,7 +65,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_hostLabel, 2, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_hostLineEdit, 2, 2);
// Row 3: 端口
// ---- Row 3: 端口(MySQL/Oracle) ----
_portLabel = new ElaText("<font color='red'>*</font>端口");
_portLabel->setStyleSheet("font-size: 13px;");
_portLineEdit = new ElaLineEdit();
@@ -70,7 +73,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_portLabel, 3, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_portLineEdit, 3, 2);
// Row 4: 数据库名称
// ---- Row 4: 数据库名称(仅 MySQL) ----
_databaseNameLabel = new ElaText("数据库名称");
_databaseNameLabel->setStyleSheet("font-size: 13px;");
_databaseNameLineEdit = new ElaLineEdit();
@@ -78,7 +81,26 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_databaseNameLabel, 4, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_databaseNameLineEdit, 4, 2);
// Row 5: 用户名
// ---- Row 4b: SQLite 数据库文件 + 浏览(仅 SQLite)----
// 用 column 0,1,2,3 而非 row 4 列 1,2,3,避免与 _databaseNameLabel 同行冲突
// 这里用一个独立行(row 4 但 col 1,2 已被占用 → 改用 row 4 整个行被 MySQL 占用)
// 改用 addWidget 时 row=4 同一行,但仅 SQLite 时隐藏 _databaseNameLabel
_dbFileLabel = new ElaText("数据库文件");
_dbFileLabel->setStyleSheet("font-size: 13px;");
_dbFileLineEdit = new ElaLineEdit();
_dbFileLineEdit->setPlaceholderText("请选择 .db / .sqlite 文件");
_browseButton = new ElaPushButton("浏览...");
_browseButton->setFixedWidth(80);
// SQLite 行使用 row 4,但与"数据库名称"(MySQL)使用同一行
// 切换时只显示对应类型那一行的 widget
// 注意:row 4 已被 _databaseNameLabel/_databaseNameLineEdit 占用
// SQLite 的 label/file 放到 row 4 column 1,2;browse 放到 row 4 column 3
// 切换时通过 hide()/show() 切换可见性
_formLayout->addWidget(_dbFileLabel, 4, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_dbFileLineEdit, 4, 2);
_formLayout->addWidget(_browseButton, 4, 3, Qt::AlignVCenter);
// ---- Row 5: 用户名(MySQL/Oracle) ----
_userNameLabel = new ElaText("<font color='red'>*</font>用户名");
_userNameLabel->setStyleSheet("font-size: 13px;");
_userNameLineEdit = new ElaLineEdit();
@@ -86,7 +108,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_userNameLabel, 5, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_userNameLineEdit, 5, 2);
// Row 6: 密码
// ---- Row 6: 密码(MySQL/Oracle) ----
_passwordLabel = new ElaText("<font color='red'>*</font>密码");
_passwordLabel->setStyleSheet("font-size: 13px;");
_passwordLineEdit = new ElaLineEdit();
@@ -95,7 +117,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_passwordLabel, 6, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_passwordLineEdit, 6, 2);
// Row 7: 服务名
// ---- Row 7: 服务名(仅 Oracle) ----
_serviceNameLabel = new ElaText("<font color='red'>*</font>服务名");
_serviceNameLabel->setStyleSheet("font-size: 13px;");
_serviceNameLineEdit = new ElaLineEdit();
@@ -103,7 +125,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_serviceNameLabel, 7, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_serviceNameLineEdit, 7, 2);
// Row 8: 节点名称
// ---- Row 8: 节点名称(仅 MDB-SQL) ----
_nodeNameLabel = new ElaText("<font color='red'>*</font>节点名称");
_nodeNameLabel->setStyleSheet("font-size: 13px;");
_nodeNameLineEdit = new ElaLineEdit();
@@ -111,7 +133,7 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_nodeNameLabel, 8, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_nodeNameLineEdit, 8, 2);
// Row 9: 许可证编号
// ---- Row 9: 许可证编号(仅 MDB-SQL) ----
_licenseKeyLabel = new ElaText("许可证编号");
_licenseKeyLabel->setStyleSheet("font-size: 13px;");
_licenseKeyLineEdit = new ElaLineEdit();
@@ -119,19 +141,6 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
_formLayout->addWidget(_licenseKeyLabel, 9, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_licenseKeyLineEdit, 9, 2);
// Row 10: SQLite数据库文件路径
_sqliteFileLabel = new ElaText("<font color='red'>*</font>数据库文件");
_sqliteFileLabel->setStyleSheet("font-size: 13px;");
_sqliteFileLineEdit = new ElaLineEdit();
_sqliteFileLineEdit->setPlaceholderText("请选择或输入 SQLite 数据库文件路径");
_sqliteBrowseButton = new ElaToolButton(this);
_sqliteBrowseButton->setText("浏览...");
_formLayout->addWidget(_sqliteFileLabel, 10, 1, Qt::AlignRight | Qt::AlignVCenter);
_formLayout->addWidget(_sqliteFileLineEdit, 10, 2);
_formLayout->addWidget(_sqliteBrowseButton, 10, 3);
mainLayout->addLayout(_formLayout);
QHBoxLayout* buttonLayout = new QHBoxLayout();
buttonLayout->setSpacing(12);
@@ -147,10 +156,10 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
mainLayout->addLayout(buttonLayout);
connect(_dbTypeComboBox, &ElaComboBox::currentTextChanged, this, &ElaDatabaseConnectionDialog::onDbTypeChanged);
connect(_browseButton, &ElaPushButton::clicked, this, &ElaDatabaseConnectionDialog::onBrowseClicked);
connect(_testButton, &ElaPushButton::clicked, this, &ElaDatabaseConnectionDialog::onTestConnectionClicked);
connect(_okButton, &ElaPushButton::clicked, this, &ElaDatabaseConnectionDialog::onOkClicked);
connect(_cancelButton, &ElaPushButton::clicked, this, &ElaDatabaseConnectionDialog::reject);
connect(_sqliteBrowseButton, &ElaToolButton::clicked, this, &ElaDatabaseConnectionDialog::onBrowseSqliteFile);
connect(_hostLineEdit, &ElaLineEdit::textChanged, this, &ElaDatabaseConnectionDialog::onHostTextChanged);
connect(_portLineEdit, &ElaLineEdit::textChanged, this, &ElaDatabaseConnectionDialog::onPortTextChanged);
@@ -158,8 +167,8 @@ ElaDatabaseConnectionDialog::ElaDatabaseConnectionDialog(QWidget* parent)
connect(_serviceNameLineEdit, &ElaLineEdit::textChanged, this, &ElaDatabaseConnectionDialog::onServiceNameTextChanged);
connect(_nodeNameLineEdit, &ElaLineEdit::textChanged, this, &ElaDatabaseConnectionDialog::onNodeNameTextChanged);
// 初始化可见性(不再清空 layout)
updateFormFields();
adjustSize();
}
ElaDatabaseConnectionDialog::~ElaDatabaseConnectionDialog()
@@ -168,72 +177,62 @@ ElaDatabaseConnectionDialog::~ElaDatabaseConnectionDialog()
void ElaDatabaseConnectionDialog::updateFormFields()
{
// 不动 layout:通过 hide/show 切换可见性,避免 widget 漂移或丢失
// 所有 widget 已在构造函数中添加到 _formLayout 的固定 row/col,
// 此处仅按 dbType 控制每行 widget 的可见性。
QString dbType = _dbTypeComboBox->currentText();
// 连接名称始终显示
_connectionNameLabel->show();
_connectionNameLineEdit->show();
// 共用:连接名称、数据库类型
_connectionNameLabel->setVisible(true);
_connectionNameLineEdit->setVisible(true);
_dbTypeLabel->setVisible(true);
_dbTypeComboBox->setVisible(true);
// 默认隐藏可选字段
_hostLabel->hide();
_hostLineEdit->hide();
_portLabel->hide();
_portLineEdit->hide();
_databaseNameLabel->hide();
_databaseNameLineEdit->hide();
_userNameLabel->hide();
_userNameLineEdit->hide();
_passwordLabel->hide();
_passwordLineEdit->hide();
_serviceNameLabel->hide();
_serviceNameLineEdit->hide();
_nodeNameLabel->hide();
_nodeNameLineEdit->hide();
_licenseKeyLabel->hide();
_licenseKeyLineEdit->hide();
_sqliteFileLabel->hide();
_sqliteFileLineEdit->hide();
_sqliteBrowseButton->hide();
// 默认全部隐藏
auto hideAll = [&]() {
_hostLabel->hide(); _hostLineEdit->hide();
_portLabel->hide(); _portLineEdit->hide();
_databaseNameLabel->hide(); _databaseNameLineEdit->hide();
_dbFileLabel->hide(); _dbFileLineEdit->hide(); _browseButton->hide();
_userNameLabel->hide(); _userNameLineEdit->hide();
_passwordLabel->hide(); _passwordLineEdit->hide();
_serviceNameLabel->hide(); _serviceNameLineEdit->hide();
_nodeNameLabel->hide(); _nodeNameLineEdit->hide();
_licenseKeyLabel->hide(); _licenseKeyLineEdit->hide();
};
if (dbType == "MDB-SQL") {
_nodeNameLabel->show();
_nodeNameLineEdit->show();
_licenseKeyLabel->show();
_licenseKeyLineEdit->show();
} else if (dbType == "Oracle") {
_hostLabel->show();
_hostLineEdit->show();
_portLabel->show();
_portLineEdit->show();
_userNameLabel->show();
_userNameLineEdit->show();
_passwordLabel->show();
_passwordLineEdit->show();
_serviceNameLabel->show();
_serviceNameLineEdit->show();
if (dbType == "SQLite") {
hideAll();
_dbFileLabel->show(); _dbFileLineEdit->show(); _browseButton->show();
} else if (dbType == "MySQL") {
_hostLabel->show();
_hostLineEdit->show();
_portLabel->show();
_portLineEdit->show();
_databaseNameLabel->show();
_databaseNameLineEdit->show();
_userNameLabel->show();
_userNameLineEdit->show();
_passwordLabel->show();
_passwordLineEdit->show();
} else if (dbType == "SQLite") {
// SQLite 需要数据库文件路径
_sqliteFileLabel->show();
_sqliteFileLineEdit->show();
_sqliteBrowseButton->show();
hideAll();
_hostLabel->show(); _hostLineEdit->show();
_portLabel->show(); _portLineEdit->show();
_databaseNameLabel->show(); _databaseNameLineEdit->show();
_userNameLabel->show(); _userNameLineEdit->show();
_passwordLabel->show(); _passwordLineEdit->show();
} else if (dbType == "Oracle") {
hideAll();
_hostLabel->show(); _hostLineEdit->show();
_portLabel->show(); _portLineEdit->show();
_userNameLabel->show(); _userNameLineEdit->show();
_passwordLabel->show(); _passwordLineEdit->show();
_serviceNameLabel->show(); _serviceNameLineEdit->show();
} else if (dbType == "MDB-SQL") {
hideAll();
_nodeNameLabel->show(); _nodeNameLineEdit->show();
_licenseKeyLabel->show(); _licenseKeyLineEdit->show();
} else {
hideAll();
}
// 窗口高度随显示的控件数量自适应(标题位置因固定在 VBoxLayout 顶部而不变)
adjustSize();
}
void ElaDatabaseConnectionDialog::onDbTypeChanged(const QString& /*type*/)
{
updateFormFields();
adjustSize();
}
void ElaDatabaseConnectionDialog::onHostTextChanged(const QString& text)
@@ -316,13 +315,6 @@ QString ElaDatabaseConnectionDialog::getConnectionName() const
QString ElaDatabaseConnectionDialog::getDatabaseName() const
{
if (_dbTypeComboBox->currentText() == "SQLite") {
return _sqliteFileLineEdit->text();
}
// Oracle 使用服务名作为 database 字段
if (_dbTypeComboBox->currentText() == "Oracle") {
return _serviceNameLineEdit->text();
}
return _databaseNameLineEdit->text();
}
@@ -351,6 +343,29 @@ QString ElaDatabaseConnectionDialog::getLicenseKey() const
return _licenseKeyLineEdit->text();
}
QString ElaDatabaseConnectionDialog::getDatabaseFileName() const
{
return _dbFileLineEdit->text();
}
void ElaDatabaseConnectionDialog::setDatabaseFileName(const QString& fileName)
{
_dbFileLineEdit->setText(fileName);
}
void ElaDatabaseConnectionDialog::onBrowseClicked()
{
QString fileName = QFileDialog::getOpenFileName(
this,
"选择 SQLite 数据库文件",
QString(),
"SQLite 数据库 (*.db *.sqlite *.db3 *.sqlite3);;所有文件 (*.*)");
if (!fileName.isEmpty()) {
_dbFileLineEdit->setText(fileName);
clearErrorStyle(_dbFileLineEdit);
}
}
void ElaDatabaseConnectionDialog::setDatabaseType(const QString& type)
{
int index = _dbTypeComboBox->findText(type);
@@ -377,13 +392,7 @@ void ElaDatabaseConnectionDialog::setConnectionName(const QString& name)
void ElaDatabaseConnectionDialog::setDatabaseName(const QString& name)
{
if (_dbTypeComboBox->currentText() == "SQLite") {
_sqliteFileLineEdit->setText(name);
} else if (_dbTypeComboBox->currentText() == "Oracle") {
_serviceNameLineEdit->setText(name);
} else {
_databaseNameLineEdit->setText(name);
}
_databaseNameLineEdit->setText(name);
}
void ElaDatabaseConnectionDialog::setUserName(const QString& userName)
@@ -416,22 +425,12 @@ void ElaDatabaseConnectionDialog::onTestConnectionClicked()
QString dbType = _dbTypeComboBox->currentText();
QString host = _hostLineEdit->text();
QString port = _portLineEdit->text();
QString database = _databaseNameLineEdit->text();
QString username = _userNameLineEdit->text();
QString password = _passwordLineEdit->text();
QString sqliteFile = _sqliteFileLineEdit->text();
bool hasError = false;
// 字段校验
if (dbType == "SQLite") {
if (sqliteFile.isEmpty()) {
setErrorStyle(_sqliteFileLineEdit);
hasError = true;
}
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请选择 SQLite 数据库文件", 3000, this);
return;
}
} else {
if (dbType != "SQLite") {
if (host.isEmpty()) {
setErrorStyle(_hostLineEdit);
hasError = true;
@@ -440,73 +439,90 @@ void ElaDatabaseConnectionDialog::onTestConnectionClicked()
setErrorStyle(_portLineEdit);
hasError = true;
}
if ((dbType == "MySQL" || dbType == "Oracle") && password.isEmpty()) {
}
if (dbType == "MySQL" && password.isEmpty()) {
setErrorStyle(_passwordLineEdit);
hasError = true;
}
if (dbType == "Oracle") {
if (username.isEmpty()) {
setErrorStyle(_userNameLineEdit);
hasError = true;
}
if (password.isEmpty()) {
setErrorStyle(_passwordLineEdit);
hasError = true;
}
if (dbType == "Oracle") {
if (username.isEmpty()) {
setErrorStyle(_userNameLineEdit);
hasError = true;
}
if (_serviceNameLineEdit->text().isEmpty()) {
setErrorStyle(_serviceNameLineEdit);
hasError = true;
}
}
if (dbType == "MDB-SQL") {
if (_nodeNameLineEdit->text().isEmpty()) {
setErrorStyle(_nodeNameLineEdit);
hasError = true;
}
}
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请填写所有必填项", 3000, this);
return;
if (_serviceNameLineEdit->text().isEmpty()) {
setErrorStyle(_serviceNameLineEdit);
hasError = true;
}
}
// 构造 ConnectionParams,复用 createConnector() 使测试连接与实际连接使用完全相同逻辑
ConnectionParams params;
params.dbType = dbType;
params.host = host;
params.port = port;
params.database = getDatabaseName(); // Oracle 返回服务名,SQLite 返回文件路径
params.username = username;
params.password = password;
if (dbType == "MDB-SQL") {
if (_nodeNameLineEdit->text().isEmpty()) {
setErrorStyle(_nodeNameLineEdit);
hasError = true;
}
}
DatabaseConnector* connector = createConnector(params, "test_connection");
if (!connector) {
ElaMessageBar::error(ElaMessageBarType::Top, "错误", "不支持的数据库类型: " + dbType, 3000, this);
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请填写所有必填项", 3000, this);
return;
}
if (connector->open()) {
ElaMessageBar::success(ElaMessageBarType::Top, "成功", "连接测试成功", 3000, this);
connector->close();
} else {
ElaMessageBar::error(ElaMessageBarType::Top, "错误", "无法连接数据库: " + connector->database().lastError().text(), 5000, this);
QString driverName;
if (dbType == "MySQL") {
driverName = "QMYSQL";
} else if (dbType == "SQLite") {
driverName = "QSQLITE";
} else if (dbType == "Oracle") {
driverName = "QOCI";
}
delete connector;
QString connectionName = "test_connection";
if (QSqlDatabase::contains(connectionName)) {
QSqlDatabase::removeDatabase(connectionName);
}
QSqlDatabase db = QSqlDatabase::addDatabase(driverName, connectionName);
if (dbType == "SQLite") {
if (_dbFileLineEdit->text().isEmpty()) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请选择 SQLite 数据库文件", 3000, this);
return;
}
db.setDatabaseName(_dbFileLineEdit->text());
} else {
db.setHostName(host);
db.setPort(port.toInt());
db.setDatabaseName(database);
db.setUserName(username);
db.setPassword(password);
}
if (db.open()) {
ElaMessageBar::success(ElaMessageBarType::Top, "成功", "连接测试成功", 3000, this);
db.close();
} else {
ElaMessageBar::error(ElaMessageBarType::Top, "错误", "无法连接数据库: " + db.lastError().text(), 5000, this);
}
QSqlDatabase::removeDatabase(connectionName);
}
void ElaDatabaseConnectionDialog::onOkClicked()
{
QString dbType = _dbTypeComboBox->currentText();
QString sqliteFile = _sqliteFileLineEdit->text();
bool hasError = false;
// SQLite 特殊处理
if (dbType == "SQLite") {
if (sqliteFile.isEmpty()) {
setErrorStyle(_sqliteFileLineEdit);
if (_dbFileLineEdit->text().isEmpty()) {
setErrorStyle(_dbFileLineEdit);
hasError = true;
}
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请选择 SQLite 数据库文件", 3000, this);
return;
}
} else {
if (_hostLineEdit->text().isEmpty()) {
setErrorStyle(_hostLineEdit);
@@ -517,52 +533,39 @@ void ElaDatabaseConnectionDialog::onOkClicked()
setErrorStyle(_portLineEdit);
hasError = true;
}
}
if (dbType == "MySQL" && _passwordLineEdit->text().isEmpty()) {
if (dbType == "MySQL" && _passwordLineEdit->text().isEmpty()) {
setErrorStyle(_passwordLineEdit);
hasError = true;
}
if (dbType == "Oracle") {
if (_userNameLineEdit->text().isEmpty()) {
setErrorStyle(_userNameLineEdit);
hasError = true;
}
if (_passwordLineEdit->text().isEmpty()) {
setErrorStyle(_passwordLineEdit);
hasError = true;
}
if (dbType == "Oracle") {
if (_userNameLineEdit->text().isEmpty()) {
setErrorStyle(_userNameLineEdit);
hasError = true;
}
if (_passwordLineEdit->text().isEmpty()) {
setErrorStyle(_passwordLineEdit);
hasError = true;
}
if (_serviceNameLineEdit->text().isEmpty()) {
setErrorStyle(_serviceNameLineEdit);
hasError = true;
}
if (_serviceNameLineEdit->text().isEmpty()) {
setErrorStyle(_serviceNameLineEdit);
hasError = true;
}
}
if (dbType == "MDB-SQL") {
if (_nodeNameLineEdit->text().isEmpty()) {
setErrorStyle(_nodeNameLineEdit);
hasError = true;
}
if (dbType == "MDB-SQL") {
if (_nodeNameLineEdit->text().isEmpty()) {
setErrorStyle(_nodeNameLineEdit);
hasError = true;
}
}
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请填写所有必填项", 3000, this);
return;
}
if (hasError) {
ElaMessageBar::warning(ElaMessageBarType::Top, "警告", "请填写所有必填项", 3000, this);
return;
}
accept();
}
void ElaDatabaseConnectionDialog::onBrowseSqliteFile()
{
QString filePath = QFileDialog::getOpenFileName(
this,
"选择 SQLite 数据库文件",
QDir::homePath(),
"SQLite 数据库文件 (*.db *.sqlite *.sqlite3 *.db3);;所有文件 (*)"
);
if (!filePath.isEmpty()) {
_sqliteFileLineEdit->setText(filePath);
}
}
+10 -6
View File
@@ -2,13 +2,14 @@
#define ELADATABASECONNECTIONDIALOG_H
#include <QDialog>
#include <QLabel>
#include <QGridLayout>
#include "ElaLineEdit.h"
#include "ElaComboBox.h"
#include "ElaPushButton.h"
#include "ElaText.h"
class ElaToolButton;
class QGridLayout;
class ElaDatabaseConnectionDialog : public QDialog
{
@@ -22,6 +23,8 @@ public:
QString getPort() const;
QString getConnectionName() const;
QString getDatabaseName() const;
QString getDatabaseFileName() const;
void setDatabaseFileName(const QString& fileName);
QString getUserName() const;
QString getPassword() const;
QString getServiceName() const;
@@ -48,7 +51,7 @@ private Q_SLOTS:
void onPasswordTextChanged(const QString& text);
void onServiceNameTextChanged(const QString& text);
void onNodeNameTextChanged(const QString& text);
void onBrowseSqliteFile();
void onBrowseClicked();
private:
void updateFormFields();
@@ -57,6 +60,11 @@ private:
QGridLayout* _formLayout;
ElaComboBox* _dbTypeComboBox;
ElaText* _dbTypeLabel;
ElaText* _dbFileLabel;
ElaLineEdit* _dbFileLineEdit;
ElaPushButton* _browseButton;
ElaText* _hostLabel;
ElaLineEdit* _hostLineEdit;
@@ -85,10 +93,6 @@ private:
ElaText* _licenseKeyLabel;
ElaLineEdit* _licenseKeyLineEdit;
ElaText* _sqliteFileLabel;
ElaLineEdit* _sqliteFileLineEdit;
ElaToolButton* _sqliteBrowseButton;
ElaPushButton* _testButton;
ElaPushButton* _okButton;
ElaPushButton* _cancelButton;
+2
View File
@@ -24,6 +24,8 @@ void MainWindow::initWindow()
resize(900, 600);
setMinimumSize(800, 500);
setUserInfoCardVisible(false);
// 默认以最大化窗口启动
showMaximized();
// 隐藏返回和前进按钮
+49
View File
@@ -33,7 +33,9 @@
#include <QTextEdit>
#include <QRegularExpression>
#include <QSet>
#include <QSettings>
#include "utils/logmanager.h"
#include "utils/configmanager.h"
#include <Qsci/qsciscintilla.h>
#include <Qsci/qscilexersql.h>
#include <Qsci/qsciapis.h>
@@ -325,14 +327,50 @@ void DatabaseManagerPage::onConnectionManage()
QString selectedKey = dialog.getSelectedConnectionKey();
if (!selectedKey.isEmpty()) {
_currentConnectionKey = selectedKey;
// 记住本次手动加载的连接,作为下一次启动的默认连接
markDefaultConnection(selectedKey);
updateConnectionInfo();
refreshTables();
}
}
}
void DatabaseManagerPage::markDefaultConnection(const QString& key)
{
if (key.isEmpty()) return;
QSettings* settings = appConnectionsSettings();
const QStringList groups = settings->childGroups();
for (const QString& group : groups) {
settings->beginGroup(group);
settings->setValue("isDefault", (group == key));
settings->endGroup();
}
settings->sync();
}
QString DatabaseManagerPage::getDefaultConnectionKey()
{
QSettings* settings = appConnectionsSettings();
const QStringList groups = settings->childGroups();
for (const QString& group : groups) {
settings->beginGroup(group);
bool isDefault = settings->value("isDefault", false).toBool();
settings->endGroup();
if (isDefault)
return group;
}
return QString();
}
void DatabaseManagerPage::loadConnections()
{
// 启动时自动连接上一次加载(设为默认)的数据库
QString defaultKey = getDefaultConnectionKey();
if (!defaultKey.isEmpty() && ConnectionParams::fromSettings(defaultKey).dbType != "") {
_currentConnectionKey = defaultKey;
updateConnectionInfo();
refreshTables();
}
}
void DatabaseManagerPage::refreshTables()
@@ -344,6 +382,13 @@ void DatabaseManagerPage::refreshTables()
// 切换连接时关闭旧连接,确保重新建立新数据库连接
if (_connector) {
// 关键:先解绑视图并销毁旧的 EditableSqlModel,
// 否则 _dataModel 内部持有的 QSqlQuery 仍指向即将被删除的数据库连接,导致后续访问崩溃
if (_dataTableView) _dataTableView->setModel(nullptr);
if (_dataModel) {
delete _dataModel;
_dataModel = nullptr;
}
delete _connector;
_connector = nullptr;
}
@@ -351,6 +396,10 @@ void DatabaseManagerPage::refreshTables()
_currentTableName.clear();
_lastExecutedSql.clear();
_currentPage = 1;
if (!_dataModel) {
_dataModel = new EditableSqlModel(this);
if (_dataTableView) _dataTableView->setModel(_dataModel);
}
_dataModel->clear();
_dataModel->clearChanges();
+27 -15
View File
@@ -2,16 +2,22 @@
#define DATABASEMANAGERPAGE_H
#include <QWidget>
#include <QTableView>
#include <QLineEdit>
#include <QSqlQueryModel>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QSplitter>
#include <QListView>
#include <QLabel>
#include <QComboBox>
#include <QGroupBox>
#include <QCoreApplication>
class QsciScintilla;
class QsciLexerSQL;
class QsciAPIs;
class QComboBox;
class EditableSqlModel;
class ElaTableView;
class ElaLineEdit;
class ElaPushButton;
@@ -19,8 +25,9 @@ class ElaToolButton;
class ElaComboBox;
class ElaListView;
class ElaTabWidget;
class EditableSqlModel;
class DatabaseConnector;
struct ConnectionParams;
class DatabaseManagerPage : public QWidget
{
@@ -39,24 +46,27 @@ private:
bool openDatabase();
void updateConnectionInfo();
void onConnectionManage();
static void markDefaultConnection(const QString& key);
static QString getDefaultConnectionKey();
void onTableDoubleClicked(const QModelIndex& index);
void onExecuteSql();
void onTableSearchTextChanged(const QString& text);
void onSubmitChanges();
void onExportData();
void onPrevPage();
void onNextPage();
void onPageSizeChanged(int index);
void onPreviewChanges();
void updateUndoRedoButtons();
QWidget* createSqlEditorTab();
QsciScintilla* currentEditor() const;
void onAddTab();
void loadTableData(int page = 1);
void loadTableData(int page);
void onPrevPage();
void onNextPage();
void onPageSizeChanged(int index);
QString getCurrentSqlContent();
int _tabCounter = 0;
int _currentPage = 1;
int _pageSize = 100;
private:
ElaListView* _tableView;
@@ -68,23 +78,25 @@ private:
ElaToolButton* _addRecordButton;
ElaToolButton* _submitButton;
ElaToolButton* _exportButton;
QLabel* _connectionInfoLabel;
QLabel* _rowCountLabel;
QLabel* _pendingChangesLabel;
QLabel* _pageLabel;
ElaToolButton* _prevButton;
ElaToolButton* _nextButton;
QLabel* _connectionInfoLabel;
QLabel* _rowCountLabel;
QLabel* _pageLabel;
QLabel* _pendingChangesLabel;
QComboBox* _pageSizeCombo;
ElaTabWidget* _sqlTabWidget;
EditableSqlModel* _dataModel;
QStandardItemModel* _tableModel;
QSortFilterProxyModel* _tableProxyModel;
DatabaseConnector* _connector = nullptr;
QString _currentConnectionKey;
QString _currentTableName;
QString _lastExecutedSql;
DatabaseConnector* _connector = nullptr; // 当前数据库连接器
QString _lastConnectedKey;
int _currentPage = 1;
int _pageSize = 100;
QList<QsciScintilla*> _editorList;
QList<QsciAPIs*> _apisList;
+19 -2
View File
@@ -24,9 +24,9 @@ ConfigManager* ConfigManager::instance()
return _instance;
}
void ConfigManager::loadConfig(const QString& basePath)
void ConfigManager::loadConfig()
{
_configPath = QDir(basePath).filePath("config.ini");
_configPath = QDir(appConfigDir()).filePath("config.ini");
_settings = new QSettings(_configPath, QSettings::IniFormat);
_settings->beginGroup("Database");
@@ -117,3 +117,20 @@ void ConfigManager::saveConfig()
{
_settings->sync();
}
QString appConfigDir()
{
QString dir = QDir(QCoreApplication::applicationDirPath()).filePath("config");
QDir().mkpath(dir);
return dir;
}
QSettings* appConnectionsSettings()
{
static QSettings* s = nullptr;
if (!s) {
QString path = QDir(appConfigDir()).filePath("config.ini");
s = new QSettings(path, QSettings::IniFormat);
}
return s;
}
+5 -1
View File
@@ -9,7 +9,7 @@ class ConfigManager
public:
static ConfigManager* instance();
void loadConfig(const QString& basePath);
void loadConfig();
QString getDatabaseHost() const;
QString getDatabasePort() const;
@@ -36,4 +36,8 @@ private:
QString _configPath;
};
// 指向 "程序目录/config/config.ini" 的共享 QSettings(IniFormat),用于数据库连接列表存储
QSettings* appConnectionsSettings();
QString appConfigDir();
#endif // CONFIGMANAGER_H