458 lines
13 KiB
C++
458 lines
13 KiB
C++
|
|
/**
|
|||
|
|
* @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;
|
|||
|
|
}
|