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;
|
||
}
|