logplus/Workflow/WFWidget/src/PaiLineEdit.cpp

458 lines
13 KiB
C++
Raw Normal View History

2026-01-16 17:18:41 +08:00
/**
* @file PaiLineEdit.cpp
* @brief PaiLineEdit是P.A.I系统定制发布的单行文本框控件
* @date 2011-10-21
*/
#include <QPixmap>
#include <QIcon>
#include <QSize>
#include <QPushButton>
#include <QHBoxLayout>
#include <QPainter>
#include <QValidator>
#include <QKeyEvent>
#include <QInputMethodEvent>
#include <QTimer>
#include <QFontMetrics>
#include <QApplication>
#include <QClipboard>
#include <QCompleter>
#include <QMenu>
#include <QAction>
#include <QAbstractItemView>
#include "PaiLineEdit.h"
#include "SmartCompleter.h"
using namespace pai::gui;
#define DEFAULT_HEIGHT 18 ///< 默认高度
PaiLineEdit::PaiLineEdit(QWidget *pParent) :
QLineEdit(pParent)
{
Init();
}
PaiLineEdit::PaiLineEdit(const QString & strText, QWidget *pParent) :
QLineEdit(strText, pParent)
{
Init();
}
void PaiLineEdit::InsertCompletion(const QString& completion)
{
setText(completion);
selectAll();
}
void PaiLineEdit::SetSmartCompleter(pai::SmartCompleter *pComleter)
{
if (m_pCompleter)
{
QObject::disconnect(m_pCompleter, 0, this, 0);
}
m_pCompleter = pComleter;
if (!m_pCompleter)
{
return;
}
m_pCompleter->setWidget(this);
connect(m_pCompleter, SIGNAL(activated(const QString&)), this, SLOT(InsertCompletion(const QString&)));
}
pai::SmartCompleter *PaiLineEdit::SmartCompleter() const
{
return m_pCompleter;
}
void PaiLineEdit::Init()
{
m_pCompleter = NULL;
m_PromptType = PT_NULL;
m_pDelayTimer = new QTimer(this);
m_pDelayTimer->setInterval(300);
this->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop);
m_pRightPBtn = NULL;
setMinimumHeight(DEFAULT_HEIGHT); // 该值不在style sheet中设置否则会造成其它位置不能设置该值
connect(this, SIGNAL(editingFinished()), this, SLOT(TextEditingFinished()));
connect(this, SIGNAL(textChanged(const QString&)), m_pDelayTimer, SLOT(start()));
connect(m_pDelayTimer, SIGNAL(timeout()), this, SLOT(EmitEditingStoped()));
}
void PaiLineEdit::SetRightIcon(const QString & iconPath)
{
QPixmap pixmap(iconPath);
// 添加右边按钮控件
if(m_pRightPBtn == NULL)
{
m_pRightPBtn = new QPushButton;
}
m_pRightPBtn->setIcon(QIcon(pixmap));
QSize size = QSize(pixmap.size().width() + 6, pixmap.size().height() + 4);
m_pRightPBtn->setMinimumSize(size);
m_pRightPBtn->setMaximumSize(size); // 设置按钮的大小为图片的大小
m_pRightPBtn->setFocusPolicy(Qt::NoFocus); // 得到焦点的时候,不显示虚线框
m_pRightPBtn->setFlat(true);
m_pRightPBtn->setDefault(true);
QHBoxLayout *pHLayout = new QHBoxLayout();
pHLayout->setContentsMargins(0, 0, 0, 0);
pHLayout->addStretch();
pHLayout->addWidget(m_pRightPBtn);
// 设置输入框中文件输入区, 不让输入的文字被藏在按钮下
setLayout(pHLayout);
setTextMargins(0, 1, pixmap.size().width(), 1);
// 触发信号
connect(m_pRightPBtn, SIGNAL(clicked()), this, SIGNAL(RightIconClicked()));
}
void PaiLineEdit::SetValidatorFailureMessage(const QString & validateFailure)
{
m_ValidateMessage = validateFailure;
}
void PaiLineEdit::SetExceedMaxLengthMessage(const QString & exceedMaxLength)
{
m_ExceedMaxLengthMessage = exceedMaxLength;
}
void PaiLineEdit::setPlaceholderText(const QString & text)
{
m_PlaceholderText = text;
}
QString PaiLineEdit::placeholderText() const
{
return m_PlaceholderText;
}
void PaiLineEdit::paintEvent(QPaintEvent *pEvent)
{
QPainter p(this);
QLineEdit::paintEvent(pEvent);
QPainter painter(this);
// draw placeholder text as needed
if(!m_PlaceholderText.isEmpty() && text().isEmpty())
{
QRect phRect = rect();
phRect.adjust(4, 0, 0, 0);
painter.setPen(Qt::gray);
painter.drawText(phRect, Qt::AlignTop | Qt::AlignLeft, m_PlaceholderText);
}
// 当错误模式时显示红线请勿使用style sheet来设置以避免重复设置带来的问题
if(m_PromptType == PT_Error)
{
painter.setPen(QColor("#CC0000"));
painter.drawRect(rect().adjusted(0, 0, -1, -1));
}
}
void PaiLineEdit::keyReleaseEvent(QKeyEvent *pEvent)
{
QLineEdit::keyReleaseEvent(pEvent);
}
void PaiLineEdit::keyPressEvent(QKeyEvent *pEvent)
{
QString orgText = text();//输入前的文本
int selStart = selectionStart();//输入前选中文本的偏移量
int cursPos = cursorPosition();//输入前鼠标所在文本位置偏移量
QString selText = selectedText();//输入前选中文本
if (m_pCompleter && m_pCompleter->popup()->isVisible())
{
// The following keys are forwarded by the completer to the widget
switch (pEvent->key())
{
case Qt::Key_Enter:
case Qt::Key_Return:
case Qt::Key_Escape:
case Qt::Key_Tab:
case Qt::Key_Backtab:
pEvent->ignore();
return; // Let the completer do default behavior
break;
default:
break;
}
}
QLineEdit::keyPressEvent(pEvent); // Don't send the shortcut (CTRL-E) to the text edit.
if (m_pCompleter != NULL && (pEvent->key() != Qt::Key_Alt))
{
m_pCompleter->Update(text());
m_pCompleter->popup()->setCurrentIndex(m_pCompleter->completionModel()->index(0, 0));
}
if((pEvent->key() == Qt::Key_Backspace) || (pEvent->key() == Qt::Key_Delete))
{
return;
}
if(((pEvent->key() == Qt::Key_C)
|| (pEvent->key() == Qt::Key_A)
|| (pEvent->key() == Qt::Key_Z)
|| (pEvent->key() == Qt::Key_S))
&& (pEvent->modifiers() & Qt::ControlModifier))
{
return;
}
if(!((pEvent->key() == Qt::Key_V) && (pEvent->modifiers() & Qt::ControlModifier)))
{
CheckInput(pEvent->text());
}
if((pEvent->key() == Qt::Key_V) && (pEvent->modifiers() & Qt::ControlModifier))
{
QClipboard *pClipboard = QApplication::clipboard();
if(selStart == -1)
{
// 全部粘贴成功
if(orgText.insert(cursPos, pClipboard->text()) == text())
{
return;
}
if(orgText.size() > maxLength())
{
ShowPromptMessge(m_ExceedMaxLengthMessage, PaiLineEdit::PT_Warning);
return;
}
}
else
{
// 全部替换成功
orgText.remove(selStart, selText.size());
if(orgText.insert(selStart, pClipboard->text()) == text())
{
return;
}
if(orgText.size() > maxLength())
{
ShowPromptMessge(m_ExceedMaxLengthMessage, PaiLineEdit::PT_Warning);
return;
}
}
}
// 处理键盘的上下键和回车键
DealDirectionKey(pEvent->key());
}
void PaiLineEdit::TextEditingFinished()
{
emit EditingStoped(text());
emit EditingFinished(text());
}
PaiLineEdit::~PaiLineEdit()
{
int a;
}
void PaiLineEdit::inputMethodEvent(QInputMethodEvent *pEvent)
{
QLineEdit::inputMethodEvent(pEvent);
if (m_pCompleter != NULL)
{
m_pCompleter->Update(text());
m_pCompleter->popup()->setCurrentIndex(m_pCompleter->completionModel()->index(0, 0));
}
CheckInput(pEvent->commitString());
}
void PaiLineEdit::CheckInput(const QString & inputText)
{
QString ckText = text() + inputText;
const QValidator *pValidator = validator();
int pos = cursorPosition();
if(ckText.size() > maxLength())
{
ShowPromptMessge(m_ExceedMaxLengthMessage, PaiLineEdit::PT_Warning);
}
else if(pValidator && (pValidator->validate(ckText, pos) == QValidator::Invalid))
{
ShowPromptMessge(m_ValidateMessage, PaiLineEdit::PT_Warning);
}
}
void PaiLineEdit::ShowPromptMessge(const QString & message, PromptType type)
{
m_PromptMessage = message;
m_PromptType = type;
}
void PaiLineEdit::EmitEditingStoped()
{
m_pDelayTimer->stop();
emit EditingStoped(text());
}
QSize PaiLineEdit::sizeHint() const
{
QSize LineEditSizeHint = QLineEdit::sizeHint();
QFontMetrics fontWidth(font());
return QSize(fontWidth.width(m_ExceedMaxLengthMessage) + 30, LineEditSizeHint.height());
}
void PaiLineEdit::mousePressEvent(QMouseEvent *pEvent)
{
if(pEvent->button() == Qt::LeftButton)
{
emit LeftMousePress();
}
QLineEdit::mousePressEvent(pEvent);
}
bool PaiLineEdit::IsEmpty()
{
return text().isEmpty();
}
void PaiLineEdit::SetEditStopDuration(int duration)
{
m_pDelayTimer->setInterval(duration);
}
void PaiLineEdit::DealDirectionKey(int key)
{
QCompleter *pCompleter = m_pCompleter != NULL ? m_pCompleter : completer();
if(pCompleter)
{
QAbstractItemView *pPopupView = pCompleter->popup();
if(pPopupView && !pPopupView->isHidden())
{
// int key = event->key();
int count = pPopupView->model()->rowCount();
QModelIndex currentIndex = pPopupView->currentIndex();
if(Qt::Key_Down == key)
{
// 按向下方向键时,移动光标选中下一个完成列表中的项
int row = currentIndex.row() + 1;
if(row >= count)
{
row = 0;
}
QModelIndex index = pPopupView->model()->index(row, 0);
pPopupView->setCurrentIndex(index);
}
else if(Qt::Key_Up == key)
{
// 按向下方向键时,移动光标选中上一个完成列表中的项
int row = currentIndex.row() - 1;
if(row < 0)
{
row = count - 1;
}
QModelIndex index = pPopupView->model()->index(row, 0);
pPopupView->setCurrentIndex(index);
}
else if(Qt::Key_Escape == key)
{
// 按下Esc键时隐藏完成列表
pPopupView->hide();
}
else if((Qt::Key_Enter == key) || (Qt::Key_Return == key))
{
// 按下回车键时,使用完成列表中选中的项,并隐藏完成列表
if(currentIndex.isValid())
{
QString text = pPopupView->currentIndex().data().toString();
setText(text);
}
pPopupView->hide();
}
}
else
{
// 其他情况隐藏完成列表并使用QLineEdit的键盘按下事件
pPopupView->hide();
}
}
}
void PaiLineEdit::contextMenuEvent(QContextMenuEvent *pEvent)
{
QString orgText = text();//输入前的文本
int selStart = selectionStart();//输入前选中文本的偏移量
int cursPos = cursorPosition();//输入前鼠标所在文本位置偏移量
QString selText = selectedText();//输入前选中文本
//系统默认的右键菜单
QMenu *pDefaultMenu = createStandardContextMenu();
if(pDefaultMenu)
{
//菜单中被选中的action
QAction *pSelectedAction = pDefaultMenu->exec(pEvent->globalPos());
if(pSelectedAction)
{
QString actionText = pSelectedAction->iconText();
if(actionText.contains(tr("Paste")) || actionText.contains(tr("Ctrl+V")))
{
QClipboard *pClipboard = QApplication::clipboard();
if(selStart == -1)
{
// 粘贴板中内容插入文本框
if(orgText.insert(cursPos, pClipboard->text()) == text())
{
delete pDefaultMenu;
pDefaultMenu = NULL;
return;
}
// 粘贴后输入框中内容长度大于100显示警告
if(orgText.size() > maxLength())
{
ShowPromptMessge(m_ExceedMaxLengthMessage, PaiLineEdit::PT_Warning);
delete pDefaultMenu;
pDefaultMenu = NULL;
return;
}
}
else
{
// 移除鼠标选中的文本,插入粘贴板中的文本
orgText.remove(selStart, selText.size());
if(orgText.insert(selStart, pClipboard->text()) == text())
{
delete pDefaultMenu;
pDefaultMenu = NULL;
return;
}
// 粘贴后输入框中内容长度大于100显示警告
if(orgText.size() > maxLength())
{
ShowPromptMessge(m_ExceedMaxLengthMessage, PaiLineEdit::PT_Warning);
delete pDefaultMenu;
pDefaultMenu = NULL;
return;
}
}
// 校验是否有不合法的字符
const QValidator *pValidator = validator();
int pos = cursorPosition();
if(pValidator && (pValidator->validate(orgText, pos) == QValidator::Invalid))
{
ShowPromptMessge(m_ValidateMessage, PaiLineEdit::PT_Warning);
}
}
}
}
delete pDefaultMenu;
pDefaultMenu = NULL;
}