#include "attributeTableDelegate.h" #include "attributeTableModel.h" #include "attributeNamespace.h" #include "sqlQueryExecutor.h" #include "ui_textEditWidget.h" //#include "messageBox.h" #include #include #include #include #include #include TextEditWidget::TextEditWidget(QWidget* parent) : QWidget(parent), ui(new Ui::TextEditWidget) { ui->setupUi(this); setWindowFlags(Qt::FramelessWindowHint); m_promptString = ""; m_patternString = ""; connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &TextEditWidget::onTextChanged); connect(ui->btnConfirm, &QPushButton::clicked, this, &TextEditWidget::onBtnClicked_confirm); connect(ui->btnCancle, &QPushButton::clicked, this, &TextEditWidget::onBtnClicked_cancle); installEventFilter(this); ui->plainTextEdit->installEventFilter(this); } TextEditWidget::~TextEditWidget() { delete ui; } bool TextEditWidget::eventFilter(QObject* obj, QEvent* event) { if(obj == this && event->type() == QEvent::MouseButtonPress) return true; //戒断鼠标事件,防止传递给父组件(tableView)触发单元格切换造成的editor关闭 else if (obj == ui->plainTextEdit && event->type() == QEvent::KeyPress) { QKeyEvent* pKeyEvent = static_cast(event); if (pKeyEvent->key() == Qt::Key_Escape) { emit closeWidget(); //return true; } } return QWidget::eventFilter(obj, event); } // void TextEditWidget::mousePressEvent(QMouseEvent* event) // { // event->accept(); // } QString TextEditWidget::editText() { return ui->plainTextEdit->toPlainText(); } void TextEditWidget::setEditText(const QString& text) { ui->plainTextEdit->setPlainText(text); } void TextEditWidget::setPrompt(const QString& prompt) { m_promptString = prompt; ui->label->setText(m_promptString); } void TextEditWidget::setRegularExpression(const QString& pattern) { //QPlainTextEidt没有setValidator方法,所以需要在textChanged槽函数中进行处理 /*QRegularExpression regExp(pattern); QRegularExpressionValidator* validator = new QRegularExpressionValidator(regExp, this); ui->plainTextEdit->setValidator(validator);*/ m_patternString = pattern; m_regExp.setPattern(m_patternString.replace(1, 0 , "^")); } 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); if(m_patternString.isEmpty()) return; QString text = ui->plainTextEdit->toPlainText(); QString filtered = text; filtered.replace(m_regExp, ""); //qDebug() << text << " " << m_regExp.pattern() << " " << filtered; if (filtered != text) { // 保存光标位置,避免替换后光标跳转 QTextCursor cursor = ui->plainTextEdit->textCursor(); int pos = cursor.position(); ui->plainTextEdit->setPlainText(filtered); cursor.setPosition(pos - (text.length() - filtered.length())); ui->plainTextEdit->setTextCursor(cursor); } } void TextEditWidget::onBtnClicked_confirm() { emit confirm(); } void TextEditWidget::onBtnClicked_cancle() { emit cancle(); } AttributeTableDelegate::AttributeTableDelegate(QTableView* view, const QString& connection, QObject *parent) : QStyledItemDelegate(parent) , m_tableView(view) , m_connection(connection) { } AttributeTableDelegate::~AttributeTableDelegate() {} void AttributeTableDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { //根据行号设置交替色 QStyleOptionViewItem opt = option; initStyleOption(&opt, index); if ((index.row() + 1) % 2 == 0) { //opt.backgroundBrush = QBrush(QColor(243, 245, 249)); painter->fillRect(opt.rect, QColor(240, 248, 255)); } //处理加粗字体逻辑 if(/*index.column() == 0 || */index.data(Qt::UserRole + AttributeEidt::EditStatus).toBool()) { opt.font.setBold(true); //opt.palette.setColor(QPalette::Text, Qt::red); } //处理被选择时的背景色,注意:如果qss中有设置,会覆盖此处逻辑 if(option.state.testFlag(QStyle::State_Selected)) { if(index.column() == 0) painter->fillRect(opt.rect, QColor(70, 130, 180)); else painter->fillRect(opt.rect, QColor(211, 241, 250)); } //如果行号列(第一列)被选中,做整行处理 if(m_tableView && m_tableView->model() && index.column() != 0) { QModelIndex numberIndex = m_tableView->model()->index(index.row(), 0); QItemSelectionModel *selectionModel = m_tableView->selectionModel(); if(selectionModel->isSelected(numberIndex)) painter->fillRect(opt.rect, QColor(211, 241, 250)); } //先执行默认绘制(包括背景、文本等基础元素) QStyledItemDelegate::paint(painter, opt, index); //最后绘制删除线(确保位于最顶层) if(m_tableView && m_tableView->model()) { QModelIndex numberIndex = m_tableView->model()->index(index.row(), 0); QString text = numberIndex.data(Qt::DisplayRole).toString(); if(text.contains("-")) { QRect rect = m_tableView->visualRect(index); painter->save(); painter->setPen(Qt::red); painter->drawLine(rect.left(), rect.y() + rect.height()*0.5, rect.right(), rect.y() + rect.height()*0.5); //painter属于view,所以要以view的坐标系为标准 painter->restore(); } } } QWidget* AttributeTableDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const { int dataCol = index.column() - 1; if(dataCol == 0) //属性类型 { TextEditWidget* textEditor = new TextEditWidget(parent); textEditor->setPrompt(QString::fromWCharArray(L"类型必须为英文")); textEditor->setRegularExpression("[A-Za-z0-9_]"); connect(textEditor, &TextEditWidget::confirm, this, [=]{ /*QString strText = textEditor->editText(); int id = SqlQueryExecutor::instance().getAttributeID(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); if(m_tableView) m_tableView->setFocus(); }); connect(textEditor, &TextEditWidget::cancle, this, [=]{ //createEditor为const成员函数,而closeEditor是QAbstractItemDelegate的非const信号,在const成员函数中不能直接调用,需要转换为非const指针 emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); if(m_tableView) m_tableView->setFocus(); }); connect(textEditor, &TextEditWidget::closeWidget, this, [=]{ if(m_tableView) m_tableView->setFocus(); }); //延迟获取焦点,防止可能因渲染未完成失效 QTimer::singleShot(10, this, [textEditor]() { textEditor->setFocusToTextEdit(); }); return textEditor; } else if(dataCol == 1 || dataCol == 4) //1-数据名称、4-默认值 { TextEditWidget* textEditor = new TextEditWidget(parent); connect(textEditor, &TextEditWidget::confirm, this, [=]{ emit const_cast(this)->commitData(textEditor); emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); if(m_tableView) m_tableView->setFocus(); }); connect(textEditor, &TextEditWidget::cancle, this, [=]{ emit const_cast(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint); if(m_tableView) m_tableView->setFocus(); }); connect(textEditor, &TextEditWidget::closeWidget, this, [=]{ if(m_tableView) m_tableView->setFocus(); }); //延迟获取焦点,防止可能因渲染未完成失效 QTimer::singleShot(10, this, [textEditor]() { textEditor->setFocusToTextEdit(); }); return textEditor; } else if(dataCol == 2) //数据类型 { if(m_tableView) { auto* model = qobject_cast(m_tableView->model()); if(model) { QMap dataTypes = model->getDataTypes(); QComboBox* comboBox = new QComboBox(parent); for(auto dataType : dataTypes) comboBox->addItem(dataType.type); return comboBox; } } } else if(dataCol == 3) //数据长度 { QSpinBox* spinBox = new QSpinBox(parent); spinBox->setRange(-1, 999); spinBox->setValue(0); return spinBox; } else if(dataCol == 5) //可见性 { QComboBox* comboBox = new QComboBox(parent); comboBox->addItem("1"); comboBox->addItem("0"); return comboBox; } return QStyledItemDelegate::createEditor(parent, option, index); } // void AttributeTableDelegate::destroyEditor(QWidget* editor, const QModelIndex& index) const // { // emit const_cast(this)->closeEditor(editor, QAbstractItemDelegate::NoHint); // } 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); } void AttributeTableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QVariant newValue; if(TextEditWidget* textEditor = qobject_cast(editor)) newValue = textEditor->editText(); else if(QLineEdit* lineEdit = qobject_cast(editor)) newValue = lineEdit->text(); else if(QComboBox* comboBox = qobject_cast(editor)) newValue = comboBox->currentText(); else if(QSpinBox* spinBox = qobject_cast(editor)) newValue = spinBox->value(); else { QStyledItemDelegate::setModelData(editor, model, index); return; } QVariant oldValue = index.data(Qt::EditRole); //qDebug() << "newValue: " << newValue.toString() << "oldValue: " << oldValue.toString(); 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().getAttributeID(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); } void AttributeTableDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { if(TextEditWidget* textEditor = qobject_cast(editor)) { QSize editorSize = textEditor->size(); QRect optRect = option.rect; QWidget* parentWidget = textEditor->parentWidget(); int nX = optRect.x(); if(parentWidget && (nX + editorSize.width()) > parentWidget->width()) nX = parentWidget->width() - editorSize.width(); int nY = optRect.bottom() - editorSize.height(); if(nY < 0) nY = 0; textEditor->setGeometry(nX, nY, editorSize.width(), editorSize.height()); } else editor->setGeometry(option.rect); } bool AttributeTableDelegate::isEnumType(const QModelIndex& index) const { return index.data(Qt::UserRole + AttributeEidt::DataType).toInt() == AttributeEidt::ENUM; }