logplus/Workflow/WFWidget/src/PaiLineEdit.cpp
2026-01-16 17:18:41 +08:00

458 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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;
}