diff --git a/CMakeLists.txt b/CMakeLists.txt index c7be7c8..b06ceba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ set(H_HEADER_FILES include/dbStructureView.h include/connectionDialog.h include/messageDialog.h + include/messageBox.h include/settings.h include/tableWidgetHoverDelegate.h include/customMenu.h @@ -37,6 +38,7 @@ set(H_HEADER_FILES include/attributeTableModel.h include/attributeTableDelegate.h include/attributeView.h + include/attributeSelector.h ) set(CPP_SOURCE_FILES @@ -51,6 +53,7 @@ set(CPP_SOURCE_FILES source/dbStructureView.cpp source/connectionDialog.cpp source/messageDialog.cpp + source/messageBox.cpp source/settings.cpp source/tableWidgetHoverDelegate.cpp source/customMenu.cpp @@ -60,6 +63,7 @@ set(CPP_SOURCE_FILES source/attributeTableModel.cpp source/attributeTableDelegate.cpp source/attributeView.cpp + source/attributeSelector.cpp ) set(UI_FILES @@ -69,6 +73,7 @@ set(UI_FILES ui/messageDialog.ui ui/modelInfoEditDialog.ui ui/textEditWidget.ui + ui/attributeSelector.ui ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user index fd54da9..738bd79 100644 --- a/CMakeLists.txt.user +++ b/CMakeLists.txt.user @@ -1,6 +1,6 @@ - + EnvironmentId @@ -727,7 +727,6 @@ true true true - E:/Code/CL-Softwares/Git/PowerModeler/build/Qt_MinGW_64_bit-Debug 1 diff --git a/include/attributeSelector.h b/include/attributeSelector.h new file mode 100644 index 0000000..88ceeea --- /dev/null +++ b/include/attributeSelector.h @@ -0,0 +1,36 @@ +#ifndef ATTRIBUTESELECTOR_H +#define ATTRIBUTESELECTOR_H + +#include "global.h" +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class AttributeSelector; +} +QT_END_NAMESPACE + +class MainWindow; +class AttributeView; +class AttributeSelector : public QWidget +{ + Q_OBJECT + +public: + AttributeSelector(const QString& connection = "", QWidget *parent = nullptr); + ~AttributeSelector(); + + void setMainWindow(MainWindow*); + +private slots: + void onBtnClicked_refreshData(); + void onSyncDataStatus(bool, const PaginationInfo&); + +private: + Ui::AttributeSelector *ui; + MainWindow* m_pMainWindow; + AttributeView* m_attributeView; + QString m_connection; +}; + +#endif //ATTRIBUTESELECTOR_H diff --git a/include/attributeTableDelegate.h b/include/attributeTableDelegate.h index 6d23ca6..097d693 100644 --- a/include/attributeTableDelegate.h +++ b/include/attributeTableDelegate.h @@ -1,6 +1,7 @@ #ifndef ATTRIBUTETABLEDELEGATE_H #define ATTRIBUTETABLEDELEGATE_H +#include "messageDialog.h" #include #include @@ -21,6 +22,7 @@ public: void setPrompt(const QString&); void setRegularExpression(const QString&); void setErrorInfo(const QString&); + void setFocusToTextEdit(); signals: void confirm(); @@ -58,6 +60,9 @@ public: void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; +signals: + void showMessage(MessageDialogType,const QString&,const QString&); + private: bool isEnumType(const QModelIndex&) const; diff --git a/include/attributeTableModel.h b/include/attributeTableModel.h index 0b180d8..74be095 100644 --- a/include/attributeTableModel.h +++ b/include/attributeTableModel.h @@ -24,14 +24,6 @@ class AttributeTableModel : public QAbstractTableModel Q_OBJECT public: - enum EditState - { - Clean = 0, - Modified, - New, - Deleted - }; - struct DataType //数据类型 { int id; @@ -53,6 +45,10 @@ public: int columnCount(const QModelIndex& parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; + //ModelAttributeGroup getModelAttributeGroup() {return m_modelAttributeGroup;} + bool attributeTypeExistsInCurrentGroup(int, const QString&); //除数据库外,还有从内存存储的数据(当前页m_currentPageData)中进行查找判断,因为可能有编辑完但未提交至数据空的信息 + void updateRowThroughExisitingAttribute(int, int); + //分页控制 void setPageSize(int); int pageSize() const; @@ -96,14 +92,14 @@ private: //QSqlRecord record; QVector values; QHash cellModified; //记录单元格是否被修改 - EditState state = Clean; + EditState state = EditState(Clean); }; void iniDisplayField(); void getDataTypesFromDB(); void loadPageData(); // 加载当前页数据 void updateTotalCount(); // 更新总记录数 - QList filterRowsByEditState(EditState); + QList filterRowsByEditState(EditStateFlag); int getDataTypeID(const QString&); QString m_connection; diff --git a/include/attributeView.h b/include/attributeView.h index 0e826f7..a0b48d0 100644 --- a/include/attributeView.h +++ b/include/attributeView.h @@ -5,6 +5,7 @@ #include #include "global.h" #include "attributeTableModel.h" +#include "attributeTableDelegate.h" class QVBoxLayout; class MultiLineHeaderView; @@ -21,6 +22,7 @@ public: QTableView* view() const { return m_tableView; } AttributeTableModel* model() const { return m_attributeTableModel; } + AttributeTableDelegate* delegate() const { return m_attributeTableDelegate; } void active(); @@ -31,6 +33,7 @@ private: QTableView* m_tableView; AttributeTableModel* m_attributeTableModel; + AttributeTableDelegate* m_attributeTableDelegate; QVBoxLayout* m_vLayout; MultiLineHeaderView* m_multiLinHeader; diff --git a/include/global.h b/include/global.h index 3303e14..7483278 100644 --- a/include/global.h +++ b/include/global.h @@ -11,6 +11,18 @@ enum DialogState DS_Edit }; +enum EditStateFlag +{ + Clean = 0, // 二进制: 0b0000 + Modified = 1 << 0, // 二进制: 0b0001 + New = 1 << 1, // 二进制: 0b0010 + Deleted = 1 << 2 // 二进制: 0b0100 +}; +//创建 QFlags 包装类型 +Q_DECLARE_FLAGS(EditState, EditStateFlag) +//生成运算符重载 +Q_DECLARE_OPERATORS_FOR_FLAGS(EditState) + struct DatabaseConfig { QString strID; //存储在配置文件时用作唯一标识 diff --git a/include/mainwindow.h b/include/mainwindow.h index 2307566..bc45bc2 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -33,11 +33,15 @@ public: protected: bool eventFilter(QObject*, QEvent*) override; + void resizeEvent(QResizeEvent*) override; private: void initialize(); + void showMaskLayer(); + void hideMaskLayer(); Ui::MainWindow *ui; + QWidget* m_maskLayer; DatabaseManager* m_dbManager; DatabaseBrowser* m_dbBrowser; QSqlError m_lastSqlError; diff --git a/include/messageBox.h b/include/messageBox.h new file mode 100644 index 0000000..b309ab4 --- /dev/null +++ b/include/messageBox.h @@ -0,0 +1,49 @@ +#ifndef MESSAGEBOX_H +#define MESSAGEBOX_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { +class messageDialog; +} +QT_END_NAMESPACE + +enum MessageBoxType +{ + t_information = 0, + t_question, + t_warning +}; + +// enum MessageBoxBtn +// { +// btn_Null = 0, +// btn_Yes, +// btn_No +// }; +//extern MessageBoxBtn g_msgBoxBtn; + +class MessageBox : public QDialog +{ + Q_OBJECT + +public: + MessageBox(QWidget *parent = nullptr); + ~MessageBox(); + + static int show(MessageBoxType,const QString&,const QString&); + +public slots: + void onBtnClicked_confirm(); + void onBtnClicked_yes(); + void onBtnClicked_no(); + +private: + void setType(MessageBoxType); + void setMessage(MessageBoxType,const QString&,const QString&); + + Ui::messageDialog* ui; +}; + +#endif diff --git a/include/sqlQueryExecutor.h b/include/sqlQueryExecutor.h index fb83fe8..13c45cd 100644 --- a/include/sqlQueryExecutor.h +++ b/include/sqlQueryExecutor.h @@ -35,8 +35,10 @@ public: bool removeModel(const QString&, int); //属性相关 int getAttributeCount(const QString&, int, int); + int getAllAttributeCount(const QString&); bool getAttributeInfo(const QString&, const QString&, Attribute&); - bool attributeTypeExistsInDB(const QString&, const QString&); + int attributeTypeExistsInDB(const QString&, const QString&); + bool attributeTypeUseByModelGroup(const QString&, int, int, int); bool batchInsertAttributes(const QString&, int, int, QList); bool batchDeleteAttributes(const QString&, int, int, QList); bool batchUpdateAttributes(const QString&, int, int, QList); diff --git a/resource/PowerModeler.qrc b/resource/PowerModeler.qrc index ebdfe39..5876a27 100644 --- a/resource/PowerModeler.qrc +++ b/resource/PowerModeler.qrc @@ -1,5 +1,7 @@ + images/icon_search_white.png + images/icon_search.png images/icon_refresh3_disable.png images/icon_close_disable.png images/btn_close_pressed.png diff --git a/resource/images/icon_search.png b/resource/images/icon_search.png new file mode 100644 index 0000000..a2d05f5 Binary files /dev/null and b/resource/images/icon_search.png differ diff --git a/resource/images/icon_search_white.png b/resource/images/icon_search_white.png new file mode 100644 index 0000000..8212bbb Binary files /dev/null and b/resource/images/icon_search_white.png differ diff --git a/source/attributeSelector.cpp b/source/attributeSelector.cpp new file mode 100644 index 0000000..4afdb82 --- /dev/null +++ b/source/attributeSelector.cpp @@ -0,0 +1,49 @@ +#include "attributeSelector.h" +#include "ui_attributeSelector.h" +#include "mainwindow.h" +#include "attributeView.h" + +AttributeSelector::AttributeSelector(const QString& connection, QWidget *parent) + : QWidget(parent) + , ui(new Ui::AttributeSelector) + , m_connection(connection) +{ + ui->setupUi(this); + //隐藏一些功能按钮 + ui->btnAdd->setVisible(false); + ui->btnRemove->setVisible(false); + ui->btnSave->setVisible(false); + ui->btnCancle->setVisible(false); + + ModelAttributeGroup attributeGroup(-1, -1, "" ,""); + m_attributeView = new AttributeView(attributeGroup, ui->attributeViewContainer, connection); + ui->layoutTableView->addWidget(m_attributeView); + + connect(ui->btnRefresh, &QPushButton::clicked, this, &AttributeSelector::onBtnClicked_refreshData); +} + +AttributeSelector::~AttributeSelector() +{ + delete ui; +} + +void AttributeSelector::setMainWindow(MainWindow* window) +{ + m_pMainWindow = window; +} + +void AttributeSelector::onBtnClicked_refreshData() +{ + +} + +void AttributeSelector::onSyncDataStatus(bool hasModifiedData, const PaginationInfo& paginationInfo) +{ + ui->btnSave->setEnabled(!hasModifiedData); + ui->btnCancle->setEnabled(!hasModifiedData); + + QString recordInfo = QString::fromWCharArray(L"共 %1 条记录").arg(paginationInfo.totalEntries); + ui->recordInfo->setText(recordInfo); + ui->lineEdit->setText(QString::number(paginationInfo.currentPage)); + ui->lineEdit->setEnabled(true); +} diff --git a/source/attributeTableDelegate.cpp b/source/attributeTableDelegate.cpp index a1846fa..e50409a 100644 --- a/source/attributeTableDelegate.cpp +++ b/source/attributeTableDelegate.cpp @@ -3,10 +3,12 @@ #include "attributeNamespace.h" #include "sqlQueryExecutor.h" #include "ui_textEditWidget.h" +//#include "messageBox.h" #include #include #include #include +#include #include TextEditWidget::TextEditWidget(QWidget* parent) @@ -76,6 +78,12 @@ void TextEditWidget::setErrorInfo(const QString& errorInfo) ui->label->setText(errorInfo); } +void TextEditWidget::setFocusToTextEdit() +{ + ui->plainTextEdit->setFocus(); + ui->plainTextEdit->moveCursor(QTextCursor::End); +} + void TextEditWidget::onTextChanged() { ui->label->setText(m_promptString); @@ -161,23 +169,30 @@ QWidget* AttributeTableDelegate::createEditor(QWidget *parent, const QStyleOptio if(dataCol == 0) //属性类型 { TextEditWidget* textEditor = new TextEditWidget(parent); - textEditor->setPrompt(QString::fromWCharArray(L"类型为英文")); + textEditor->setPrompt(QString::fromWCharArray(L"类型必须为英文")); textEditor->setRegularExpression("[A-Za-z0-9]"); connect(textEditor, &TextEditWidget::confirm, this, [=]{ - QString strText = textEditor->editText(); - bool exists = SqlQueryExecutor::instance().attributeTypeExistsInDB(m_connection, strText); - if(exists) + /*QString strText = textEditor->editText(); + int id = SqlQueryExecutor::instance().attributeTypeExistsInDB(m_connection, strText); + if(id != -1) textEditor->setErrorInfo(QString::fromWCharArray(L"该类型已存在")); else { emit const_cast(this)->commitData(textEditor); emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); - } + }*/ + //判断放在setModelData函数中,因为那里会先进行是否做内容改变的判断 + emit const_cast(this)->commitData(textEditor); + emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); }); connect(textEditor, &TextEditWidget::cancle, this, [=]{ //createEditor为const成员函数,而closeEditor是QAbstractItemDelegate的非const信号,在const成员函数中不能直接调用,需要转换为非const指针 emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); }); + //延迟获取焦点,防止可能因渲染未完成失效 + QTimer::singleShot(10, this, [textEditor]() { + textEditor->setFocusToTextEdit(); + }); return textEditor; } else if(dataCol == 1 || dataCol == 4) //1-数据名称、4-默认值 @@ -190,6 +205,10 @@ QWidget* AttributeTableDelegate::createEditor(QWidget *parent, const QStyleOptio connect(textEditor, &TextEditWidget::cancle, this, [=]{ emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); }); + //延迟获取焦点,防止可能因渲染未完成失效 + QTimer::singleShot(10, this, [textEditor]() { + textEditor->setFocusToTextEdit(); + }); return textEditor; } else if(dataCol == 2) //数据类型 @@ -227,7 +246,10 @@ QWidget* AttributeTableDelegate::createEditor(QWidget *parent, const QStyleOptio void AttributeTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { if(TextEditWidget* textEditor = qobject_cast(editor)) + { textEditor->setEditText(index.data(Qt::DisplayRole).toString()); + //textEditor->setFocus(); + } else QStyledItemDelegate::setEditorData(editor, index); } @@ -254,6 +276,48 @@ void AttributeTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *m if (newValue == oldValue) return; + int dataCol = index.column() - 1; + if(dataCol == 0) //属性类型 做预先判断:1.是否以已在同组中 2.是否已被创建 + { + auto attributeTableModel = qobject_cast(model); + auto textEditor = qobject_cast(editor); + if(attributeTableModel && textEditor) + { + QString strText = textEditor->editText(); + int id = SqlQueryExecutor::instance().attributeTypeExistsInDB(m_connection, strText); + //1.是否以已在同组中(要同时从内存和数据库中都进行查找,避免遗漏已创建但未提交的数据) + bool existsInCurrentGropu = attributeTableModel->attributeTypeExistsInCurrentGroup(id, strText); + if(existsInCurrentGropu) + { + emit const_cast(this)->showMessage(type_information, QString::fromWCharArray(L"提示"), + QString::fromWCharArray(L"该类型属性已在当前组中存在")); + return; + } + //2.是否已被创建 + if(id != -1) + { + /*int result = MessageBox::show(t_question, QString::fromWCharArray(L"提示"), QString::fromWCharArray(L"该类型属性已创建,是否直接载入当前数据")); + if(result == QDialog::Accepted) + { + auto attributeTableModel = qobject_cast(model); + attributeTableModel->updateRowThroughExisitingAttribute(index.row(), id); + return; + } + else + return;*/ + emit const_cast(this)->showMessage(type_question, QString::fromWCharArray(L"提示"), + QString::fromWCharArray(L"该类型属性已创建,是否直接载入当前数据")); + if(g_msgDlgBtn == btn_Yes) + { + attributeTableModel->updateRowThroughExisitingAttribute(index.row(), id); + return; + } + else + return; + } + } + } + model->setData(index, newValue, Qt::EditRole); } diff --git a/source/attributeTableModel.cpp b/source/attributeTableModel.cpp index 1b92d4b..87acf65 100644 --- a/source/attributeTableModel.cpp +++ b/source/attributeTableModel.cpp @@ -27,7 +27,7 @@ QModelIndex AttributeTableModel::index(int row, int column, const QModelIndex& p return QModelIndex(); int dataCol = column - 1; - if(dataCol >= m_displayField.count()) + if(dataCol > m_displayField.count()) return QModelIndex(); return createIndex(row, column); @@ -59,6 +59,9 @@ QVariant AttributeTableModel::data(const QModelIndex& index, int role) const case New: mark = "+"; break; + case New | Modified: + mark = "+"; + break; case Deleted: mark = "-"; break; @@ -133,7 +136,11 @@ bool AttributeTableModel::setData(const QModelIndex &index, const QVariant &valu else modifiedRow.values[dataCol] = value; modifiedRow.cellModified[dataCol] = true; //标记单元格 - modifiedRow.state = (modifiedRow.state == New) ? New : Modified; + const int attributeID = modifiedRow.values.last().toInt(); + if(attributeID == -1) //纯新建 + modifiedRow.state = (modifiedRow.state == New) ? New : Modified; + else + modifiedRow.state = (modifiedRow.state == New) ? modifiedRow.state |= Modified : Modified; //新建时从已有数据进行的加载,然后再次编辑就会变为叠加态 m_modifiedRows[globalRow] = modifiedRow; m_currentPageData[row] = modifiedRow; @@ -173,13 +180,67 @@ int AttributeTableModel::columnCount(const QModelIndex &) const Qt::ItemFlags AttributeTableModel::flags(const QModelIndex &index) const { - QModelIndex numberIndex = createIndex(index.row(), 0); - QString text = numberIndex.data(Qt::DisplayRole).toString(); - Qt::ItemFlags flags = QAbstractTableModel::flags(index); - if (index.column() != 0 && !text.contains("-")) //行号列和处于删除状态的item不能编辑 - flags = flags | Qt::ItemIsEditable; - return flags; + if(m_modelAttributeGroup.modelID < 0) //表示当前加载数据对象是所有属性,前端UI是属性选择器,选择器为非可编辑状态 + return flags; + else + { + QModelIndex numberIndex = createIndex(index.row(), 0); + QString text = numberIndex.data(Qt::DisplayRole).toString(); + + if (index.column() != 0 && !text.contains("-")) //行号列和处于删除状态的item不能编辑 + flags = flags | Qt::ItemIsEditable; + return flags; + } +} + +bool AttributeTableModel::attributeTypeExistsInCurrentGroup(int id, const QString& type) +{ + //先查找内存数据 + for(RowData rowData : m_currentPageData) + { + if(rowData.values[0] == type) + return true; + } + + //再从数据库中查找,因为内存只存储当前页的数据 + if(id != -1) //说明是之前创建过的属性(数据库中已存在) + return SqlQueryExecutor::instance().attributeTypeUseByModelGroup(m_connection, id, m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID); + + return false; +} + +void AttributeTableModel::updateRowThroughExisitingAttribute(int row, int attributeID) +{ + //qDebug() << "row:" << row << " attributeID:" << attributeID; + QStringList columns; + for(int i = 0; i < m_displayField.count(); i++) + columns << m_displayField.at(i).originalName; + Attribute attribute; + attribute.id = attributeID; + if(SqlQueryExecutor::instance().getAttributeInfo(m_connection, columns.join(", "), attribute)) + { + RowData updateRow = m_currentPageData[row]; + //updateRow.values.resize(m_displayField.count() + 1); + updateRow.values[0] = attribute.type; + updateRow.values[1] = attribute.name; + updateRow.values[2] = attribute.dataTypeID; + updateRow.values[3] = attribute.dataLength; + updateRow.values[4] = attribute.defaultValue; + updateRow.values[5] = attribute.id;//将id存入最后,不做显示,删除或者修改数据的时候会用到 + + for(int i = 0; i < m_displayField.count(); i++) + updateRow.cellModified[i] = true; //标记单元格 + updateRow.state = (updateRow.state == New) ? New : Modified; + + m_currentPageData[row] = updateRow; + int globalRow = (m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage + row; + m_modifiedRows[globalRow] = updateRow; + + QModelIndex topLeft = index(row, 1, QModelIndex()); + QModelIndex bottomRight = index(row, m_displayField.count(), QModelIndex()); + emit dataChanged(topLeft, bottomRight); + } } void AttributeTableModel::iniDisplayField() @@ -263,38 +324,64 @@ void AttributeTableModel::loadPageData() beginResetModel(); - QString strSQL = QString("SELECT attribute_id FROM basic.model_attribute WHERE model_type_id = %1 AND attribute_group_id = %2 LIMIT %3 OFFSET %4") - .arg(m_modelAttributeGroup.modelID) - .arg(m_modelAttributeGroup.groupID) - .arg(m_paginationInfo.entriesPerPage) - .arg((m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage); - try - { - QStringList columns; - for(int i = 0; i < m_displayField.count(); i++) - columns << m_displayField.at(i).originalName; + QStringList columns; + for(int i = 0; i < m_displayField.count(); i++) + columns << m_displayField.at(i).originalName; - QSqlQuery query = SqlQueryExecutor::instance().executeSQL(m_connection, strSQL); - while(query.next()) + if(m_modelAttributeGroup.modelID < 0) //表示当前加载数据对象是所有属性 + { + columns.append("id"); //将id放到最后,和按照具体模型、具体属性组读取数据方式时逻辑统一,具体见下面分支逻辑 + QString strSQL = QString("SELECT %1 FROM basic.attribute LIMIT %2 OFFSET %3") + .arg(columns.join(", ")) + .arg(m_paginationInfo.entriesPerPage) + .arg((m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage); + try { - Attribute attribute; - attribute.id = query.value(0).toInt(); - if(SqlQueryExecutor::instance().getAttributeInfo(m_connection, columns.join(", "), attribute)) + QSqlQuery query = SqlQueryExecutor::instance().executeSQL(m_connection, strSQL); + while(query.next()) { RowData data; - data.values.append(attribute.type); - data.values.append(attribute.name); - data.values.append(attribute.dataTypeID); - data.values.append(attribute.dataLength); - data.values.append(attribute.defaultValue); - data.values.append(attribute.id);//将id存入最后,不做显示,删除或者修改数据的时候会用到 + for(int i = 0; i < columns.count(); i++) + data.values.append(query.value(i)); m_currentPageData.append(data); } } + catch (const DatabaseException& e) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性信息失败(所有属性)。")); + } } - catch (const DatabaseException& e) + else //按具体模型的具体属性组读取数据 { - LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性信息失败。modelID:%1, groupID:%2").arg(m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID)); + QString strSQL = QString("SELECT attribute_id FROM basic.model_attribute WHERE model_type_id = %1 AND attribute_group_id = %2 LIMIT %3 OFFSET %4") + .arg(m_modelAttributeGroup.modelID) + .arg(m_modelAttributeGroup.groupID) + .arg(m_paginationInfo.entriesPerPage) + .arg((m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage); + try + { + QSqlQuery query = SqlQueryExecutor::instance().executeSQL(m_connection, strSQL); + while(query.next()) + { + Attribute attribute; + attribute.id = query.value(0).toInt(); + if(SqlQueryExecutor::instance().getAttributeInfo(m_connection, columns.join(", "), attribute)) + { + RowData data; + data.values.append(attribute.type); + data.values.append(attribute.name); + data.values.append(attribute.dataTypeID); + data.values.append(attribute.dataLength); + data.values.append(attribute.defaultValue); + data.values.append(attribute.id);//将id存入最后,不做显示,删除或者修改数据的时候会用到 + m_currentPageData.append(data); + } + } + } + catch (const DatabaseException& e) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性信息失败。modelID:%1, groupID:%2").arg(m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID)); + } } endResetModel(); @@ -368,15 +455,18 @@ void AttributeTableModel::updateTotalCount() return; }*/ - m_paginationInfo.totalEntries = SqlQueryExecutor::instance().getAttributeCount(m_connection, m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID); + if(m_modelAttributeGroup.modelID < 0) + m_paginationInfo.totalEntries = SqlQueryExecutor::instance().getAllAttributeCount(m_connection); + else + m_paginationInfo.totalEntries = SqlQueryExecutor::instance().getAttributeCount(m_connection, m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID); } -QList AttributeTableModel::filterRowsByEditState(EditState state) +QList AttributeTableModel::filterRowsByEditState(EditStateFlag state) { QList result; for(auto it = m_modifiedRows.begin(); it != m_modifiedRows.end(); it++) { - if(it.value().state == state) + if(it.value().state.testFlag(state)) result.append(it.value()); } return result; @@ -415,7 +505,8 @@ void AttributeTableModel::insertRecord(int row) RowData newRow; newRow.state = New; - newRow.values.resize(m_displayField.count()); + newRow.values.resize(m_displayField.count() + 1); //多出一个位置给id + newRow.values.last() = -1; //newRow.values[2] = 11; int globalRow = (m_paginationInfo.currentPage - 1) * m_paginationInfo.entriesPerPage + row; @@ -486,7 +577,10 @@ void AttributeTableModel::submitChanges() if(rowData.values.value(4).isValid()) defaultValue = rowData.values.value(4).toString(); - insertAttributes.emplace_back(-1, name, type, dataTypeID, dataLength, defaultValue); + int id = -1; + if(rowData.values.size() == m_displayField.count() +1) + id = rowData.values.value(m_displayField.count()).toInt(); + insertAttributes.emplace_back(id, name, type, dataTypeID, dataLength, defaultValue); } insertCompleted = SqlQueryExecutor::instance().batchInsertAttributes(m_connection, m_modelAttributeGroup.modelID, m_modelAttributeGroup.groupID, insertAttributes); } diff --git a/source/attributeView.cpp b/source/attributeView.cpp index f6255c6..cac5e95 100644 --- a/source/attributeView.cpp +++ b/source/attributeView.cpp @@ -14,13 +14,14 @@ AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWi m_tableView = new QTableView(this); m_tableView->setStyleSheet("QTableView::item{padding-left:5px;} QTableView::item:selected{border:1px solid rgb(70,130,180);}"); m_tableView->verticalHeader()->setVisible(false); - //m_tableView->setTabKeyNavigation(false); //关闭tab键导航 + m_tableView->setFocusPolicy(Qt::NoFocus); //避免视图抢Editor的焦点 + m_tableView->setTabKeyNavigation(false); //关闭tab键导航 m_attributeTableModel = new AttributeTableModel(m_modelAttributeGroup, this, m_connection, m_attributeTable); m_tableView->setModel(m_attributeTableModel); - AttributeTableDelegate* delegate = new AttributeTableDelegate(m_tableView, m_connection, m_tableView); - m_tableView->setItemDelegate(delegate); + m_attributeTableDelegate = new AttributeTableDelegate(m_tableView, m_connection, m_tableView); + m_tableView->setItemDelegate(m_attributeTableDelegate); //自定义表头 m_multiLinHeader = new MultiLineHeaderView(Qt::Horizontal, this); diff --git a/source/attributeView.cpp.autosave b/source/attributeView.cpp.autosave new file mode 100644 index 0000000..fa64dc9 --- /dev/null +++ b/source/attributeView.cpp.autosave @@ -0,0 +1,62 @@ +#include "attributeView.h" +#include "attributeTableDelegate.h" +#include "multiLineHeaderView.h" +#include +#include +#include + +AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWidget* parent, const QString& connection, const QString& tableName) + : QWidget(parent) + , m_connection(connection) + , m_attributeTable(tableName) + , m_modelAttributeGroup(modelAttributeGroup) +{ + m_tableView = new QTableView(this); + m_tableView->setStyleSheet("QTableView::item{padding-left:5px;} QTableView::item:selected{border:1px solid rgb(70,130,180);}"); + m_tableView->verticalHeader()->setVisible(false); + + m_tableView->setTabKeyNavigation(false); //关闭tab键导航 + + m_attributeTableModel = new AttributeTableModel(m_modelAttributeGroup, this, m_connection, m_attributeTable); + m_tableView->setModel(m_attributeTableModel); + + m_attributeTableDelegate = new AttributeTableDelegate(m_tableView, m_connection, m_tableView); + m_tableView->setItemDelegate(m_attributeTableDelegate); + + //自定义表头 + m_multiLinHeader = new MultiLineHeaderView(Qt::Horizontal, this); + QColor bg(246, 246, 246); + QColor border(228, 228, 228); + m_multiLinHeader->setBackgroundColor(bg); + m_multiLinHeader->setBorderColor(border); + //主标题加粗展示 + for(int i =0; i < m_attributeTableModel->columnCount(); i++) + { + HeaderLineStyle mainTitleStyle; + mainTitleStyle.font.setBold(true); + m_multiLinHeader->setSectionLineStyle(i, 0, mainTitleStyle); + HeaderLineStyle subTitleStyle; + //subTitleStyle.font.setPointSize(8); + m_multiLinHeader->setSectionLineStyle(i, 1, subTitleStyle); + } + m_tableView->setHorizontalHeader(m_multiLinHeader); + //除了第一列其余列恢复可以手动调整模式 + QTimer::singleShot(1000, this, [=](){ + for(int i = 1; i < m_multiLinHeader->count(); i++) + m_multiLinHeader->setSectionResizeMode(i, QHeaderView::Interactive); + }); + + 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() +{} + +void AttributeView::active() +{ + m_attributeTableModel->triggerSyncSignal(); +} diff --git a/source/dbBrowser.cpp b/source/dbBrowser.cpp index 0d95dc0..7bf4a3e 100644 --- a/source/dbBrowser.cpp +++ b/source/dbBrowser.cpp @@ -55,6 +55,7 @@ void DatabaseBrowser::addTab_attribute(const QString& connection, ModelAttribute AttributeView* view = new AttributeView(attributeGroup, ui->tabWidget, connection); connect(view->model(), &AttributeTableModel::showMessage, this, &DatabaseBrowser::onShowMessage); connect(view->model(), &AttributeTableModel::syncDataStatus, this, &DatabaseBrowser::onSyncDataStatus); + connect(view->delegate(), &AttributeTableDelegate::showMessage, this, &DatabaseBrowser::onShowMessage); index = ui->tabWidget->addTab(view, QIcon(":/img/images/icon_hierarchy.png"), tabText); //添加自定义按钮 /*QPushButton* closeBtn = new QPushButton(""); diff --git a/source/mainwindow.cpp b/source/mainwindow.cpp index 6af671a..7d1aac3 100644 --- a/source/mainwindow.cpp +++ b/source/mainwindow.cpp @@ -16,6 +16,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) + , m_maskLayer(nullptr) , m_dbManager(nullptr) , m_dbBrowser(nullptr) , m_pMessageDialog(nullptr) @@ -50,6 +51,13 @@ bool MainWindow::eventFilter(QObject* obj, QEvent* event) return QObject::eventFilter(obj, event); } +void MainWindow::resizeEvent(QResizeEvent* event) +{ + if(m_maskLayer) + m_maskLayer->setGeometry(0, 0, width(), height()); + QWidget::resizeEvent(event); +} + void MainWindow::initialize() { connect(ui->connectAction, &QAction::triggered, this, &MainWindow::onActionTrigger_connect); @@ -60,6 +68,11 @@ void MainWindow::initialize() connect(&SqlQueryExecutor::instance(), &SqlQueryExecutor::errorOccurred, this, &MainWindow::onSIG_errorFormSQLExecutor); + m_maskLayer = new QWidget(this); + //m_maskLayer->setAttribute(Qt::WA_TransparentForMouseEvents, true); + m_maskLayer->setStyleSheet("background:rgba(112,128,144,180);"); + m_maskLayer->hide(); + m_dbManager = new DatabaseManager(this); connect(m_dbManager, &DatabaseManager::errorOccurred, this, &MainWindow::onSIG_errorFromDBManger); connect(m_dbManager, &DatabaseManager::connectionStatusChanged, this, &MainWindow::onSIG_connectionStatusChanged); @@ -90,6 +103,18 @@ void MainWindow::initialize() // ui->splitter->setStretchFactor(1, 7); } +void MainWindow::showMaskLayer() +{ + m_maskLayer->setGeometry(0, 0, width(), height()); + m_maskLayer->raise(); + m_maskLayer->show(); +} + +void MainWindow::hideMaskLayer() +{ + m_maskLayer->hide(); +} + void MainWindow::showMessageDialog(MessageDialogType type,const QString& strTitle,const QString& strContent) { if(m_pMessageDialog == nullptr) @@ -107,7 +132,10 @@ void MainWindow::showMessageDialog(MessageDialogType type,const QString& strTitl // m_pMessageDialog->exec(); // else // m_pMessageDialog->show(); + + //showMaskLayer(); m_pMessageDialog->exec(); + //hideMaskLayer(); } void MainWindow::hideMessageDialog() { @@ -148,7 +176,10 @@ void MainWindow::onActionTrigger_connect() // QPoint centerPos = this->mapToGlobal(this->rect().center()); // centerPos -= QPoint(m_pConnectionDialog->width()/2, m_pConnectionDialog->height()/2); // m_pConnectionDialog->move(centerPos); - m_pConnectionDialog->show(); + + //showMaskLayer(); + m_pConnectionDialog->exec(); + //hideMaskLayer(); } void MainWindow::onActionTrigger_disconnect() { @@ -173,7 +204,10 @@ void MainWindow::onActionTrigger_addModel() int nY = this->geometry().y() + (this->height() - m_pModelInfoDialog->height()) * 0.5; m_pModelInfoDialog->move(nX, nY); m_pModelInfoDialog->setState(DS_New); + + //showMaskLayer(); m_pModelInfoDialog->exec(); + //hideMaskLayer(); } void MainWindow::onActionTrigger_removeModel() { diff --git a/source/messageBox.cpp b/source/messageBox.cpp new file mode 100644 index 0000000..b172b0f --- /dev/null +++ b/source/messageBox.cpp @@ -0,0 +1,87 @@ +#include "messageBox.h" +#include "ui_messageDialog.h" + +//MessageBoxBtn g_msgBoxBtn = btn_Null; + +MessageBox::MessageBox(QWidget *parent) + : QDialog(parent) + , ui(new Ui::messageDialog) +{ + ui->setupUi(this); + + if(QSysInfo::kernelType() == "linux") + { + //Linux下默认的Qt::Dialog即使有父窗口也无法按照子窗口的行为进行展示,并且最大、最小按钮不好关闭,因此需要去掉Dialog属性,随之而来的问题是,模态无法起作用 + setWindowFlags(windowFlags() & ~Qt::Dialog); + setStyleSheet("QDialog{border: 1px solid rgb(205,205,205);border-radius:5px;background-color:rgb(245,245,245);background-color:rgb(245,245,245);}"); + } + else + { + setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint);//去掉关闭按钮和图标 + setFixedSize(width(), height()); //不可缩放 + } + + connect(ui->btnConfrim, SIGNAL(clicked()), this, SLOT(onBtnClicked_confirm())); + connect(ui->btnYes, SIGNAL(clicked()), this, SLOT(onBtnClicked_yes())); + connect(ui->btnNo, SIGNAL(clicked()), this, SLOT(onBtnClicked_no())); +} + +MessageBox::~MessageBox() +{ + delete ui; +} + +void MessageBox::setType(MessageBoxType type) +{ + if(type == t_information) + { + ui->typeLabel->setStyleSheet("border-image: url(:/img/images/icon_information.png);"); + ui->stackedWidget->setCurrentIndex(0); + } + else if(type == t_question) + { + ui->typeLabel->setStyleSheet("border-image: url(:/img/images/icon_question.png);"); + ui->stackedWidget->setCurrentIndex(1); + } + else if(type == t_warning) + { + ui->typeLabel->setStyleSheet("border-image: url(:/img/images/icon_no.png);"); + ui->stackedWidget->setCurrentIndex(0); + } +} + +void MessageBox::setMessage(MessageBoxType type,const QString& strTitle,const QString& strContent) +{ + setType(type); + ui->labelTitle->setText(strTitle); + setWindowTitle(strTitle); + ui->labelContent->setText(strContent); +} + +int MessageBox::show(MessageBoxType type,const QString& strTitle,const QString& strContent) +{ + MessageBox msgBox; + msgBox.setMessage(type, strTitle, strContent); + return msgBox.exec(); +} + +void MessageBox::onBtnClicked_confirm() +{ + // hide(); + accept(); +} + +void MessageBox::onBtnClicked_yes() +{ + // g_msgDlgBtn = btn_Yes; + // hide(); + accept(); +} + +void MessageBox::onBtnClicked_no() +{ + // g_msgDlgBtn = btn_No; + // hide(); + reject(); +} + diff --git a/source/sqlQueryExecutor.cpp b/source/sqlQueryExecutor.cpp index 6f91463..6e121f1 100644 --- a/source/sqlQueryExecutor.cpp +++ b/source/sqlQueryExecutor.cpp @@ -446,6 +446,24 @@ int SqlQueryExecutor::getAttributeCount(const QString& connectionName, int model return count; } +int SqlQueryExecutor::getAllAttributeCount(const QString& connectionName) +{ + int count = 0; + QString strSQL = QString("SELECT COUNT(*) FROM basic.attribute"); + try + { + QSqlQuery query = executeSQL(connectionName, strSQL); + if(query.next()) + count = query.value(0).toInt(); + } + catch (const DatabaseException& e) + { + LOG_ERROR("SQL", QString::fromWCharArray(L"获取属性数量失败")); + } + + return count; +} + bool SqlQueryExecutor::getAttributeInfo(const QString& connectionName, const QString& columns, Attribute& attribute) { QString strSQL = QString("SELECT %1 FROM basic.attribute WHERE id = %2").arg(columns).arg(attribute.id); @@ -472,21 +490,41 @@ bool SqlQueryExecutor::getAttributeInfo(const QString& connectionName, const QSt return true; } -bool SqlQueryExecutor::attributeTypeExistsInDB(const QString& connectionName, const QString& type) +int SqlQueryExecutor::attributeTypeExistsInDB(const QString& connectionName, const QString& type) { - bool exists = false; + int id = -1; QString strSQL = "SELECT id FROM basic.attribute WHERE attribute = \'" + type + "\'"; try { QSqlQuery query = executeSQL(connectionName, strSQL); if(query.next()) - exists = true; + id = query.value(0).toInt(); } catch (const DatabaseException& e) { - exists = true; + id = -1; } - return exists; + return id; +} + +bool SqlQueryExecutor::attributeTypeUseByModelGroup(const QString& connectionName, int attributeID, int modelID, int groupID) +{ + QString strSQL = "SELECT id FROM basic.model_attribute WHERE model_type_id = :modelID AND attribute_group_id = :groupID AND attribute_id = :attributeID"; + QVariantHash params; + params.insert(":modelID", modelID); + params.insert(":groupID", groupID); + params.insert(":attributeID", attributeID); + try + { + QSqlQuery query = executeSQL(connectionName, strSQL, params); + if(query.next()) + return true; + } + catch (const DatabaseException& e) + { + return false; + } + return false; } bool SqlQueryExecutor::batchInsertAttributes(const QString& connectionName, int modelID, int attributeGroupID, QList attributes) @@ -509,6 +547,12 @@ bool SqlQueryExecutor::batchInsertAttributes(const QString& connectionName, int QList attributeIDList; for(const Attribute& attribute : attributes) { + if(attribute.id != -1) //新建条目是通过选择已有的记录完成,此类不再做重复插入 + { + attributeIDList.append(attribute.id); + continue; + } + qint64 attributeID = QDateTime::currentDateTime().toMSecsSinceEpoch(); //先向model_type中插入一条记录 QString strSQL = "INSERT INTO basic.attribute (attribute, attribute_name, data_type_id, length_precision, default_value) VALUES " diff --git a/ui/attributeSelector.ui b/ui/attributeSelector.ui new file mode 100644 index 0000000..5f3392d --- /dev/null +++ b/ui/attributeSelector.ui @@ -0,0 +1,713 @@ + + + AttributeSelector + + + + 0 + 0 + 1111 + 481 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 36 + + + + + 16777215 + 36 + + + + QWidget #searchBar +{ +background-color: rgb(243, 243, 243); +} + +QLineEdit +{ +border:1px solid rgb(210,210,210); +border-radius:3px; +} + + + + + + 20 + 10 + 61 + 16 + + + + 属性类别: + + + + + + 80 + 8 + 113 + 20 + + + + + + + 280 + 8 + 113 + 20 + + + + + + + 220 + 10 + 61 + 16 + + + + 属性名称: + + + + + + 420 + 5 + 61 + 26 + + + + QPushButton +{ +color: rgb(250, 250, 250); +font: 9pt; +border:0px; +border-radius:5px; +background-color:rgb(67,160,249); +} +QPushButton:hover +{ +background-color:rgb(55,131,204); +} +QPushButton:pressed +{ +background-color:rgb(67,160,249); +} + + + 查找 + + + + :/img/images/icon_search_white.png:/img/images/icon_search_white.png + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + 31 + + + + + 16777215 + 31 + + + + QWidget #toolBar +{ + background-color: rgb(243, 243, 243); +} + +QPushButton +{ + border: 0px solid rgb(205,205,205); + border-radius:0px; +} +QPushButton:hover +{ + background-color:rgba(70,130,180,35); +} +QPushButton:pressed +{ + background-color:rgba(70,130,180,65); +} + + + + QLayout::SizeConstraint::SetNoConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 150 + 0 + + + + + 150 + 16777215 + + + + + false + + + + 10 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 添加 + + + + + + + + + + :/img/images/icon_plus.png + :/img/images/icon_plus_disable.png:/img/images/icon_plus.png + + + + 16 + 16 + + + + + + false + + + + 36 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 删除 + + + + + + + + + + :/img/images/icon_subtract.png + :/img/images/icon_subtract_disable.png:/img/images/icon_subtract.png + + + + 16 + 16 + + + + + + false + + + + 62 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 提交修改 + + + + + + + :/img/images/icon_done.png + :/img/images/icon_done_disable.png:/img/images/icon_done.png + + + + 16 + 16 + + + + + + false + + + + 88 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 取销修改 + + + + + + + :/img/images/icon_close.png + :/img/images/icon_close_disable.png:/img/images/icon_close.png + + + + 16 + 16 + + + + + + true + + + + 114 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 刷新 + + + + + + + + + + :/img/images/icon_refresh3.png + :/img/images/icon_refresh3_disable.png:/img/images/icon_refresh3.png + + + + 16 + 16 + + + + + + + + + Qt::Orientation::Horizontal + + + + 727 + 20 + + + + + + + + + 300 + 0 + + + + + 300 + 16777215 + + + + + true + + + + 210 + 5 + 41 + 21 + + + + + 41 + 21 + + + + + 41 + 21 + + + + border:0px; +background-color: rgb(255, 255, 255); + + + 1 + + + Qt::AlignmentFlag::AlignCenter + + + + + false + + + + 170 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 第一页 + + + + + + + + + + :/img/images/icon_first.png:/img/images/icon_first.png + + + + 16 + 16 + + + + + + false + + + + 272 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 最后一页 + + + + + + + + + + :/img/images/icon_last.png:/img/images/icon_last.png + + + + 16 + 16 + + + + + + false + + + + 190 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 上一页 + + + + + + + + + + :/img/images/icon_previous.png:/img/images/icon_previous.png + + + + 16 + 16 + + + + + + false + + + + 252 + 5 + 21 + 21 + + + + + 21 + 21 + + + + + 21 + 21 + + + + 下一页 + + + + + + + + + + :/img/images/icon_next.png:/img/images/icon_next.png + + + + 16 + 16 + + + + + + + 12 + 5 + 151 + 21 + + + + + + + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter + + + + + + + + + + + + + + diff --git a/ui/messageDialog.ui b/ui/messageDialog.ui index 9eaeb5a..e1fd5b0 100644 --- a/ui/messageDialog.ui +++ b/ui/messageDialog.ui @@ -64,7 +64,7 @@ font: 10pt; - 获取属性组别信息失败,详情可见日志文件 + 该类型已存在,是否读取数据载入详细数据 diff --git a/ui/textEditWidget.ui b/ui/textEditWidget.ui index 3568bfd..fc2b9a8 100644 --- a/ui/textEditWidget.ui +++ b/ui/textEditWidget.ui @@ -64,7 +64,7 @@ background-color:rgb(255,255,255); - Qt::FocusPolicy::ClickFocus + Qt::FocusPolicy::StrongFocus background-color: transparent; @@ -98,7 +98,7 @@ padding:2px; 0 - 10 + 5 0 @@ -132,14 +132,14 @@ font: 8pt "Microsoft YaHei UI"; - 51 - 26 + 41 + 21 - 51 - 26 + 41 + 21 @@ -166,14 +166,14 @@ QPushButton:pressed - 51 - 26 + 41 + 21 - 51 - 26 + 41 + 21