diff --git a/main.cpp b/main.cpp index b29f211..de1d42f 100644 --- a/main.cpp +++ b/main.cpp @@ -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(); } \ No newline at end of file diff --git a/src/connectors/DatabaseConnector.h b/src/connectors/DatabaseConnector.h index fc5b817..1754c5a 100644 --- a/src/connectors/DatabaseConnector.h +++ b/src/connectors/DatabaseConnector.h @@ -5,6 +5,7 @@ #include #include #include +#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; } }; diff --git a/src/dialogs/DatabaseConnectionConfigDialog.cpp b/src/dialogs/DatabaseConnectionConfigDialog.cpp index cb3a713..37f3e47 100644 --- a/src/dialogs/DatabaseConnectionConfigDialog.cpp +++ b/src/dialogs/DatabaseConnectionConfigDialog.cpp @@ -9,11 +9,14 @@ #include #include #include +#include #include #include #include #include +#include #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) { diff --git a/src/dialogs/DatabaseConnectionConfigDialog.h b/src/dialogs/DatabaseConnectionConfigDialog.h index 27baca3..0169e6f 100644 --- a/src/dialogs/DatabaseConnectionConfigDialog.h +++ b/src/dialogs/DatabaseConnectionConfigDialog.h @@ -3,6 +3,7 @@ #include #include +#include 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; diff --git a/src/dialogs/ElaDatabaseConnectionDialog.cpp b/src/dialogs/ElaDatabaseConnectionDialog.cpp index efc8faa..3a6fe19 100644 --- a/src/dialogs/ElaDatabaseConnectionDialog.cpp +++ b/src/dialogs/ElaDatabaseConnectionDialog.cpp @@ -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 #include #include @@ -14,31 +11,37 @@ #include #include #include -#include 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("*主机地址"); _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("*端口"); _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("*用户名"); _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("*密码"); _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("*服务名"); _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("*节点名称"); _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("*数据库文件"); - _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); - } } \ No newline at end of file diff --git a/src/dialogs/ElaDatabaseConnectionDialog.h b/src/dialogs/ElaDatabaseConnectionDialog.h index aa4c0ab..eecdfa1 100644 --- a/src/dialogs/ElaDatabaseConnectionDialog.h +++ b/src/dialogs/ElaDatabaseConnectionDialog.h @@ -2,13 +2,14 @@ #define ELADATABASECONNECTIONDIALOG_H #include +#include #include #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,7 +60,12 @@ private: QGridLayout* _formLayout; ElaComboBox* _dbTypeComboBox; + ElaText* _dbTypeLabel; + ElaText* _dbFileLabel; + ElaLineEdit* _dbFileLineEdit; + ElaPushButton* _browseButton; + ElaText* _hostLabel; ElaLineEdit* _hostLineEdit; @@ -84,10 +92,6 @@ private: ElaText* _licenseKeyLabel; ElaLineEdit* _licenseKeyLineEdit; - - ElaText* _sqliteFileLabel; - ElaLineEdit* _sqliteFileLineEdit; - ElaToolButton* _sqliteBrowseButton; ElaPushButton* _testButton; ElaPushButton* _okButton; diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index a65f11f..0815fca 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -24,6 +24,8 @@ void MainWindow::initWindow() resize(900, 600); setMinimumSize(800, 500); setUserInfoCardVisible(false); + // 默认以最大化窗口启动 + showMaximized(); // 隐藏返回和前进按钮 diff --git a/src/pages/DatabaseManagerPage.cpp b/src/pages/DatabaseManagerPage.cpp index 91f89be..96b80bd 100644 --- a/src/pages/DatabaseManagerPage.cpp +++ b/src/pages/DatabaseManagerPage.cpp @@ -33,7 +33,9 @@ #include #include #include +#include #include "utils/logmanager.h" +#include "utils/configmanager.h" #include #include #include @@ -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(); diff --git a/src/pages/DatabaseManagerPage.h b/src/pages/DatabaseManagerPage.h index 38e488b..f5ea86e 100644 --- a/src/pages/DatabaseManagerPage.h +++ b/src/pages/DatabaseManagerPage.h @@ -2,16 +2,22 @@ #define DATABASEMANAGERPAGE_H #include +#include +#include +#include #include #include +#include +#include #include -#include +#include +#include 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 _editorList; QList _apisList; diff --git a/src/utils/configmanager.cpp b/src/utils/configmanager.cpp index bf20808..a08ad72 100644 --- a/src/utils/configmanager.cpp +++ b/src/utils/configmanager.cpp @@ -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"); @@ -116,4 +116,21 @@ void ConfigManager::setDatabaseType(const QString& type) 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; } \ No newline at end of file diff --git a/src/utils/configmanager.h b/src/utils/configmanager.h index da9d7c4..2b22443 100644 --- a/src/utils/configmanager.h +++ b/src/utils/configmanager.h @@ -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 \ No newline at end of file