411 lines
15 KiB
C++
411 lines
15 KiB
C++
#include "attributeTableDelegate.h"
|
||
#include "attributeTableModel.h"
|
||
#include "attributeNamespace.h"
|
||
#include "sqlQueryExecutor.h"
|
||
#include "ui_textEditWidget.h"
|
||
//#include "messageBox.h"
|
||
#include <QSpinBox>
|
||
#include <QComboBox>
|
||
#include <QLineEdit>
|
||
#include <QPainter>
|
||
#include <QTimer>
|
||
#include <QRegularExpressionValidator>
|
||
|
||
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<QKeyEvent*>(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(49, 54, 63));
|
||
}
|
||
|
||
//处理加粗字体逻辑
|
||
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(49, 91, 125));
|
||
else
|
||
painter->fillRect(opt.rect, QColor(65, 122, 166));
|
||
}
|
||
|
||
//如果行号列(第一列)被选中,做整行处理
|
||
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(65, 122, 166));
|
||
}
|
||
|
||
//先执行默认绘制(包括背景、文本等基础元素)
|
||
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<AttributeTableDelegate*>(this)->commitData(textEditor);
|
||
emit const_cast<AttributeTableDelegate*>(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint);
|
||
}*/
|
||
//判断放在setModelData函数中,因为那里会先进行是否做内容改变的判断
|
||
emit const_cast<AttributeTableDelegate*>(this)->commitData(textEditor);
|
||
emit const_cast<AttributeTableDelegate*>(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<AttributeTableDelegate*>(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<AttributeTableDelegate*>(this)->commitData(textEditor);
|
||
emit const_cast<AttributeTableDelegate*>(this)->closeEditor(textEditor, QAbstractItemDelegate::NoHint);
|
||
if(m_tableView)
|
||
m_tableView->setFocus();
|
||
});
|
||
connect(textEditor, &TextEditWidget::cancle, this, [=]{
|
||
emit const_cast<AttributeTableDelegate*>(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<AttributeTableModel*>(m_tableView->model());
|
||
if(model)
|
||
{
|
||
QMap<int, AttributeTableModel::DataType> 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->setStyleSheet("border-radius: 0px;");
|
||
spinBox->setRange(-1, 999);
|
||
spinBox->setValue(0);
|
||
return spinBox;
|
||
}
|
||
else if(dataCol == 5) //可见性
|
||
{
|
||
QComboBox* comboBox = new QComboBox(parent);
|
||
//comboBox->setStyleSheet("QComboBox{border-radius: 0px;background-color:rgb(67, 73, 87);}");
|
||
comboBox->addItem("1");
|
||
comboBox->addItem("0");
|
||
comboBox->addItem("2");
|
||
return comboBox;
|
||
}
|
||
|
||
return QStyledItemDelegate::createEditor(parent, option, index);
|
||
}
|
||
|
||
// void AttributeTableDelegate::destroyEditor(QWidget* editor, const QModelIndex& index) const
|
||
// {
|
||
// emit const_cast<AttributeTableDelegate*>(this)->closeEditor(editor, QAbstractItemDelegate::NoHint);
|
||
// }
|
||
|
||
void AttributeTableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||
{
|
||
if(TextEditWidget* textEditor = qobject_cast<TextEditWidget*>(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<TextEditWidget*>(editor))
|
||
newValue = textEditor->editText();
|
||
else if(QLineEdit* lineEdit = qobject_cast<QLineEdit*>(editor))
|
||
newValue = lineEdit->text();
|
||
else if(QComboBox* comboBox = qobject_cast<QComboBox*>(editor))
|
||
newValue = comboBox->currentText();
|
||
else if(QSpinBox* spinBox = qobject_cast<QSpinBox*>(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<AttributeTableModel*>(model);
|
||
auto textEditor = qobject_cast<TextEditWidget*>(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<AttributeTableDelegate*>(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<AttributeTableModel*>(model);
|
||
attributeTableModel->updateRowThroughExisitingAttribute(index.row(), id);
|
||
return;
|
||
}
|
||
else
|
||
return;*/
|
||
emit const_cast<AttributeTableDelegate*>(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<TextEditWidget*>(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 if(QComboBox* comboBox = qobject_cast<QComboBox*>(editor))
|
||
// {
|
||
// comboBox->setGeometry(option.rect);
|
||
// comboBox->setStyleSheet("border-radius: 0px;background-color:rgb(58, 63, 75);");
|
||
// }
|
||
else if(QSpinBox* spinBox = qobject_cast<QSpinBox*>(editor))
|
||
{
|
||
spinBox->setGeometry(option.rect.adjusted(-3,-3,3,3));
|
||
spinBox->setStyleSheet("background-color:rgb(58, 63, 75);"); //QSpinBox不能设置和border相关的项,否则up button无法点击,暂时不知道原因
|
||
}
|
||
else
|
||
{
|
||
editor->setGeometry(option.rect);
|
||
editor->setStyleSheet("border-radius: 0px;background-color:rgb(58, 63, 75);");
|
||
}
|
||
|
||
}
|
||
|
||
bool AttributeTableDelegate::isEnumType(const QModelIndex& index) const
|
||
{
|
||
return index.data(Qt::UserRole + AttributeEidt::DataType).toInt() == AttributeEidt::ENUM;
|
||
}
|