diff --git a/CMakeLists.txt b/CMakeLists.txt index 776f594..46642cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set(CMAKE_AUTOUIC_SEARCH_PATHS "ui") set(H_HEADER_FILES include/global.h include/logger.h - include/mainWindow.h + include/mainwindow.h include/dbManager.h include/dbBrowser.h include/dbStructureNode.h @@ -32,13 +32,15 @@ set(H_HEADER_FILES include/customMenu.h include/modelInfoEditDialog.h include/sqlQueryExecutor.h + include/attributeTableModel.h + include/attributeView.h ) set(CPP_SOURCE_FILES source/main.cpp source/global.cpp source/logger.cpp - source/mainWindow.cpp + source/mainwindow.cpp source/dbManager.cpp source/dbBrowser.cpp source/dbStructureNode.cpp @@ -51,10 +53,12 @@ set(CPP_SOURCE_FILES source/customMenu.cpp source/modelInfoEditDialog.cpp source/sqlQueryExecutor.cpp + source/attributeTableModel.cpp + source/attributeView.cpp ) set(UI_FILES - ui/mainWindow.ui + ui/mainwindow.ui ui/dbBrowser.ui ui/connectionDialog.ui ui/messageDialog.ui diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index 702be04..a1fa6e3 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/include/attributeTableModel.h b/include/attributeTableModel.h new file mode 100644 index 0000000..c713d1c --- /dev/null +++ b/include/attributeTableModel.h @@ -0,0 +1,80 @@ +#ifndef ATTRIBUTETABLEMODEL_H +#define ATTRIBUTETABLEMODEL_H + +/** + * @brief 用来处理attribute数据的Model类 + * + * 基本功能包括: + * 1、可以自定义显示数据表中的哪些列 + * 2、可以分页显示并自定义每页展示数量 + * 3、编辑的数据可以突出展示(如加粗、改色) + * 4、最前方加入一个用于展示行号的列(行号从1开始) + * 5、点击行号列可以实现选中标识(通过icon) + * 6、哪一行被编辑,改行的行号指示可以加*进行标识 + * + */ + +#include +#include + +class AttributeTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + enum EditState + { + Clean = 0, + Modified, + New, + Deleted + }; + + explicit AttributeTableModel(QObject* parent = nullptr + , const QString& connection = "" + , const QString& modelID = "" + , const QString& groupID = "" + , const QString& tableName = "basic.attribute"); + ~AttributeTableModel(); + + QVariant data(const QModelIndex& index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + //分页控制 + void setPageSize(int); + int pageSize() const; + void setCurrentPage(int); + int currentPage() const; + int totalPages() const; + + //展示列控制 + void setVisibleColumns(const QStringList& columns); + +private: + struct RowData + { + QSqlRecord record; + EditState state = Clean; + }; + + void loadPageData(); // 加载当前页数据 + void updateTotalCount(); // 更新总记录数 + + QString m_connection; + QString m_modelID; + QString m_groupID; + QString m_tableName; + + int m_pageSize; + int m_currentPage; + int m_totalCount; + QStringList m_visibleColumns; + QList m_currentPageData; + QHash m_modifiedRows; //key:global row number +}; + +#endif //ATTRIBUTETABLEMODEL_H diff --git a/include/attributeView.h b/include/attributeView.h new file mode 100644 index 0000000..13c6e06 --- /dev/null +++ b/include/attributeView.h @@ -0,0 +1,33 @@ +#ifndef ATTRIBUTEVIEW_H +#define ATTRIBUTEVIEW_H + +#include + +class QTableView; +class AttributeTableModel; +class QVBoxLayout; + +class AttributeView : public QWidget +{ + Q_OBJECT + +public: + AttributeView(QWidget *parent = nullptr + , const QString& connection = "" + , const QString& modelID = "" + , const QString& groupID = "" + , const QString& tableName = "basic.attribute"); + ~AttributeView(); + +private: + QString m_connection; + QString m_modelID; + QString m_groupID; + QString m_attributeTable; + + QTableView* m_tableView; + AttributeTableModel* m_attributeTableModel; + QVBoxLayout* m_vLayout; +}; + +#endif //ATTRIBUTEVIEW_H diff --git a/include/customTab.h b/include/customTab.h new file mode 100644 index 0000000..3d5d042 --- /dev/null +++ b/include/customTab.h @@ -0,0 +1,41 @@ +#ifndef CUSTOMTAB_H +#define CUSTOMTAB_H + +#include + +class QLabel; +class QPushButton; +class QBoxLayout; +class CustomTab : public QWidget +{ + Q_OBJECT + +public: + CustomTab(QWidget *parent = nullptr); + virtual ~CustomTab(); + + void setText(const QString&); + const QString text(); + + void setIcon(const QIcon&); + +signals: + void closeTab(QWidget*); + +protected: + void enterEvent(QEnterEvent*); + void leaveEvent(QEvent*); + +private slots: + void onCloseButtonClicked(); + +private: + QIcon m_Icon; + QSize m_IconSize; + QLabel* m_pIconLabel; + QLabel* m_pTitle; + QPushButton* m_pCloseBtn; + QBoxLayout* m_pLayout; +}; + +#endif //CUSTOMTAB_H diff --git a/include/dbBrowser.h b/include/dbBrowser.h index 6e55f0f..cf8b952 100644 --- a/include/dbBrowser.h +++ b/include/dbBrowser.h @@ -1,3 +1,7 @@ +#ifndef DBBROWSER_H +#define DBBROWSER_H + +#include "global.h" #include QT_BEGIN_NAMESPACE @@ -6,7 +10,7 @@ class DatabaseBrowser; } QT_END_NAMESPACE - +class AttributeView; class DatabaseBrowser : public QWidget { Q_OBJECT @@ -15,6 +19,14 @@ public: DatabaseBrowser(QWidget *parent = nullptr); ~DatabaseBrowser(); + void addTab_attribute(const QString&, ModelAttributeGroup&); + +private slots: + void closeTab(QWidget*); + private: Ui::DatabaseBrowser *ui; + QList m_attributeViewList; }; + +#endif //DBBROWSER_H diff --git a/include/dbStructureView.h b/include/dbStructureView.h index f0c731e..c62a5c8 100644 --- a/include/dbStructureView.h +++ b/include/dbStructureView.h @@ -1,6 +1,7 @@ #ifndef DBSTRUCTUREVIEW_H #define DBSTRUCTUREVIEW_H +#include "global.h" #include class MainWindow; @@ -36,6 +37,7 @@ private: signals: void actionTrigger_addModel(); + void openAttributeInfo(const QString&, ModelAttributeGroup&); private slots: void itemDoubleClick(const QModelIndex&); diff --git a/include/global.h b/include/global.h index 5950e7b..134ac67 100644 --- a/include/global.h +++ b/include/global.h @@ -72,6 +72,19 @@ struct Model }; +struct ModelAttributeGroup +{ + int modelID; + int groupID; + QString strModelName; + QString strGroupName; + + ModelAttributeGroup(int modelID, int groupID, QString strModelName, QString strGroupName) + : modelID(modelID), + groupID(groupID), + strModelName(std::move(strModelName)), + strGroupName(std::move(strGroupName)){} +}; class DatabaseException : public std::runtime_error { diff --git a/include/logger.h b/include/logger.h index 0e5fa6c..a9dd5f6 100644 --- a/include/logger.h +++ b/include/logger.h @@ -3,7 +3,6 @@ #include #include -#include #include // 日志宏定义 diff --git a/include/mainwindow.h b/include/mainwindow.h index 42f04b7..5376e84 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -58,6 +58,7 @@ private slots: void onSIG_errorFormSQLExecutor(const QString& error); void onSIG_connectionStatusChanged(const QString& strConnectionName, bool bConnected); void onSIG_addModel(Model&); + void onSIG_openAttributeInfo(const QString&, ModelAttributeGroup&); }; #endif // MAINWINDOW_H diff --git a/include/sqlQueryExecutor.h b/include/sqlQueryExecutor.h index 71f8871..20d2030 100644 --- a/include/sqlQueryExecutor.h +++ b/include/sqlQueryExecutor.h @@ -28,7 +28,8 @@ public: bool addModel(const QString&, Model&); bool modelNameExistsInDB(const QString&, const QString&); bool modelTypeExistsInDB(const QString&, const QString&); - bool removeMode(const QString&, int); + bool removeModel(const QString&, int); + int getAttributeCount(const QString&, const QString&); signals: void errorOccurred(const QString& error); diff --git a/include/tableEditModel.h b/include/tableEditModel.h new file mode 100644 index 0000000..14cd2a5 --- /dev/null +++ b/include/tableEditModel.h @@ -0,0 +1,61 @@ +#ifndef TABLEEDITMODEL_H +#define TABLEEDITMODEL_H + +/** + * @brief 用来加载显示数据库中数据表的Model类 + * + * 基本功能包括: + * 1、可以自定义显示数据表中的哪些列 + * 2、可以分页显示并自定义每页展示数量 + * 3、编辑的数据可以突出展示(如加粗、改色) + * 4、最前方加入一个用于展示行号的列(行号从1开始) + * 5、点击行号列可以实现选中标识(通过icon) + * 6、哪一行被编辑,改行的行号指示可以加*进行标识 + * + */ + +#include +#include + +class TableEditModel : public QSqlTableModel +{ + Q_OBJECT +public: + explicit TableEditModel(QObject* parent = nullptr, const QSqlDatabase& db = QSqlDatabase(), const QStringList &visibleColumns = {}); + ~TableEditModel(); + + QVariant data(const QModelIndex& index, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + //分页控制 + void setPageSize(int); + int pageSize() const; + void setCurrentPage(int); + int currentPage() const; + int totalPages() const; + + //展示列控制 + void setVisibleColumns(const QStringList& columns); + +protected: + QString selectStatement() const override; //调用select()时会使用该函数重写后返回的语句 + +private: + struct EditRecord //编辑记录 + { + QSqlRecord original; + QSqlRecord modified; + bool isNew = false; + bool isDeleted = false; + }; + + int m_pageSize; + int m_currentPage; + int m_totalRecords; + QStringList m_visibleColumns; + QHash m_editCache; //key:当前页中的row +}; + +#endif //TABLEEDITMODEL_H diff --git a/resource/PowerModeler.qrc b/resource/PowerModeler.qrc index d3810a3..1d1c224 100644 --- a/resource/PowerModeler.qrc +++ b/resource/PowerModeler.qrc @@ -1,5 +1,8 @@ + images/btn_close_pressed.png + images/btn_close_default.png + images/btn_close_hover.png images/icon_first.png images/icon_last.png images/icon_next.png diff --git a/resource/images/btn_close_default.png b/resource/images/btn_close_default.png new file mode 100644 index 0000000..76de305 Binary files /dev/null and b/resource/images/btn_close_default.png differ diff --git a/resource/images/btn_close_hover.png b/resource/images/btn_close_hover.png new file mode 100644 index 0000000..469bd78 Binary files /dev/null and b/resource/images/btn_close_hover.png differ diff --git a/resource/images/btn_close_pressed.png b/resource/images/btn_close_pressed.png new file mode 100644 index 0000000..9416655 Binary files /dev/null and b/resource/images/btn_close_pressed.png differ diff --git a/source/attributeTableModel.cpp b/source/attributeTableModel.cpp new file mode 100644 index 0000000..edee2d1 --- /dev/null +++ b/source/attributeTableModel.cpp @@ -0,0 +1,172 @@ +#include "attributeTableModel.h" +#include "logger.h" +#include "sqlQueryExecutor.h" + +AttributeTableModel::AttributeTableModel(QObject* parent, const QString& connection, const QString& modelID, const QString& groupID, const QString& tableName) + : QAbstractTableModel(parent) + , m_connection(connection) + , m_modelID(modelID) + , m_groupID(groupID) + , m_tableName(tableName) +{ + m_pageSize = 100; + m_currentPage = 1; + m_totalCount = 0; + + m_visibleColumns << "attribute" << "attribute_name" << "data_type_id" << "length_precision" << "default_value"; +} + +AttributeTableModel::~AttributeTableModel() +{} + +QVariant AttributeTableModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + int row = index.row(); + int col = index.column(); + int globalRow = (m_currentPage - 1) * m_pageSize + row; + + if(index.column() == 0) //第一列显示行号 + { + switch (role) + { + case Qt::DisplayRole: + { + QString prefix; + if(m_modifiedRows.contains(globalRow)) + { + switch(m_modifiedRows[globalRow].state) + { + case Modified: + prefix = "*"; + break; + case New: + prefix = "+"; + break; + case Deleted: + prefix = "-"; + break; + default: + break; + } + } + return prefix + QString::number(globalRow + 1); + } + case Qt::DecorationRole: + return QVariant(); + case Qt::TextAlignmentRole: + return Qt::AlignCenter; //行号居中展示 + default: + return QVariant(); + } + } + else + { + int dataCol = col - 1; + const RowData& rowData = m_currentPageData[row]; + if (role == Qt::DisplayRole || role == Qt::EditRole) + return rowData.record.value(dataCol); + else if (role == Qt::UserRole + 100) //以100来标识数据是否被编辑,在相关代理Delegate类实现中同步进行处理(文字加粗等效果) + return (rowData.state != Clean); + } + + return QVariant(); +} + +bool AttributeTableModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (role != Qt::EditRole || index.column() == 0) + return false; + + int row = index.row(); + int globalRow = (m_currentPage - 1) * m_pageSize + row; + int dataCol = index.column() - 1; //第一列显示了行号 + //记录修改 + RowData modifiedRow = m_currentPageData[row]; + modifiedRow.record.setValue(dataCol, value); + modifiedRow.state = (modifiedRow.state == New) ? New : Modified; + + m_modifiedRows[globalRow] = modifiedRow; + m_currentPageData[row] = modifiedRow; + + emit dataChanged(index, index, {role, Qt::UserRole + 100}); + return true; +} + +QVariant AttributeTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + { + if(section == 0) + return role == Qt::DisplayRole ? "No." : QVariant(); + else + { + return m_visibleColumns.value(section); + } + } + return QAbstractTableModel::headerData(section, orientation, role); +} + +int AttributeTableModel::rowCount(const QModelIndex& parent) const +{ + return m_currentPageData.count(); +} + +int AttributeTableModel::columnCount(const QModelIndex &) const +{ + return m_visibleColumns.isEmpty() ? 0 : m_visibleColumns.count() + 1; +} + +Qt::ItemFlags AttributeTableModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractTableModel::flags(index); + if (index.column() != 0) //行号列不能编辑 + flags = flags | Qt::ItemIsEditable; + return flags; +} + +void AttributeTableModel::loadPageData() +{ + if (m_tableName.isEmpty()) + { + LOG_ERROR("DB", QString("Attribute table name is empty, load data failed")); + return; + } + + beginResetModel(); + + QString strSQL = QString("SELECT %1 FROM %2 LIMIT %3 OFFSET %4") + .arg(m_visibleColumns.join(", ")) + .arg(m_tableName) + .arg(m_pageSize) + .arg((m_currentPage - 1) * m_pageSize); + try + { + QSqlQuery query = SqlQueryExecutor::instance().executeSQL(m_connection, strSQL); + while(query.next()) + { + RowData data; + data.record = query.record(); + m_currentPageData.append(data); + } + } + catch (const DatabaseException& e) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性信息失败。modelID:%1, groupID:%2").arg(m_modelID, m_groupID)); + } + + endResetModel(); +} + +void AttributeTableModel::updateTotalCount() +{ + if (m_tableName.isEmpty()) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"属性表名称为空,获取属性数量失败")); + return; + } + + m_totalCount = SqlQueryExecutor::instance().getAttributeCount(m_connection, m_tableName); +} diff --git a/source/attributeView.cpp b/source/attributeView.cpp new file mode 100644 index 0000000..2c80d25 --- /dev/null +++ b/source/attributeView.cpp @@ -0,0 +1,25 @@ +#include "attributeView.h" +#include "attributeTableModel.h" +#include +#include + +AttributeView::AttributeView(QWidget* parent, const QString& connection, const QString& modelID, const QString& groupID, const QString& tableName) + : QWidget(parent) + , m_connection(connection) + , m_modelID(modelID) + , m_groupID(groupID) + , m_attributeTable(tableName) +{ + m_tableView = new QTableView(this); + m_attributeTableModel = new AttributeTableModel(this, m_connection, m_modelID, m_groupID, m_attributeTable); + m_tableView->setModel(m_attributeTableModel); + + m_vLayout = new QVBoxLayout(this); + m_vLayout->setSpacing(0); + m_vLayout->setContentsMargins(0, 0, 0, 0); + m_vLayout->addWidget(m_tableView); + this->setLayout(m_vLayout); +} + +AttributeView::~AttributeView() +{} diff --git a/source/customTab.cpp b/source/customTab.cpp new file mode 100644 index 0000000..adcb1da --- /dev/null +++ b/source/customTab.cpp @@ -0,0 +1,62 @@ +#include "customTab.h" +#include "qlabel.h" +#include +#include +#include + +CustomTab::CustomTab(QWidget* parent) + :QWidget(parent) +{ + m_pTitle = new QLabel(this); + + m_IconSize = QSize(16,16); + m_pIconLabel = new QLabel(this); + m_pIconLabel->setMinimumSize(m_IconSize); + m_pIconLabel->setMaximumSize(m_IconSize); + + m_pCloseBtn = new QPushButton(this); + connect(m_pCloseBtn, &QPushButton::clicked, this, &CustomTab::onCloseButtonClicked); + m_pCloseBtn->setMinimumSize(m_IconSize); + m_pCloseBtn->setMaximumSize(m_IconSize); + m_pCloseBtn->setStyleSheet("QPushButton\n" + "{\n" + " border-image: url(:/img/images/btn_close_default.png);\n" + "}\n" + "QPushButton:hover\n" + "{\n" + " border-image: url(:/img/images/btn_close_hover.png);\n" + "}\n" + "QPushButton:pressed\n" + "{\n" + " border-image: url(:/img/images/btn_close_pressed.png);\n" + "}"); + + m_pLayout = new QBoxLayout(QBoxLayout::LeftToRight); + m_pLayout->setContentsMargins(9, 0, 0, 9); + m_pLayout->setSpacing(1); + m_pLayout->addWidget(m_pIconLabel); + m_pLayout->addWidget(m_pTitle); + m_pLayout->addWidget(m_pCloseBtn); + setLayout(m_pLayout); + + m_pCloseBtn->hide(); +} + +CustomTab::~CustomTab() +{ +} + +void CustomTab::enterEvent(QEnterEvent* event) +{ + m_pCloseBtn->show(); +} + +void CustomTab::leaveEvent(QEvent* event) +{ + m_pCloseBtn->hide(); +} + +void CustomTab::onCloseButtonClicked() +{ + emit closeTab(this); +} diff --git a/source/dbBrowser.cpp b/source/dbBrowser.cpp index 47d8b37..7325bee 100644 --- a/source/dbBrowser.cpp +++ b/source/dbBrowser.cpp @@ -1,5 +1,7 @@ #include "dbBrowser.h" #include "ui_dbBrowser.h" +#include "attributeView.h" +#include DatabaseBrowser::DatabaseBrowser(QWidget *parent) : QWidget(parent) @@ -12,3 +14,32 @@ DatabaseBrowser::~DatabaseBrowser() { delete ui; } + +void DatabaseBrowser::addTab_attribute(const QString& connection, ModelAttributeGroup& attributeGroup) +{ + AttributeView* view = new AttributeView(ui->tabWidget, connection, QString::number(attributeGroup.modelID), QString::number(attributeGroup.groupID)); + int index = ui->tabWidget->addTab(view, QIcon(":/img/images/icon_hierarchy.png"), attributeGroup.strGroupName); + //添加自定义按钮 + QPushButton* closeBtn = new QPushButton(""); + closeBtn->setFixedSize(12, 12); + closeBtn->setStyleSheet("QPushButton\n" + "{\n" + " border-image: url(:/img/images/btn_close_default.png);\n" + "}\n" + "QPushButton:hover\n" + "{\n" + " border-image: url(:/img/images/btn_close_hover.png);\n" + "}\n" + "QPushButton:pressed\n" + "{\n" + " border-image: url(:/img/images/btn_close_pressed.png);\n" + "}"); + QTabBar* tabBar = ui->tabWidget->tabBar(); + tabBar->setTabButton(index, QTabBar::RightSide, closeBtn); + + ui->tabWidget->setCurrentIndex(index); +} + +void DatabaseBrowser::closeTab(QWidget* tab) +{ +} diff --git a/source/dbStructureModel.cpp b/source/dbStructureModel.cpp index b8ef3ad..ff19207 100644 --- a/source/dbStructureModel.cpp +++ b/source/dbStructureModel.cpp @@ -179,7 +179,7 @@ void DBStructureModel::removeDataModel(DBStructureNode* modelNode) } return; } - bool result = SqlQueryExecutor::instance().removeMode(connNode->name(), modelID); + bool result = SqlQueryExecutor::instance().removeModel(connNode->name(), modelID); if(!result) { if(m_pMainWindow) diff --git a/source/dbStructureView.cpp b/source/dbStructureView.cpp index 1e276b0..1361ef1 100644 --- a/source/dbStructureView.cpp +++ b/source/dbStructureView.cpp @@ -138,7 +138,7 @@ void DBStructureView::onActionTrigger_removeModel() void DBStructureView::itemDoubleClick(const QModelIndex& index) { DBStructureNode* node = static_cast(index.internalPointer()); - if(node->type() == ConnectionNode ) + if(node->type() == ConnectionNode) { if(!m_curConnection.isEmpty()) //先断掉当前链接 { @@ -152,6 +152,19 @@ void DBStructureView::itemDoubleClick(const QModelIndex& index) m_curConnection = node->name(); } } + else if(node->type() == GroupNode) + { + DBStructureNode* parent = node->parentNode(); + if(parent && parent->type() == TableNode) + { + int modelID = parent->data(Qt::UserRole + NodeDataRole::ID).toInt(); + int groupID = node->data(Qt::UserRole + NodeDataRole::ID).toInt(); + QString modelName = parent->name(); + QString groupName = node->name(); + ModelAttributeGroup attributeGroup(modelID, groupID, modelName, groupName); + emit openAttributeInfo(m_curConnection, attributeGroup); + } + } } void DBStructureView::showContextMenu(const QPoint& pos) diff --git a/source/logger.cpp b/source/logger.cpp index a321f40..6ad8397 100644 --- a/source/logger.cpp +++ b/source/logger.cpp @@ -2,6 +2,7 @@ #include "settings.h" #include #include +#include Logger& Logger::instance() { diff --git a/source/mainwindow.cpp b/source/mainwindow.cpp index 4963305..888eb6a 100644 --- a/source/mainwindow.cpp +++ b/source/mainwindow.cpp @@ -70,6 +70,7 @@ void MainWindow::initialize() m_pDBStrutureView = new DBStructureView(m_dbManager, this); m_pDBStrutureView->setMainWindow(this); connect(m_pDBStrutureView, &DBStructureView::actionTrigger_addModel, this, &MainWindow::onActionTrigger_addModel); + connect(m_pDBStrutureView, &DBStructureView::openAttributeInfo, this, &MainWindow::onSIG_openAttributeInfo); ui->layoutDBStructure->addWidget(m_pDBStrutureView); m_pDBStrutureModel = new DBStructureModel(this); m_pDBStrutureModel->setMainWindow(this); @@ -215,3 +216,9 @@ void MainWindow::onSIG_addModel(Model& model) QString connection = m_pDBStrutureView->curConnection(); m_pDBStrutureModel->addDataModel(connection, model); } + +void MainWindow::onSIG_openAttributeInfo(const QString& connection, ModelAttributeGroup& attributeGroup) +{ + if(m_dbBrowser) + m_dbBrowser->addTab_attribute(connection, attributeGroup); +} diff --git a/source/sqlQueryExecutor.cpp b/source/sqlQueryExecutor.cpp index 12a54cc..9a1325b 100644 --- a/source/sqlQueryExecutor.cpp +++ b/source/sqlQueryExecutor.cpp @@ -308,7 +308,7 @@ bool SqlQueryExecutor::modelTypeExistsInDB(const QString& connectionName, const return exists; } -bool SqlQueryExecutor::removeMode(const QString& connectionName, int modelID) +bool SqlQueryExecutor::removeModel(const QString& connectionName, int modelID) { QString strSQL = "DELETE FROM basic.model_type WHERE id = :id"/* + QString::number(modelID)*/; QVariantHash params; @@ -368,3 +368,21 @@ const QString SqlQueryExecutor::getArributeGropuName(const QString& strConnectio return name; } + +int SqlQueryExecutor::getAttributeCount(const QString& strConnectionName, const QString& tableName) +{ + int count = 0; + QString strSQL = QString("SELECT COUNT(*) FROM %1").arg(tableName); + try + { + QSqlQuery query = executeSQL(strConnectionName, strSQL); + if(query.next()) + count = query.value(0).toInt(); + } + catch (const DatabaseException& e) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败")); + } + + return count; +} diff --git a/source/tableEditModel.cpp b/source/tableEditModel.cpp new file mode 100644 index 0000000..fae7fe4 --- /dev/null +++ b/source/tableEditModel.cpp @@ -0,0 +1,101 @@ +#include "tableEditModel.h" + +TableEditModel::TableEditModel(QObject *parent, const QSqlDatabase &db, const QStringList &visibleColumns) + : QSqlTableModel(parent, db), m_visibleColumns(visibleColumns) +{ + setEditStrategy(QSqlTableModel::OnManualSubmit); //对编辑数据手动进行提交 + + m_pageSize = 100; + m_currentPage = 1; + m_totalRecords = 0; +} + +TableEditModel::~TableEditModel() +{} + +//重写生成查询的方法 +QString TableEditModel::selectStatement() const +{ + QString originalQuery = QSqlTableModel::selectStatement(); + QString newQuery; + if(m_visibleColumns.isEmpty()) + newQuery = originalQuery; + else + { + int fromInex = originalQuery.indexOf(" FROM "); + QString selectPart = "SELECT " + m_visibleColumns.join(", "); + newQuery = selectPart + originalQuery + selectPart.mid(fromInex); + } + newQuery = newQuery + QString(" LIMIT %1 OFFSET %2").arg(m_pageSize, (m_currentPage - 1) * m_pageSize); + + return newQuery; +} + +QVariant TableEditModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + if(index.column() == 0) //第一列显示行号 + { + int golbalRow = (m_currentPage - 1) * m_pageSize + index.row(); + switch (role) + { + case Qt::DisplayRole: + { + QString displayRow = QString::number(golbalRow + 1); + if(m_editCache.keys().contains(index.row())) + displayRow = "*" + displayRow; + return displayRow; + } + case Qt::DecorationRole: + return QVariant(); + case Qt::TextAlignmentRole: //行号居中展示 + return Qt::AlignCenter; + default: + return QVariant(); + } + } + else if(role == Qt::UserRole + 100) //先以100来标识数据是否被编辑,在相关代理Delegate类实现中同步进行处理(文字加粗等效果) + return isDirty(index); + else + return QSqlTableModel::data(createIndex(index.row(), index.column() - 1), role); //因为第一列显示行号,所以其它数据列要错位展示 +} + +bool TableEditModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.column() == 0 || role != Qt::EditRole) //忽略行号列 + return false; + + // if(index.column() == 0) //忽略行号列 + // return QSqlTableModel::setData(createIndex(index.row(), index.column()-1), value, role); + + int row = index.row(); + if (row < 0 || row >= rowCount()) + return false; + + //记录修改到缓存 + if(!m_editCache.contains(row)) + { + EditRecord record; + record.original = QSqlTableModel::record(row); + m_editCache[row] = record; + } + m_editCache[row].modified.setValue(index.column() - 1, value); + + emit dataChanged(index, index, {role}); + return true; +} + +int TableEditModel::columnCount(const QModelIndex &parent) const +{ + return QSqlTableModel::columnCount(parent) + 1; // 原始列数 + 行号列 +} + +Qt::ItemFlags TableEditModel::flags(const QModelIndex &index) const +{ + if(index.column() == 0) //行号列不可编辑 + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + else return QSqlTableModel::flags(this->index(index.row(), index.column() - 1)); +} + diff --git a/source/tableWidgetHoverDelegate.cpp b/source/tableWidgetHoverDelegate.cpp index f572e2f..0dfab31 100644 --- a/source/tableWidgetHoverDelegate.cpp +++ b/source/tableWidgetHoverDelegate.cpp @@ -11,7 +11,7 @@ QTableWidgetHoverDelegate::~QTableWidgetHoverDelegate() void QTableWidgetHoverDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - if(option.state.testFlag(QStyle::State_MouseOver)) + if(option.state.testFlag(QStyle::State_MouseOver) && m_tableWiget) { QTableWidgetItem* hoveredItem = m_tableWiget->item(index.row(), index.column()); if(hoveredItem) diff --git a/ui/dbBrowser.ui b/ui/dbBrowser.ui index d7808bf..e592fb8 100644 --- a/ui/dbBrowser.ui +++ b/ui/dbBrowser.ui @@ -32,37 +32,11 @@ - 0 + -1 + + + false - - - - :/img/images/icon_hierarchy2.png:/img/images/icon_hierarchy2.png - - - NULL - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - @@ -241,7 +215,7 @@ QPushButton:pressed - 提交更改 + 提交修改 @@ -282,7 +256,7 @@ QPushButton:pressed - 取销更改 + 取销修改