8#if QT_CONFIG(itemviews)
9#include "qabstractitemview.h"
11#if QT_CONFIG(draganddrop)
15# include "qwidgetaction.h"
18#if QT_CONFIG(accessibility)
19#include "qaccessible.h"
26#if QT_CONFIG(animation)
27#include <qpropertyanimation.h>
29#include <qstylehints.h>
30#include <qvalidator.h>
34const int QLineEditPrivate::verticalMargin(1);
35const int QLineEditPrivate::horizontalMargin(2);
38QRect QLineEditPrivate::adjustedControlRect(
const QRect &rect)
const
40 QRect widgetRect = !rect.isEmpty() ? rect : q_func()->rect();
41 QRect cr = adjustedContentsRect();
42 int cix = cr.x() - hscroll + horizontalMargin;
43 return widgetRect.translated(QPoint(cix, vscroll - control->ascent() + q_func()->fontMetrics().ascent()));
46int QLineEditPrivate::xToPos(
int x, QTextLine::CursorPosition betweenOrOn)
const
48 QRect cr = adjustedContentsRect();
49 x-= cr.x() - hscroll + horizontalMargin;
50 return control->xToPos(x, betweenOrOn);
53QString QLineEditPrivate::textBeforeCursor(
int curPos)
const
55 const QString &text = control->text();
56 return text.mid(0, curPos);
59QString QLineEditPrivate::textAfterCursor(
int curPos)
const
61 const QString &text = control->text();
62 return text.mid(curPos);
65bool QLineEditPrivate::inSelection(
int x)
const
67 x -= adjustedContentsRect().x() - hscroll + horizontalMargin;
68 return control->inSelection(x);
71QRect QLineEditPrivate::cursorRect()
const
73 return adjustedControlRect(control->cursorRect());
76#if QT_CONFIG(completer)
77void QLineEditPrivate::connectCompleter()
80 QObject::connect(control->completer(), qOverload<
const QString &>(&QCompleter::activated),
81 q, &QLineEdit::setText);
82 QObjectPrivate::connect(control->completer(), qOverload<
const QString &>(&QCompleter::highlighted),
83 this, &QLineEditPrivate::completionHighlighted);
86void QLineEditPrivate::disconnectCompleter()
89 QObject::disconnect(control->completer(), qOverload<
const QString &>(&QCompleter::activated),
90 q, &QLineEdit::setText);
91 QObjectPrivate::disconnect(control->completer(), qOverload<
const QString &>(&QCompleter::highlighted),
92 this, &QLineEditPrivate::completionHighlighted);
95void QLineEditPrivate::completionHighlighted(
const QString &newText)
98 if (control->completer()->completionMode() != QCompleter::InlineCompletion) {
101 int c = control->cursor();
102 QString text = control->text();
103 q->setText(QStringView{text}.left(c) + QStringView{newText}.mid(c));
104 control->moveCursor(control->end(),
false);
106 const bool mark =
true;
108 const bool mark = (imHints & Qt::ImhNoPredictiveText);
110 control->moveCursor(c, mark);
116void QLineEditPrivate::handleWindowActivate()
119 if (!q->hasFocus() && control->hasSelectedText())
123void QLineEditPrivate::textEdited(
const QString &text)
127 emit q->textEdited(text);
128#if QT_CONFIG(completer)
129 if (control->completer()
130 && control->completer()->completionMode() != QCompleter::InlineCompletion)
131 control->complete(-1);
135void QLineEditPrivate::cursorPositionChanged(
int from,
int to)
139 emit q->cursorPositionChanged(from, to);
142#ifdef QT_KEYPAD_NAVIGATION
143void QLineEditPrivate::editFocusChange(
bool e)
150void QLineEditPrivate::selectionChanged()
153 if (control->preeditAreaText().isEmpty()) {
154 QStyleOptionFrame opt;
155 q->initStyleOption(&opt);
156 bool showCursor = control->hasSelectedText() ?
157 q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q):
159 setCursorVisible(showCursor);
162 emit q->selectionChanged();
163#if QT_CONFIG(accessibility)
164 QAccessibleTextSelectionEvent ev(q, control->selectionStart(), control->selectionEnd());
165 ev.setCursorPosition(control->cursorPosition());
166 QAccessible::updateAccessibility(&ev);
170void QLineEditPrivate::updateNeeded(
const QRect &rect)
172 q_func()->update(adjustedControlRect(rect));
175void QLineEditPrivate::init(
const QString& txt)
179 const auto qUpdateMicroFocus = [q]()
181 q->updateMicroFocus();
183 control =
new QWidgetLineControl(txt);
184 control->setParent(q);
185 control->setFont(q->font());
186 QObject::connect(control, &QWidgetLineControl::textChanged,
187 q, &QLineEdit::textChanged);
188 QObjectPrivate::connect(control, &QWidgetLineControl::textEdited,
189 this, &QLineEditPrivate::textEdited);
190 QObjectPrivate::connect(control, &QWidgetLineControl::cursorPositionChanged,
191 this, &QLineEditPrivate::cursorPositionChanged);
192 QObjectPrivate::connect(control, &QWidgetLineControl::selectionChanged,
193 this, &QLineEditPrivate::selectionChanged);
194 QObjectPrivate::connect(control, &QWidgetLineControl::editingFinished,
195 this, &QLineEditPrivate::controlEditingFinished);
196#ifdef QT_KEYPAD_NAVIGATION
197 QObject::connect(control, &QWidgetLineControl::editFocusChange,
198 this, &QLineEditPrivate::editFocusChange);
200 QObject::connect(control, &QWidgetLineControl::cursorPositionChanged,
201 q, qUpdateMicroFocus);
203 QObject::connect(control, &QWidgetLineControl::textChanged,
204 q, qUpdateMicroFocus);
206 QObject::connect(control, &QWidgetLineControl::updateMicroFocus,
207 q, qUpdateMicroFocus);
210 QObject::connect(control, &QWidgetLineControl::selectionChanged,
211 q, qOverload<>(&QLineEdit::update));
213 QObject::connect(control, &QWidgetLineControl::selectionChanged,
214 q, qUpdateMicroFocus);
216 QObject::connect(control, &QWidgetLineControl::displayTextChanged,
217 q, qOverload<>(&QLineEdit::update));
219 QObjectPrivate::connect(control, &QWidgetLineControl::updateNeeded,
220 this, &QLineEditPrivate::updateNeeded);
221 QObject::connect(control, &QWidgetLineControl::inputRejected,
222 q, &QLineEdit::inputRejected);
224 QStyleOptionFrame opt;
225 q->initStyleOption(&opt);
226 control->setPasswordCharacter(
char16_t(q->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, q)));
227 control->setPasswordMaskDelay(q->style()->styleHint(QStyle::SH_LineEdit_PasswordMaskDelay, &opt, q));
229 q->setCursor(Qt::IBeamCursor);
231 q->setFocusPolicy(Qt::StrongFocus);
232 q->setAttribute(Qt::WA_InputMethodEnabled);
235 q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit));
236 q->setBackgroundRole(QPalette::Base);
237 q->setAttribute(Qt::WA_KeyCompression);
238 q->setMouseTracking(
true);
239 q->setAcceptDrops(
true);
241 q->setAttribute(Qt::WA_MacShowFocusRect);
243 initMouseYThreshold();
246void QLineEditPrivate::initMouseYThreshold()
248 mouseYThreshold = QGuiApplication::styleHints()->mouseQuickSelectionThreshold();
251QRect QLineEditPrivate::adjustedContentsRect()
const
253 Q_Q(
const QLineEdit);
254 QStyleOptionFrame opt;
255 q->initStyleOption(&opt);
256 QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q);
257 r = r.marginsRemoved(effectiveTextMargins());
261void QLineEditPrivate::setCursorVisible(
bool visible)
264 if ((
bool)cursorVisible == visible)
266 cursorVisible = visible;
267 if (control->inputMask().isEmpty())
268 q->update(cursorRect());
273void QLineEditPrivate::setText(
const QString& text)
276 control->setText(text);
279void QLineEditPrivate::updatePasswordEchoEditing(
bool editing)
282 control->updatePasswordEchoEditing(editing);
283 q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod());
286void QLineEditPrivate::resetInputMethod()
289 if (q->hasFocus() && qApp) {
290 QGuiApplication::inputMethod()->reset();
295
296
297
298
299bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e )
302 if ( control->composeMode() ) {
303 int tmp_cursor = xToPos(e->position().toPoint().x());
304 int mousePos = tmp_cursor - control->cursor();
305 if ( mousePos < 0 || mousePos > control->preeditAreaText().size() )
309 if (e->type() == QEvent::MouseButtonRelease)
310 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
322#if QT_CONFIG(draganddrop)
323void QLineEditPrivate::drag()
327 QMimeData *data =
new QMimeData;
328 data->setText(control->selectedText());
329 QDrag *drag =
new QDrag(q);
330 drag->setMimeData(data);
331 Qt::DropAction action = drag->exec(Qt::CopyAction);
332 if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q)
333 control->removeSelection();
338#if QT_CONFIG(toolbutton)
339QLineEditIconButton::QLineEditIconButton(QWidget *parent)
340 : QToolButton(parent)
343 setFocusPolicy(Qt::NoFocus);
346QLineEditPrivate *QLineEditIconButton::lineEditPrivate()
const
348 QLineEdit *le = qobject_cast<QLineEdit *>(parentWidget());
349 return le ?
static_cast<QLineEditPrivate *>(qt_widget_private(le)) :
nullptr;
352void QLineEditIconButton::paintEvent(QPaintEvent *)
354 QPainter painter(
this);
355 QIcon::Mode state = QIcon::Disabled;
357 state = isDown() ? QIcon::Active : QIcon::Normal;
358 const QLineEditPrivate *lep = lineEditPrivate();
359 const int iconWidth = lep ? lep->sideWidgetParameters().iconSize : 16;
360 const QSize iconSize(iconWidth, iconWidth);
361 const QPixmap iconPixmap = icon().pixmap(iconSize, devicePixelRatio(), state, QIcon::Off);
362 QRect pixmapRect = QRect(QPoint(0, 0), iconSize);
363 pixmapRect.moveCenter(rect().center());
364 painter.setOpacity(m_opacity);
365 painter.drawPixmap(pixmapRect, iconPixmap);
368void QLineEditIconButton::actionEvent(QActionEvent *e)
371 case QEvent::ActionChanged: {
372 const auto *action = e->action();
373 if (isVisibleTo(parentWidget()) != action->isVisible()) {
374 setVisible(action->isVisible());
375 if (QLineEditPrivate *lep = lineEditPrivate())
376 lep->positionSideWidgets();
383 QToolButton::actionEvent(e);
386void QLineEditIconButton::setOpacity(qreal value)
388 if (!qFuzzyCompare(m_opacity, value)) {
395#if QT_CONFIG(animation)
396bool QLineEditIconButton::shouldHideWithText()
const
398 return m_hideWithText;
401void QLineEditIconButton::setHideWithText(
bool hide)
403 m_hideWithText = hide;
406void QLineEditIconButton::onAnimationFinished()
408 if (shouldHideWithText() && isVisible() && m_fadingOut) {
413 if (
auto le = lineEditPrivate())
414 le->updateGeometry_helper(
true);
418void QLineEditIconButton::animateShow(
bool visible)
420 m_fadingOut = !visible;
422 if (shouldHideWithText() && !isVisible()) {
426 if (
auto le = lineEditPrivate())
427 le->updateGeometry_helper(
true);
430 startOpacityAnimation(visible ? 1.0 : 0.0);
433void QLineEditIconButton::startOpacityAnimation(qreal endValue)
435 QPropertyAnimation *animation =
new QPropertyAnimation(
this, QByteArrayLiteral(
"opacity"),
this);
436 connect(animation, &QPropertyAnimation::finished,
this, &QLineEditIconButton::onAnimationFinished);
438 animation->setDuration(160);
439 animation->setEndValue(endValue);
440 animation->start(QAbstractAnimation::DeleteWhenStopped);
444void QLineEditIconButton::updateCursor()
447 setCursor(qFuzzyCompare(m_opacity, qreal(1.0)) || !parentWidget() ? QCursor(Qt::ArrowCursor) : parentWidget()->cursor());
452#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
453static void displayWidgets(
const QLineEditPrivate::SideWidgetEntryList &widgets,
bool display)
455 for (
const auto &e : widgets) {
456 if (e.flags & QLineEditPrivate::SideWidgetFadeInWithText)
457 static_cast<QLineEditIconButton *>(e.widget)->animateShow(display);
462void QLineEditPrivate::textChanged(
const QString &text)
464 if (hasSideWidgets()) {
465 const int newTextSize = text.size();
466 if (!newTextSize || !lastTextSize) {
467 lastTextSize = newTextSize;
468#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
469 const bool display = newTextSize > 0;
470 displayWidgets(leadingSideWidgets, display);
471 displayWidgets(trailingSideWidgets, display);
477void QLineEditPrivate::clearButtonClicked()
480 if (!q->text().isEmpty()) {
482 textEdited(QString());
486void QLineEditPrivate::controlEditingFinished()
490 emit q->returnPressed();
491 emit q->editingFinished();
494QLineEditPrivate::SideWidgetParameters QLineEditPrivate::sideWidgetParameters()
const
496 Q_Q(
const QLineEdit);
497 SideWidgetParameters result;
498 result.iconSize = q->style()->pixelMetric(QStyle::PM_LineEditIconSize,
nullptr, q);
499 result.margin = q->style()->pixelMetric(QStyle::PM_LineEditIconMargin,
nullptr, q);
500 result.widgetWidth = result.iconSize + 6;
501 result.widgetHeight = result.iconSize + 2;
505QIcon QLineEditPrivate::clearButtonIcon()
const
507 Q_Q(
const QLineEdit);
508 QStyleOptionFrame styleOption;
509 q->initStyleOption(&styleOption);
510 return q->style()->standardIcon(QStyle::SP_LineEditClearButton, &styleOption, q);
513void QLineEditPrivate::setClearButtonEnabled(
bool enabled)
516 for (
const SideWidgetEntry &e : trailingSideWidgets) {
517 if (e.flags & SideWidgetClearButton) {
518 e.action->setEnabled(enabled);
527void QLineEditPrivate::positionSideWidgets()
530 if (hasSideWidgets()) {
531 const QRect contentRect = q->rect();
532 const SideWidgetParameters p = sideWidgetParameters();
533 const int delta = p.margin + p.widgetWidth;
534 QRect widgetGeometry(QPoint(p.margin, (contentRect.height() - p.widgetHeight) / 2),
535 QSize(p.widgetWidth, p.widgetHeight));
536 for (
const SideWidgetEntry &e : leftSideWidgetList()) {
537 e.widget->setGeometry(widgetGeometry);
539 if (e.action->isVisible())
540 widgetGeometry.moveLeft(widgetGeometry.left() + delta);
545 widgetGeometry.moveLeft(contentRect.width() - p.widgetWidth - p.margin);
546 for (
const SideWidgetEntry &e : rightSideWidgetList()) {
547 e.widget->setGeometry(widgetGeometry);
549 if (e.action->isVisible())
550 widgetGeometry.moveLeft(widgetGeometry.left() - delta);
557QLineEditPrivate::SideWidgetLocation QLineEditPrivate::findSideWidget(
const QAction *a)
const
560 for (
const auto &e : leadingSideWidgets) {
562 return {QLineEdit::LeadingPosition, i};
566 for (
const auto &e : trailingSideWidgets) {
568 return {QLineEdit::TrailingPosition, i};
571 return {QLineEdit::LeadingPosition, -1};
574QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition position,
int flags)
579 if (!hasSideWidgets()) {
580 QObjectPrivate::connect(q, &QLineEdit::textChanged,
581 this, &QLineEditPrivate::textChanged);
582 lastTextSize = q->text().size();
584 QWidget *w =
nullptr;
587 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(newAction)) {
588 if ((w = widgetAction->requestWidget(q)))
589 flags |= SideWidgetCreatedByWidgetAction;
592#if QT_CONFIG(toolbutton)
593 QLineEditIconButton *toolButton =
new QLineEditIconButton(q);
594 toolButton->setIcon(newAction->icon());
595 toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0);
596 if (flags & SideWidgetClearButton) {
597 QObjectPrivate::connect(toolButton, &QToolButton::clicked,
598 this, &QLineEditPrivate::clearButtonClicked);
600#if QT_CONFIG(animation)
603 toolButton->setHideWithText(
true);
606 toolButton->setDefaultAction(newAction);
614 if (!before && !(flags & SideWidgetClearButton) && position == QLineEdit::TrailingPosition) {
615 for (
const SideWidgetEntry &e : trailingSideWidgets) {
616 if (e.flags & SideWidgetClearButton) {
632 const SideWidgetLocation loc = {position, -1};
633 const auto location = before ? findSideWidget(before) : loc;
635 const auto location = before ? findSideWidget(before) : SideWidgetLocation{position, -1};
638 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
639 list.insert(location.isValid() ? list.begin() + location.index : list.end(),
640 SideWidgetEntry(w, newAction, flags));
641 positionSideWidgets();
646void QLineEditPrivate::removeAction(QAction *action)
649 const auto location = findSideWidget(action);
650 if (!location.isValid())
652 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
653 SideWidgetEntry entry = list[location.index];
654 list.erase(list.begin() + location.index);
655 if (entry.flags & SideWidgetCreatedByWidgetAction)
656 static_cast<QWidgetAction *>(entry.action)->releaseWidget(entry.widget);
659 positionSideWidgets();
660 if (!hasSideWidgets())
661 QObjectPrivate::connect(q, &QLineEdit::textChanged,
662 this, &QLineEditPrivate::textChanged);
668 const QLineEditPrivate::SideWidgetParameters ¶meters)
671 return defaultMargin;
673 const auto visibleSideWidgetCount =
std::count_if(widgets.begin(), widgets.end(),
674 [](
const QLineEditPrivate::SideWidgetEntry &e) {
675#if QT_CONFIG(toolbutton) && QT_CONFIG(animation)
677 if (
auto* iconButton = qobject_cast<QLineEditIconButton*>(e.widget))
678 return iconButton->needsSpace();
681 return e.widget->isVisibleTo(e.widget->parentWidget());
684 return defaultMargin + (parameters.margin + parameters.widgetWidth) * visibleSideWidgetCount;
687QMargins QLineEditPrivate::effectiveTextMargins()
const
689 return {effectiveTextMargin(textMargins.left(), leftSideWidgetList(), sideWidgetParameters()),
691 effectiveTextMargin(textMargins.right(), rightSideWidgetList(), sideWidgetParameters()),
692 textMargins.bottom()};
698#include "moc_qlineedit_p.cpp"
Combined button and popup list for selecting options.
static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets, const QLineEditPrivate::SideWidgetParameters ¶meters)