9#if QT_CONFIG(itemviews)
10#include "qabstractitemview.h"
12#if QT_CONFIG(draganddrop)
16# include "qwidgetaction.h"
19#if QT_CONFIG(accessibility)
20#include "qaccessible.h"
27#if QT_CONFIG(animation)
28#include <qpropertyanimation.h>
30#include <qstylehints.h>
31#include <qvalidator.h>
35const int QLineEditPrivate::verticalMargin(1);
36const int QLineEditPrivate::horizontalMargin(2);
39QRect QLineEditPrivate::adjustedControlRect(
const QRect &rect)
const
41 QRect widgetRect = !rect.isEmpty() ? rect : q_func()->rect();
42 QRect cr = adjustedContentsRect();
43 int cix = cr.x() - hscroll + horizontalMargin;
44 return widgetRect.translated(QPoint(cix, vscroll - control->ascent() + q_func()->fontMetrics().ascent()));
47int QLineEditPrivate::xToPos(
int x, QTextLine::CursorPosition betweenOrOn)
const
49 QRect cr = adjustedContentsRect();
50 x-= cr.x() - hscroll + horizontalMargin;
51 return control->xToPos(x, betweenOrOn);
54QString QLineEditPrivate::textBeforeCursor(
int curPos)
const
56 const QString &text = control->text();
57 return text.mid(0, curPos);
60QString QLineEditPrivate::textAfterCursor(
int curPos)
const
62 const QString &text = control->text();
63 return text.mid(curPos);
66bool QLineEditPrivate::inSelection(
int x)
const
68 x -= adjustedContentsRect().x() - hscroll + horizontalMargin;
69 return control->inSelection(x);
72QRect QLineEditPrivate::cursorRect()
const
74 return adjustedControlRect(control->cursorRect());
77#if QT_CONFIG(completer)
78void QLineEditPrivate::connectCompleter()
81 QObject::connect(control->completer(), qOverload<
const QString &>(&QCompleter::activated),
82 q, &QLineEdit::setText);
83 QObjectPrivate::connect(control->completer(), qOverload<
const QString &>(&QCompleter::highlighted),
84 this, &QLineEditPrivate::completionHighlighted);
87void QLineEditPrivate::disconnectCompleter()
90 QObject::disconnect(control->completer(), qOverload<
const QString &>(&QCompleter::activated),
91 q, &QLineEdit::setText);
92 QObjectPrivate::disconnect(control->completer(), qOverload<
const QString &>(&QCompleter::highlighted),
93 this, &QLineEditPrivate::completionHighlighted);
96void QLineEditPrivate::completionHighlighted(
const QString &newText)
99 if (control->completer()->completionMode() != QCompleter::InlineCompletion) {
102 int c = control->cursor();
103 QString text = control->text();
104 q->setText(QStringView{text}.left(c) + QStringView{newText}.mid(c));
105 control->moveCursor(control->end(),
false);
107 const bool mark =
true;
109 const bool mark = (imHints & Qt::ImhNoPredictiveText);
111 control->moveCursor(c, mark);
117void QLineEditPrivate::handleWindowActivate()
120 if (!q->hasFocus() && control->hasSelectedText())
124void QLineEditPrivate::textEdited(
const QString &text)
128 emit q->textEdited(text);
129#if QT_CONFIG(completer)
130 if (control->completer()
131 && control->completer()->completionMode() != QCompleter::InlineCompletion)
132 control->complete(-1);
136void QLineEditPrivate::cursorPositionChanged(
int from,
int to)
140 emit q->cursorPositionChanged(from, to);
143#ifdef QT_KEYPAD_NAVIGATION
144void QLineEditPrivate::editFocusChange(
bool e)
151void QLineEditPrivate::selectionChanged()
154 if (control->preeditAreaText().isEmpty()) {
155 QStyleOptionFrame opt;
156 q->initStyleOption(&opt);
157 bool showCursor = control->hasSelectedText() ?
158 q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q):
160 setCursorVisible(showCursor);
163 emit q->selectionChanged();
164#if QT_CONFIG(accessibility)
165 QAccessibleTextSelectionEvent ev(q, control->selectionStart(), control->selectionEnd());
166 ev.setCursorPosition(control->cursorPosition());
167 QAccessible::updateAccessibility(&ev);
171void QLineEditPrivate::updateNeeded(
const QRect &rect)
173 q_func()->update(adjustedControlRect(rect));
176void QLineEditPrivate::init(
const QString& txt)
180 const auto qUpdateMicroFocus = [q]()
182 q->updateMicroFocus();
184 control =
new QWidgetLineControl(txt);
185 control->setParent(q);
186 control->setFont(q->font());
187 QObject::connect(control, &QWidgetLineControl::textChanged,
188 q, &QLineEdit::textChanged);
189 QObjectPrivate::connect(control, &QWidgetLineControl::textEdited,
190 this, &QLineEditPrivate::textEdited);
191 QObjectPrivate::connect(control, &QWidgetLineControl::cursorPositionChanged,
192 this, &QLineEditPrivate::cursorPositionChanged);
193 QObjectPrivate::connect(control, &QWidgetLineControl::selectionChanged,
194 this, &QLineEditPrivate::selectionChanged);
195 QObjectPrivate::connect(control, &QWidgetLineControl::editingFinished,
196 this, &QLineEditPrivate::controlEditingFinished);
197#ifdef QT_KEYPAD_NAVIGATION
198 QObject::connect(control, &QWidgetLineControl::editFocusChange,
199 this, &QLineEditPrivate::editFocusChange);
201 QObject::connect(control, &QWidgetLineControl::cursorPositionChanged,
202 q, qUpdateMicroFocus);
204 QObject::connect(control, &QWidgetLineControl::textChanged,
205 q, qUpdateMicroFocus);
207 QObject::connect(control, &QWidgetLineControl::updateMicroFocus,
208 q, qUpdateMicroFocus);
211 QObject::connect(control, &QWidgetLineControl::selectionChanged,
212 q, qOverload<>(&QLineEdit::update));
214 QObject::connect(control, &QWidgetLineControl::selectionChanged,
215 q, qUpdateMicroFocus);
217 QObject::connect(control, &QWidgetLineControl::displayTextChanged,
218 q, qOverload<>(&QLineEdit::update));
220 QObjectPrivate::connect(control, &QWidgetLineControl::updateNeeded,
221 this, &QLineEditPrivate::updateNeeded);
222 QObject::connect(control, &QWidgetLineControl::inputRejected,
223 q, &QLineEdit::inputRejected);
225 QStyleOptionFrame opt;
226 q->initStyleOption(&opt);
227 control->setPasswordCharacter(
char16_t(q->style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt, q)));
228 control->setPasswordMaskDelay(q->style()->styleHint(QStyle::SH_LineEdit_PasswordMaskDelay, &opt, q));
230 q->setCursor(Qt::IBeamCursor);
232 q->setFocusPolicy(Qt::StrongFocus);
233 q->setAttribute(Qt::WA_InputMethodEnabled);
236 q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit));
237 q->setBackgroundRole(QPalette::Base);
238 q->setAttribute(Qt::WA_KeyCompression);
239 q->setMouseTracking(
true);
240 q->setAcceptDrops(
true);
242 q->setAttribute(Qt::WA_MacShowFocusRect);
244 initMouseYThreshold();
247void QLineEditPrivate::initMouseYThreshold()
249 mouseYThreshold = QGuiApplication::styleHints()->mouseQuickSelectionThreshold();
252QRect QLineEditPrivate::adjustedContentsRect()
const
254 Q_Q(
const QLineEdit);
255 QStyleOptionFrame opt;
256 q->initStyleOption(&opt);
257 QRect r = q->style()->subElementRect(QStyle::SE_LineEditContents, &opt, q);
258 r = r.marginsRemoved(effectiveTextMargins());
262void QLineEditPrivate::setCursorVisible(
bool visible)
265 if ((
bool)cursorVisible == visible)
267 cursorVisible = visible;
268 if (control->inputMask().isEmpty())
269 q->update(cursorRect());
274void QLineEditPrivate::setText(
const QString& text)
277 control->setText(text);
280void QLineEditPrivate::updatePasswordEchoEditing(
bool editing)
283 control->updatePasswordEchoEditing(editing);
284 q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod());
287void QLineEditPrivate::resetInputMethod()
290 if (q->hasFocus() && qApp) {
291 QGuiApplication::inputMethod()->reset();
296
297
298
299
300bool QLineEditPrivate::sendMouseEventToInputContext( QMouseEvent *e )
303 if ( control->composeMode() ) {
304 int tmp_cursor = xToPos(e->position().toPoint().x());
305 int mousePos = tmp_cursor - control->cursor();
306 if ( mousePos < 0 || mousePos > control->preeditAreaText().size() )
310 if (e->type() == QEvent::MouseButtonRelease)
311 QGuiApplication::inputMethod()->invokeAction(QInputMethod::Click, mousePos);
323#if QT_CONFIG(draganddrop)
324void QLineEditPrivate::drag()
328 QMimeData *data =
new QMimeData;
329 data->setText(control->selectedText());
330 QDrag *drag =
new QDrag(q);
331 drag->setMimeData(data);
332 Qt::DropAction action = drag->exec(Qt::CopyAction);
333 if (action == Qt::MoveAction && !control->isReadOnly() && drag->target() != q)
334 control->removeSelection();
339#if QT_CONFIG(toolbutton)
340QLineEditIconButton::QLineEditIconButton(QWidget *parent)
341 : QToolButton(parent)
344 setFocusPolicy(Qt::NoFocus);
347QLineEditPrivate *QLineEditIconButton::lineEditPrivate()
const
349 QLineEdit *le = qobject_cast<QLineEdit *>(parentWidget());
350 return le ?
static_cast<QLineEditPrivate *>(qt_widget_private(le)) :
nullptr;
353void QLineEditIconButton::paintEvent(QPaintEvent *)
355 QPainter painter(
this);
356 QIcon::Mode state = QIcon::Disabled;
358 state = isDown() ? QIcon::Active : QIcon::Normal;
359 const QLineEditPrivate *lep = lineEditPrivate();
360 const int iconWidth = lep ? lep->sideWidgetParameters().iconSize : 16;
361 const QSize iconSize(iconWidth, iconWidth);
362 const QPixmap iconPixmap = icon().pixmap(iconSize, devicePixelRatio(), state, QIcon::Off);
363 QRect pixmapRect = QRect(QPoint(0, 0), iconSize);
364 pixmapRect.moveCenter(rect().center());
365 painter.setOpacity(m_opacity);
366 painter.drawPixmap(pixmapRect, iconPixmap);
369void QLineEditIconButton::actionEvent(QActionEvent *e)
372 case QEvent::ActionChanged: {
373 const auto *action = e->action();
374 if (isVisibleTo(parentWidget()) != action->isVisible()) {
375 setVisible(action->isVisible());
376 if (QLineEditPrivate *lep = lineEditPrivate())
377 lep->positionSideWidgets();
384 QToolButton::actionEvent(e);
387void QLineEditIconButton::setOpacity(qreal value)
389 if (!qFuzzyCompare(m_opacity, value)) {
396#if QT_CONFIG(animation)
397bool QLineEditIconButton::shouldHideWithText()
const
399 return m_hideWithText;
402void QLineEditIconButton::setHideWithText(
bool hide)
404 m_hideWithText = hide;
407void QLineEditIconButton::onAnimationFinished()
409 if (shouldHideWithText() && isVisible() && m_fadingOut) {
414 if (
auto le = lineEditPrivate())
415 le->updateGeometry_helper(
true);
419void QLineEditIconButton::animateShow(
bool visible)
421 m_fadingOut = !visible;
423 if (shouldHideWithText() && !isVisible()) {
427 if (
auto le = lineEditPrivate())
428 le->updateGeometry_helper(
true);
431 startOpacityAnimation(visible ? 1.0 : 0.0);
434void QLineEditIconButton::startOpacityAnimation(qreal endValue)
436 QPropertyAnimation *animation =
new QPropertyAnimation(
this, QByteArrayLiteral(
"opacity"),
this);
437 connect(animation, &QPropertyAnimation::finished,
this, &QLineEditIconButton::onAnimationFinished);
439 animation->setDuration(160);
440 animation->setEndValue(endValue);
441 animation->start(QAbstractAnimation::DeleteWhenStopped);
445void QLineEditIconButton::updateCursor()
448 setCursor(qFuzzyCompare(m_opacity, qreal(1.0)) || !parentWidget() ? QCursor(Qt::ArrowCursor) : parentWidget()->cursor());
453#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
454static void displayWidgets(
const QLineEditPrivate::SideWidgetEntryList &widgets,
bool display)
456 for (
const auto &e : widgets) {
457 if (e.flags & QLineEditPrivate::SideWidgetFadeInWithText)
458 static_cast<QLineEditIconButton *>(e.widget)->animateShow(display);
463void QLineEditPrivate::textChanged(
const QString &text)
465 if (hasSideWidgets()) {
466 const int newTextSize = text.size();
467 if (!newTextSize || !lastTextSize) {
468 lastTextSize = newTextSize;
469#if QT_CONFIG(animation) && QT_CONFIG(toolbutton)
470 const bool display = newTextSize > 0;
471 displayWidgets(leadingSideWidgets, display);
472 displayWidgets(trailingSideWidgets, display);
478void QLineEditPrivate::clearButtonClicked()
481 if (!q->text().isEmpty()) {
483 textEdited(QString());
487void QLineEditPrivate::controlEditingFinished()
491 emit q->returnPressed();
492 emit q->editingFinished();
495QLineEditPrivate::SideWidgetParameters QLineEditPrivate::sideWidgetParameters()
const
497 Q_Q(
const QLineEdit);
498 SideWidgetParameters result;
499 result.iconSize = q->style()->pixelMetric(QStyle::PM_LineEditIconSize,
nullptr, q);
500 result.margin = q->style()->pixelMetric(QStyle::PM_LineEditIconMargin,
nullptr, q);
501 result.widgetWidth = result.iconSize + 6;
502 result.widgetHeight = result.iconSize + 2;
506QIcon QLineEditPrivate::clearButtonIcon()
const
508 Q_Q(
const QLineEdit);
509 QStyleOptionFrame styleOption;
510 q->initStyleOption(&styleOption);
511 return q->style()->standardIcon(QStyle::SP_LineEditClearButton, &styleOption, q);
514void QLineEditPrivate::setClearButtonEnabled(
bool enabled)
517 for (
const SideWidgetEntry &e : trailingSideWidgets) {
518 if (e.flags & SideWidgetClearButton) {
519 e.action->setEnabled(enabled);
528void QLineEditPrivate::positionSideWidgets()
531 if (hasSideWidgets()) {
532 const QRect contentRect = q->rect();
533 const SideWidgetParameters p = sideWidgetParameters();
534 const int delta = p.margin + p.widgetWidth;
535 QRect widgetGeometry(QPoint(p.margin, (contentRect.height() - p.widgetHeight) / 2),
536 QSize(p.widgetWidth, p.widgetHeight));
537 for (
const SideWidgetEntry &e : leftSideWidgetList()) {
538 e.widget->setGeometry(widgetGeometry);
540 if (e.action->isVisible())
541 widgetGeometry.moveLeft(widgetGeometry.left() + delta);
546 widgetGeometry.moveLeft(contentRect.width() - p.widgetWidth - p.margin);
547 for (
const SideWidgetEntry &e : rightSideWidgetList()) {
548 e.widget->setGeometry(widgetGeometry);
550 if (e.action->isVisible())
551 widgetGeometry.moveLeft(widgetGeometry.left() - delta);
558QLineEditPrivate::SideWidgetLocation QLineEditPrivate::findSideWidget(
const QAction *a)
const
561 for (
const auto &e : leadingSideWidgets) {
563 return {QLineEdit::LeadingPosition, i};
567 for (
const auto &e : trailingSideWidgets) {
569 return {QLineEdit::TrailingPosition, i};
572 return {QLineEdit::LeadingPosition, -1};
575QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineEdit::ActionPosition position,
int flags)
580 if (!hasSideWidgets()) {
581 QObjectPrivate::connect(q, &QLineEdit::textChanged,
582 this, &QLineEditPrivate::textChanged);
583 lastTextSize = q->text().size();
585 QWidget *w =
nullptr;
588 if (QWidgetAction *widgetAction = qobject_cast<QWidgetAction *>(newAction)) {
589 if ((w = widgetAction->requestWidget(q)))
590 flags |= SideWidgetCreatedByWidgetAction;
593#if QT_CONFIG(toolbutton)
594 QLineEditIconButton *toolButton =
new QLineEditIconButton(q);
595 toolButton->setIcon(newAction->icon());
596 toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0);
597 if (flags & SideWidgetClearButton) {
598 QObjectPrivate::connect(toolButton, &QToolButton::clicked,
599 this, &QLineEditPrivate::clearButtonClicked);
601#if QT_CONFIG(animation)
604 toolButton->setHideWithText(
true);
607 toolButton->setDefaultAction(newAction);
615 if (!before && !(flags & SideWidgetClearButton) && position == QLineEdit::TrailingPosition) {
616 for (
const SideWidgetEntry &e : trailingSideWidgets) {
617 if (e.flags & SideWidgetClearButton) {
633 const SideWidgetLocation loc = {position, -1};
634 const auto location = before ? findSideWidget(before) : loc;
636 const auto location = before ? findSideWidget(before) : SideWidgetLocation{position, -1};
639 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
640 list.insert(location.isValid() ? list.begin() + location.index : list.end(),
641 SideWidgetEntry(w, newAction, flags));
642 positionSideWidgets();
647void QLineEditPrivate::removeAction(QAction *action)
650 const auto location = findSideWidget(action);
651 if (!location.isValid())
653 SideWidgetEntryList &list = location.position == QLineEdit::TrailingPosition ? trailingSideWidgets : leadingSideWidgets;
654 SideWidgetEntry entry = list[location.index];
655 list.erase(list.begin() + location.index);
656 if (entry.flags & SideWidgetCreatedByWidgetAction) {
661 if (
const auto a = qobject_cast<QWidgetAction*>(entry.action))
662 a->releaseWidget(entry.widget);
666 positionSideWidgets();
667 if (!hasSideWidgets())
668 QObjectPrivate::connect(q, &QLineEdit::textChanged,
669 this, &QLineEditPrivate::textChanged);
675 const QLineEditPrivate::SideWidgetParameters ¶meters)
678 return defaultMargin;
680 const auto visibleSideWidgetCount =
std::count_if(widgets.begin(), widgets.end(),
681 [](
const QLineEditPrivate::SideWidgetEntry &e) {
682#if QT_CONFIG(toolbutton) && QT_CONFIG(animation)
684 if (
auto* iconButton = qobject_cast<QLineEditIconButton*>(e.widget))
685 return iconButton->needsSpace();
688 return e.widget->isVisibleTo(e.widget->parentWidget());
691 return defaultMargin + (parameters.margin + parameters.widgetWidth) * visibleSideWidgetCount;
694QMargins QLineEditPrivate::effectiveTextMargins()
const
696 return {effectiveTextMargin(textMargins.left(), leftSideWidgetList(), sideWidgetParameters()),
698 effectiveTextMargin(textMargins.right(), rightSideWidgetList(), sideWidgetParameters()),
699 textMargins.bottom()};
705#include "moc_qlineedit_p.cpp"
static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets, const QLineEditPrivate::SideWidgetParameters ¶meters)