f31522130f
Build system (5 gaps hardened): - COOKBOOK_OFFLINE defaults to true (fork-mode) - normalize_patch handles diff -ruN format - New 'repo validate-patches' command (25/25 relibc patches) - 14 patched Qt/Wayland/display recipes added to protected list - relibc archive regenerated with current patch chain Boot fixes (fixable): - Full ISO EFI partition: 16 MiB → 1 MiB (matches mini, BIOS hardcoded 2 MiB offset) - D-Bus system bus: absolute /usr/bin/dbus-daemon path (was skipped) - redbear-sessiond: absolute /usr/bin/redbear-sessiond path (was skipped) - daemon framework: silenced spurious INIT_NOTIFY warnings for oneshot_async services (P0-daemon-silence-init-notify.patch) - udev-shim: demoted INIT_NOTIFY warning to INFO (expected for oneshot_async) - relibc: comprehensive named semaphores (sem_open/close/unlink) replacing upstream todo!() stubs - greeterd: Wayland socket timeout 15s → 30s (compositor DRM wait) - greeter-ui: built and linked (header guard unification, sem_compat stubs removed) - mc: un-ignored in both configs, fixed glib/libiconv/pcre2 transitive deps - greeter config: removed stale keymapd dependency from display/greeter services - prefix toolchain: relibc headers synced, _RELIBC_STDLIB_H guard unified Unfixable (diagnosed, upstream): - i2c-hidd: abort on no-I2C-hardware (QEMU) — process::exit → relibc abort - kded6/greeter-ui: page fault 0x8 — Qt library null deref - Thread panics fd != -1 — Rust std library on Redox - DHCP timeout / eth0 MAC — QEMU user-mode networking - hwrngd/thermald — no hardware RNG/thermal in VM - live preload allocation — BIOS memory fragmentation, continues on demand
1279 lines
37 KiB
C++
1279 lines
37 KiB
C++
// Copyright (C) 2025 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
|
// Qt-Security score:significant reason:default
|
|
|
|
#include "qquicksearchfield_p.h"
|
|
#include "qquickcontrol_p_p.h"
|
|
#include <private/qquickindicatorbutton_p.h>
|
|
#include <QtQuickTemplates2/private/qquicktextfield_p.h>
|
|
#include "qquickpopup_p_p.h"
|
|
#include "qquickdeferredexecute_p_p.h"
|
|
#include <private/qqmldelegatemodel_p.h>
|
|
#include "qquickabstractbutton_p.h"
|
|
#include "qquickabstractbutton_p_p.h"
|
|
#include <QtQml/qqmlcomponent.h>
|
|
#include <QtQuick/private/qquickaccessibleattached_p.h>
|
|
#if QT_CONFIG(quick_itemview)
|
|
# include <QtQuick/private/qquickitemview_p.h>
|
|
#endif
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
/*!
|
|
\qmltype SearchField
|
|
\inherits Control
|
|
//! \nativetype QQuickSearchField
|
|
\inqmlmodule QtQuick.Controls
|
|
\since 6.10
|
|
\ingroup qtquickcontrols-input
|
|
\ingroup qtquickcontrols-focusscopes
|
|
\brief A specialized input field designed to use for search functionality.
|
|
|
|
SearchField is a specialized input field designed to use for search functionality.
|
|
The control includes a text field, search and clear icons, and a popup that
|
|
displays suggestions or search results.
|
|
|
|
\note The iOS style does not provide a built-in popup for SearchField in
|
|
order to preserve the native look and feel. If a popup is still wanted,
|
|
it has to be defined by the user.
|
|
|
|
\image qtquickcontrols-searchfield.gif
|
|
{Search field with search icon and clear button}
|
|
|
|
\section1 SearchField's Indicators
|
|
|
|
SearchField provides two optional embedded indicator buttons: \l searchIndicator and
|
|
\l clearIndicator.
|
|
|
|
These are not indicators in the sense of \l BusyIndicator or \l ProgressBar. Instead,
|
|
they are interactive controls embedded into the field (similar to the up/down buttons
|
|
in \l SpinBox). Pressing \l searchIndicator triggers \l searchButtonPressed(), and pressing
|
|
\l clearIndicator triggers \l clearButtonPressed().
|
|
|
|
In addition to exposing the actions, the indicator buttons provide interaction state
|
|
(pressed/hovered/focused, etc.) that can be used by styles.
|
|
|
|
\section2 Customizing indicator content
|
|
|
|
The \l searchIndicator and \l clearIndicator properties are read-only. Customization is
|
|
supported through their internal properties.
|
|
|
|
In particular, the button's visual content is provided by its \c indicator item, which is
|
|
writable. This allows the default content to be replaced or removed entirely.
|
|
|
|
For example, to remove both indicator icons:
|
|
|
|
\code
|
|
SearchField {
|
|
searchIndicator.indicator: null
|
|
clearIndicator.indicator: null
|
|
}
|
|
\endcode
|
|
|
|
This is a supported customization scenario. Different SearchField variants may omit one
|
|
of the buttons (for example, providing only a search button) or replace the indicator
|
|
content with an alternative item (for example, a microphone icon to trigger speech input).
|
|
|
|
\sa searchIndicator, clearIndicator, searchButtonPressed(), clearButtonPressed()
|
|
|
|
\section1 SearchField Model Roles
|
|
|
|
SearchField is able to visualize standard \l {qml-data-models}{data models}
|
|
that provide the \c modelData role:
|
|
\list
|
|
\li models that have only one role
|
|
\li models that do not have named roles (JavaScript array, integer)
|
|
\endlist
|
|
|
|
When using models that have multiple named roles, SearchField must be configured
|
|
to use a specific \l {textRole}{text role} for its \l {text}{text}
|
|
and \l delegate instances.
|
|
|
|
\code
|
|
ListModel {
|
|
id : fruitModel
|
|
ListElement { name: "Apple"; color: "green" }
|
|
ListElement { name: "Cherry"; color: "red" }
|
|
ListElement { name: "Banana"; color: "yellow" }
|
|
ListElement { name: "Orange"; color: "orange" }
|
|
ListElement { name: "WaterMelon"; color: "pink" }
|
|
}
|
|
|
|
SortFilterProxyModel {
|
|
id: fruitFilter
|
|
model: fruitModel
|
|
sorters: [
|
|
RoleSorter {
|
|
roleName: "name"
|
|
}
|
|
]
|
|
filters: [
|
|
FunctionFilter {
|
|
component CustomData: QtObject { property string name }
|
|
property var regExp: new RegExp(fruitSearch.text, "i")
|
|
onRegExpChanged: invalidate()
|
|
function filter(data: CustomData): bool {
|
|
return regExp.test(data.name);
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
SearchField {
|
|
id: fruitSearch
|
|
suggestionModel: fruitFilter
|
|
textRole: "name"
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
}
|
|
\endcode
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::activated(int index)
|
|
|
|
This signal is emitted when the item at \a index is activated by the user.
|
|
|
|
An item is activated when it is selected while the popup is open,
|
|
causing the popup to close (and \l currentIndex to change).
|
|
The \l currentIndex property is set to \a index.
|
|
|
|
\sa currentIndex
|
|
*/
|
|
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::highlighted(int index)
|
|
|
|
This signal is emitted when the item at \a index in the popup list is highlighted by the user.
|
|
|
|
The highlighted signal is only emitted when the popup is open and an item
|
|
is highlighted, but not necessarily \l activated.
|
|
|
|
\sa highlightedIndex
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::accepted()
|
|
|
|
This signal is emitted when the user confirms their input by pressing
|
|
the Enter or Return key.
|
|
|
|
This signal is typically used to trigger a search or action based on
|
|
the final text input, and it indicates the user's intention to complete
|
|
or submit the query.
|
|
|
|
\sa searchTriggered()
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::searchTriggered()
|
|
|
|
This signal is emitted when a search action is initiated.
|
|
|
|
It occurs in two cases:
|
|
1. When the Enter or Return key is pressed, it will be emitted together
|
|
with accepted() signal
|
|
2. When the text is edited and if the \l live property is set to \c true,
|
|
this signal will be emitted.
|
|
|
|
This signal is ideal for initiating searches both on-demand and in real-time as
|
|
the user types, depending on the desired interaction model.
|
|
|
|
\sa accepted(), textEdited()
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::textEdited()
|
|
|
|
This signal is emitted every time the user modifies the text in the
|
|
search field, typically with each keystroke.
|
|
|
|
\sa searchTriggered()
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::searchButtonPressed()
|
|
|
|
This signal is emitted when the search button is pressed.
|
|
|
|
\sa clearButtonPressed()
|
|
*/
|
|
|
|
/*!
|
|
\qmlsignal void QtQuick.Controls::SearchField::clearButtonPressed()
|
|
|
|
This signal is emitted when the clear button is pressed.
|
|
|
|
\sa searchButtonPressed()
|
|
*/
|
|
|
|
namespace {
|
|
enum Activation { NoActivate, Activate };
|
|
enum Highlighting { NoHighlight, Highlight };
|
|
}
|
|
|
|
class QQuickSearchFieldPrivate : public QQuickControlPrivate
|
|
{
|
|
public:
|
|
Q_DECLARE_PUBLIC(QQuickSearchField)
|
|
|
|
bool isPopupVisible() const;
|
|
void showPopup();
|
|
void hidePopup(bool accept);
|
|
static void hideOldPopup(QQuickPopup *popup);
|
|
void popupVisibleChanged();
|
|
void popupDestroyed();
|
|
|
|
void itemClicked();
|
|
void itemHovered();
|
|
|
|
void createdItem(int index, QObject *object);
|
|
void suggestionCountChanged();
|
|
|
|
void increaseCurrentIndex();
|
|
void decreaseCurrentIndex();
|
|
void setCurrentIndex(int index);
|
|
void setCurrentItemAtIndex(int index, Activation activate);
|
|
void updateHighlightedIndex();
|
|
void setHighlightedIndex(int index, Highlighting highlight);
|
|
|
|
void createDelegateModel();
|
|
|
|
QString currentTextRole() const;
|
|
void selectAll();
|
|
void updateText();
|
|
void updateDisplayText();
|
|
QString textAt(int index) const;
|
|
bool isValidIndex(int index) const;
|
|
|
|
void cancelPopup();
|
|
void executePopup(bool complete = false);
|
|
|
|
bool handlePress(const QPointF &point, ulong timestamp) override;
|
|
bool handleRelease(const QPointF &point, ulong timestamp) override;
|
|
|
|
void startSearch();
|
|
void startClear();
|
|
|
|
void itemImplicitWidthChanged(QQuickItem *item) override;
|
|
void itemImplicitHeightChanged(QQuickItem *item) override;
|
|
void itemDestroyed(QQuickItem *item) override;
|
|
|
|
static inline QString popupName() { return QStringLiteral("popup"); }
|
|
|
|
QVariant suggestionModel;
|
|
bool hasCurrentIndex = false;
|
|
int highlightedIndex = -1;
|
|
int currentIndex = -1;
|
|
QString text;
|
|
QString textRole;
|
|
bool live = true;
|
|
bool searchPressed = false;
|
|
bool clearPressed = false;
|
|
bool searchFlat = false;
|
|
bool clearFlat = false;
|
|
bool searchDown = false;
|
|
bool clearDown = false;
|
|
bool hasSearchDown = false;
|
|
bool hasClearDown = false;
|
|
bool ownModel = false;
|
|
QQmlInstanceModel *delegateModel = nullptr;
|
|
QQmlComponent *delegate = nullptr;
|
|
QQuickIndicatorButton *searchIndicator = nullptr;
|
|
QQuickIndicatorButton *clearIndicator = nullptr;
|
|
QQuickDeferredPointer<QQuickPopup> popup;
|
|
};
|
|
|
|
bool QQuickSearchFieldPrivate::isPopupVisible() const
|
|
{
|
|
return popup && popup->isVisible();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::showPopup()
|
|
{
|
|
if (!popup)
|
|
executePopup(true);
|
|
|
|
if (popup && !popup->isVisible())
|
|
popup->open();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::hidePopup(bool accept)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (accept) {
|
|
setCurrentItemAtIndex(highlightedIndex, NoActivate);
|
|
// hiding the popup on user interaction should always emit activated,
|
|
// even if the current index didn't change
|
|
emit q->activated(highlightedIndex);
|
|
}
|
|
if (popup && popup->isVisible())
|
|
popup->close();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::hideOldPopup(QQuickPopup *popup)
|
|
{
|
|
if (!popup)
|
|
return;
|
|
|
|
qCDebug(lcItemManagement) << "hiding old popup" << popup;
|
|
|
|
popup->setVisible(false);
|
|
popup->setParentItem(nullptr);
|
|
#if QT_CONFIG(accessibility)
|
|
// Remove the item from the accessibility tree.
|
|
QQuickAccessibleAttached *accessible = accessibleAttached(popup);
|
|
if (accessible)
|
|
accessible->setIgnored(true);
|
|
#endif
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::popupVisibleChanged()
|
|
{
|
|
if (isPopupVisible())
|
|
QGuiApplication::inputMethod()->reset();
|
|
|
|
#if QT_CONFIG(quick_itemview)
|
|
QQuickItemView *itemView = popup->findChild<QQuickItemView *>();
|
|
if (itemView)
|
|
itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
|
|
#endif
|
|
|
|
updateHighlightedIndex();
|
|
|
|
#if QT_CONFIG(quick_itemview)
|
|
if (itemView)
|
|
itemView->positionViewAtIndex(highlightedIndex, QQuickItemView::Beginning);
|
|
#endif
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::popupDestroyed()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
popup = nullptr;
|
|
emit q->popupChanged();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::itemClicked()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
int index = delegateModel->indexOf(q->sender(), nullptr);
|
|
if (index != -1) {
|
|
setHighlightedIndex(index, Highlight);
|
|
hidePopup(true);
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::itemHovered()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
|
|
QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
|
|
if (!button || !button->isHovered() || !button->isEnabled()
|
|
|| QQuickAbstractButtonPrivate::get(button)->touchId != -1)
|
|
return;
|
|
|
|
int index = delegateModel->indexOf(button, nullptr);
|
|
if (index != -1) {
|
|
setHighlightedIndex(index, Highlight);
|
|
|
|
#if QT_CONFIG(quick_itemview)
|
|
if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
|
|
itemView->positionViewAtIndex(index, QQuickItemView::Contain);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::createdItem(int index, QObject *object)
|
|
{
|
|
Q_UNUSED(index);
|
|
Q_Q(QQuickSearchField);
|
|
QQuickItem *item = qobject_cast<QQuickItem *>(object);
|
|
if (item && !item->parentItem()) {
|
|
if (popup)
|
|
item->setParentItem(popup->contentItem());
|
|
else
|
|
item->setParentItem(q);
|
|
QQuickItemPrivate::get(item)->setCulled(true);
|
|
}
|
|
|
|
QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object);
|
|
if (button) {
|
|
button->setFocusPolicy(Qt::NoFocus);
|
|
connect(button, &QQuickAbstractButton::clicked, this,
|
|
&QQuickSearchFieldPrivate::itemClicked);
|
|
connect(button, &QQuickAbstractButton::hoveredChanged, this,
|
|
&QQuickSearchFieldPrivate::itemHovered);
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::suggestionCountChanged()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (q->suggestionCount() == 0)
|
|
setCurrentItemAtIndex(-1, NoActivate);
|
|
// If the suggestionModel has been updated and the current text matches an item in
|
|
// the model, update currentIndex and highlightedIndex to the index of that item.
|
|
if (!text.isEmpty()) {
|
|
for (int idx = 0; idx < q->suggestionCount(); ++idx) {
|
|
QString t = textAt(idx);
|
|
if (t == text) {
|
|
setCurrentItemAtIndex(idx, NoActivate);
|
|
updateHighlightedIndex();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
emit q->suggestionCountChanged();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::increaseCurrentIndex()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (isPopupVisible()) {
|
|
if (highlightedIndex < q->suggestionCount() - 1)
|
|
setHighlightedIndex(highlightedIndex + 1, Highlight);
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::decreaseCurrentIndex()
|
|
{
|
|
if (isPopupVisible()) {
|
|
if (highlightedIndex > 0)
|
|
setHighlightedIndex(highlightedIndex - 1, Highlight);
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::setCurrentIndex(int index)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (currentIndex == index)
|
|
return;
|
|
|
|
currentIndex = index;
|
|
emit q->currentIndexChanged();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::setCurrentItemAtIndex(int index, Activation activate)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (currentIndex == index)
|
|
return;
|
|
|
|
currentIndex = index;
|
|
emit q->currentIndexChanged();
|
|
|
|
updateDisplayText();
|
|
|
|
if (activate)
|
|
emit q->activated(index);
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::updateHighlightedIndex()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
int index = -1;
|
|
|
|
if (isPopupVisible()) {
|
|
if (currentIndex >= 0)
|
|
index = currentIndex;
|
|
else if (q->suggestionCount() > 0)
|
|
index = 0; // auto-highlight first suggestion
|
|
}
|
|
|
|
setHighlightedIndex(index, NoHighlight);
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::setHighlightedIndex(int index, Highlighting highlight)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (highlightedIndex == index)
|
|
return;
|
|
|
|
highlightedIndex = index;
|
|
emit q->highlightedIndexChanged();
|
|
|
|
if (highlight)
|
|
emit q->highlighted(index);
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::createDelegateModel()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
bool ownedOldModel = ownModel;
|
|
QQmlInstanceModel *oldModel = delegateModel;
|
|
|
|
if (oldModel) {
|
|
disconnect(delegateModel, &QQmlInstanceModel::countChanged, this,
|
|
&QQuickSearchFieldPrivate::suggestionCountChanged);
|
|
disconnect(delegateModel, &QQmlInstanceModel::createdItem, this,
|
|
&QQuickSearchFieldPrivate::createdItem);
|
|
}
|
|
|
|
ownModel = false;
|
|
delegateModel = suggestionModel.value<QQmlInstanceModel *>();
|
|
|
|
if (!delegateModel && suggestionModel.isValid()) {
|
|
QQmlDelegateModel *dataModel = new QQmlDelegateModel(qmlContext(q), q);
|
|
dataModel->setModel(suggestionModel);
|
|
dataModel->setDelegate(delegate);
|
|
if (q->isComponentComplete())
|
|
dataModel->componentComplete();
|
|
|
|
ownModel = true;
|
|
delegateModel = dataModel;
|
|
}
|
|
|
|
if (delegateModel) {
|
|
connect(delegateModel, &QQmlInstanceModel::countChanged, this,
|
|
&QQuickSearchFieldPrivate::suggestionCountChanged);
|
|
connect(delegateModel, &QQmlInstanceModel::createdItem, this,
|
|
&QQuickSearchFieldPrivate::createdItem);
|
|
}
|
|
|
|
emit q->delegateModelChanged();
|
|
|
|
if (ownedOldModel)
|
|
delete oldModel;
|
|
}
|
|
|
|
QString QQuickSearchFieldPrivate::currentTextRole() const
|
|
{
|
|
return textRole.isEmpty() ? QStringLiteral("modelData") : textRole;
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::selectAll()
|
|
{
|
|
QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
|
|
if (!input)
|
|
return;
|
|
input->selectAll();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::updateText()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
|
|
if (!input)
|
|
return;
|
|
|
|
const QString textInput = input->text();
|
|
|
|
if (text != textInput) {
|
|
q->setText(textInput);
|
|
emit q->textEdited();
|
|
|
|
setCurrentIndex(-1);
|
|
updateHighlightedIndex();
|
|
|
|
if (live)
|
|
emit q->searchTriggered();
|
|
}
|
|
|
|
if (text.isEmpty()) {
|
|
if (isPopupVisible())
|
|
hidePopup(false);
|
|
} else {
|
|
if (delegateModel && delegateModel->count() > 0) {
|
|
if (!isPopupVisible())
|
|
showPopup();
|
|
} else {
|
|
if (isPopupVisible())
|
|
hidePopup(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::updateDisplayText()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
const QString currentText = textAt(currentIndex);
|
|
|
|
if (text != currentText)
|
|
q->setText(currentText);
|
|
}
|
|
|
|
QString QQuickSearchFieldPrivate::textAt(int index) const
|
|
{
|
|
if (!isValidIndex(index))
|
|
return QString();
|
|
|
|
return delegateModel->stringValue(index, currentTextRole());
|
|
}
|
|
|
|
bool QQuickSearchFieldPrivate::isValidIndex(int index) const
|
|
{
|
|
return delegateModel && index >= 0 && index < delegateModel->count();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::cancelPopup()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
quickCancelDeferred(q, popupName());
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::executePopup(bool complete)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
if (popup.wasExecuted())
|
|
return;
|
|
|
|
if (!popup || complete)
|
|
quickBeginDeferred(q, popupName(), popup);
|
|
if (complete)
|
|
quickCompleteDeferred(q, popupName(), popup);
|
|
}
|
|
|
|
bool QQuickSearchFieldPrivate::handlePress(const QPointF &point, ulong timestamp)
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
QQuickControlPrivate::handlePress(point, timestamp);
|
|
|
|
QQuickItem *si = searchIndicator->indicator();
|
|
QQuickItem *ci = clearIndicator->indicator();
|
|
const bool isSearch = si && si->isEnabled() && si->contains(q->mapToItem(si, point));
|
|
const bool isClear = ci && ci->isEnabled() && ci->contains(q->mapToItem(ci, point));
|
|
|
|
if (isSearch) {
|
|
searchIndicator->setPressed(true);
|
|
startSearch();
|
|
} else if (isClear) {
|
|
clearIndicator->setPressed(true);
|
|
startClear();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool QQuickSearchFieldPrivate::handleRelease(const QPointF &point, ulong timestamp)
|
|
{
|
|
QQuickControlPrivate::handleRelease(point, timestamp);
|
|
if (searchIndicator->isPressed())
|
|
searchIndicator->setPressed(false);
|
|
else if (clearIndicator->isPressed())
|
|
clearIndicator->setPressed(false);
|
|
return true;
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::startSearch()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
|
|
QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
|
|
if (!input)
|
|
return;
|
|
|
|
input->forceActiveFocus();
|
|
emit q->searchButtonPressed();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::startClear()
|
|
{
|
|
Q_Q(QQuickSearchField);
|
|
|
|
if (text.isEmpty())
|
|
return;
|
|
|
|
// if text is not null then clear text, also reset highlightedIndex and currentIndex
|
|
if (!text.isEmpty()) {
|
|
setCurrentIndex(-1);
|
|
updateHighlightedIndex();
|
|
q->setText(QString());
|
|
|
|
if (isPopupVisible())
|
|
hidePopup(false);
|
|
|
|
emit q->clearButtonPressed();
|
|
}
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::itemImplicitWidthChanged(QQuickItem *item)
|
|
{
|
|
QQuickControlPrivate::itemImplicitWidthChanged(item);
|
|
if (item == searchIndicator->indicator())
|
|
emit searchIndicator->implicitIndicatorWidthChanged();
|
|
if (item == clearIndicator->indicator())
|
|
emit clearIndicator->implicitIndicatorWidthChanged();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::itemImplicitHeightChanged(QQuickItem *item)
|
|
{
|
|
QQuickControlPrivate::itemImplicitHeightChanged(item);
|
|
if (item == searchIndicator->indicator())
|
|
emit searchIndicator->implicitIndicatorHeightChanged();
|
|
if (item == clearIndicator->indicator())
|
|
emit clearIndicator->implicitIndicatorHeightChanged();
|
|
}
|
|
|
|
void QQuickSearchFieldPrivate::itemDestroyed(QQuickItem *item)
|
|
{
|
|
QQuickControlPrivate::itemDestroyed(item);
|
|
if (item == searchIndicator->indicator())
|
|
searchIndicator->setIndicator(nullptr);
|
|
if (item == clearIndicator->indicator())
|
|
clearIndicator->setIndicator(nullptr);
|
|
}
|
|
|
|
QQuickSearchField::QQuickSearchField(QQuickItem *parent)
|
|
: QQuickControl(*(new QQuickSearchFieldPrivate), parent)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
d->searchIndicator = new QQuickIndicatorButton(this);
|
|
d->clearIndicator = new QQuickIndicatorButton(this);
|
|
|
|
setFocusPolicy(Qt::StrongFocus);
|
|
setFlag(QQuickItem::ItemIsFocusScope);
|
|
setAcceptedMouseButtons(Qt::LeftButton);
|
|
#if QT_CONFIG(cursor)
|
|
setCursor(Qt::ArrowCursor);
|
|
#endif
|
|
|
|
d->init();
|
|
}
|
|
|
|
QQuickSearchField::~QQuickSearchField()
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
d->removeImplicitSizeListener(d->searchIndicator->indicator());
|
|
d->removeImplicitSizeListener(d->clearIndicator->indicator());
|
|
|
|
if (d->popup) {
|
|
QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d,
|
|
&QQuickSearchFieldPrivate::popupVisibleChanged);
|
|
d->hideOldPopup(d->popup);
|
|
d->popup = nullptr;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty model QtQuick.Controls::SearchField::suggestionModel
|
|
|
|
This property holds the data model used to display search suggestions in the popup menu.
|
|
|
|
\code
|
|
SearchField {
|
|
textRole: "age"
|
|
suggestionModel: ListModel {
|
|
ListElement { name: "Karen"; age: "66" }
|
|
ListElement { name: "Jim"; age: "32" }
|
|
ListElement { name: "Pamela"; age: "28" }
|
|
}
|
|
}
|
|
\endcode
|
|
|
|
\sa textRole
|
|
*/
|
|
|
|
QVariant QQuickSearchField::suggestionModel() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->suggestionModel;
|
|
}
|
|
|
|
void QQuickSearchField::setSuggestionModel(const QVariant &model)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
|
|
QVariant suggestionModel = model;
|
|
if (suggestionModel.userType() == qMetaTypeId<QJSValue>())
|
|
suggestionModel = get<QJSValue>(std::move(suggestionModel)).toVariant();
|
|
|
|
if (d->suggestionModel == suggestionModel)
|
|
return;
|
|
|
|
d->suggestionModel = suggestionModel;
|
|
d->createDelegateModel();
|
|
emit suggestionCountChanged();
|
|
emit suggestionModelChanged();
|
|
}
|
|
|
|
/*!
|
|
\readonly
|
|
\qmlproperty model QtQuick.Controls::SearchField::delegateModel
|
|
|
|
This property holds the model that provides delegate instances for the search field.
|
|
|
|
It is typically assigned to a \l ListView in the \l {Popup::}{contentItem}
|
|
of the \l popup.
|
|
|
|
*/
|
|
QQmlInstanceModel *QQuickSearchField::delegateModel() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->delegateModel;
|
|
}
|
|
|
|
/*!
|
|
\readonly
|
|
\qmlproperty int QtQuick.Controls::SearchField::suggestionCount
|
|
|
|
This property holds the number of suggestions to display from the suggestion model.
|
|
*/
|
|
int QQuickSearchField::suggestionCount() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->delegateModel ? d->delegateModel->count() : 0;
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty int QtQuick.Controls::SearchField::currentIndex
|
|
|
|
This property holds the index of the currently selected suggestion in the popup list.
|
|
|
|
Its value is \c -1 when no suggestion is selected.
|
|
|
|
currentIndex is not modified automatically when the model changes or when the user types
|
|
or edits text. It is updated only when the user explicitly selects a suggestion, either
|
|
by clicking an item in the popup, or by pressing Enter on a highlighted item.
|
|
|
|
currentIndex can be set; for example, to display the first item in the model at startup.
|
|
Before doing so, ensure that the model is not empty:
|
|
|
|
\snippet qtquickcontrols-searchfield-currentIndex.qml currentIndex
|
|
|
|
\sa activated(), text, highlightedIndex
|
|
*/
|
|
int QQuickSearchField::currentIndex() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->currentIndex;
|
|
}
|
|
|
|
void QQuickSearchField::setCurrentIndex(int index)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
d->hasCurrentIndex = true;
|
|
d->setCurrentIndex(index);
|
|
}
|
|
|
|
/*!
|
|
\readonly
|
|
\qmlproperty int QtQuick.Controls::SearchField::highlightedIndex
|
|
|
|
This property holds the index of the currently highlighted item in
|
|
the popup list.
|
|
|
|
When the highlighted item is activated, the popup closes, \l currentIndex
|
|
is updated to match \c highlightedIndex, and this property is reset to
|
|
\c -1, indicating that no item is currently highlighted.
|
|
|
|
\sa highlighted(), currentIndex
|
|
*/
|
|
int QQuickSearchField::highlightedIndex() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->highlightedIndex;
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty string QtQuick.Controls::SearchField::text
|
|
|
|
This property holds the current input text in the search field.
|
|
|
|
Text is bound to the user input, triggering suggestion updates or search logic.
|
|
|
|
\sa searchTriggered(), textEdited()
|
|
*/
|
|
QString QQuickSearchField::text() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->text;
|
|
}
|
|
|
|
void QQuickSearchField::setText(const QString &text)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
if (d->text == text)
|
|
return;
|
|
|
|
d->text = text;
|
|
emit textChanged();
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty string QtQuick.Controls::SearchField::textRole
|
|
|
|
This property holds the model role used to display items in the suggestion model
|
|
shown in the popup list.
|
|
|
|
When the model has multiple roles, \c textRole can be set to determine
|
|
which role should be displayed.
|
|
*/
|
|
QString QQuickSearchField::textRole() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->textRole;
|
|
}
|
|
|
|
void QQuickSearchField::setTextRole(const QString &textRole)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
if (d->textRole == textRole)
|
|
return;
|
|
|
|
d->textRole = textRole;
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty bool QtQuick.Controls::SearchField::live
|
|
|
|
This property holds a boolean value that determines whether the search is triggered
|
|
on every text edit.
|
|
|
|
When set to \c true, the \l searchTriggered() signal is emitted on each text change,
|
|
allowing you to respond to every keystroke.
|
|
When set to \c false, the \l searchTriggered() is only emitted when the user presses
|
|
the Enter or Return key.
|
|
|
|
\sa searchTriggered()
|
|
*/
|
|
|
|
bool QQuickSearchField::isLive() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->live;
|
|
}
|
|
|
|
void QQuickSearchField::setLive(const bool live)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
|
|
if (d->live == live)
|
|
return;
|
|
|
|
d->live = live;
|
|
}
|
|
|
|
/*!
|
|
\include qquickindicatorbutton.qdocinc {properties} {SearchField} {searchIndicator}
|
|
|
|
This property holds the search indicator. Pressing it triggers
|
|
\l searchButtonPressed().
|
|
|
|
It is exposed so that styles and applications can customize it through its
|
|
internal properties (for example, replacing or removing the \c searchIndicator
|
|
via \c searchIndicator.indicator, or reacting to interaction state such as
|
|
pressed and hovered).
|
|
|
|
\sa {SearchField's Indicators}
|
|
*/
|
|
QQuickIndicatorButton *QQuickSearchField::searchIndicator() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->searchIndicator;
|
|
}
|
|
|
|
/*!
|
|
\include qquickindicatorbutton.qdocinc {properties} {SearchField} {clearIndicator}
|
|
|
|
This property holds the clear indicator. Pressing it triggers
|
|
\l clearButtonPressed().
|
|
|
|
It is exposed so that styles and applications can customize it through its
|
|
internal properties (for example, replacing or removing the \c clearIndicator
|
|
via \c clearIndicator.indicator, or reacting to interaction state such as
|
|
pressed and hovered).
|
|
|
|
\sa {SearchField's Indicators}
|
|
*/
|
|
QQuickIndicatorButton *QQuickSearchField::clearIndicator() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->clearIndicator;
|
|
}
|
|
|
|
|
|
/*!
|
|
\qmlproperty Popup QtQuick.Controls::SearchField::popup
|
|
|
|
This property holds the popup.
|
|
|
|
The popup can be opened or closed manually, if necessary:
|
|
|
|
\code
|
|
onSpecialEvent: searchField.popup.close()
|
|
\endcode
|
|
*/
|
|
QQuickPopup *QQuickSearchField::popup() const
|
|
{
|
|
QQuickSearchFieldPrivate *d = const_cast<QQuickSearchFieldPrivate *>(d_func());
|
|
if (!d->popup)
|
|
d->executePopup(isComponentComplete());
|
|
return d->popup;
|
|
}
|
|
|
|
void QQuickSearchField::setPopup(QQuickPopup *popup)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
if (d->popup == popup)
|
|
return;
|
|
|
|
if (!d->popup.isExecuting())
|
|
d->cancelPopup();
|
|
|
|
if (d->popup) {
|
|
QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::destroyed, d,
|
|
&QQuickSearchFieldPrivate::popupDestroyed);
|
|
QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d,
|
|
&QQuickSearchFieldPrivate::popupVisibleChanged);
|
|
QQuickSearchFieldPrivate::hideOldPopup(d->popup);
|
|
}
|
|
|
|
if (popup) {
|
|
QQuickPopupPrivate::get(popup)->allowVerticalFlip = true;
|
|
popup->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent);
|
|
QObjectPrivate::connect(popup, &QQuickPopup::visibleChanged, d,
|
|
&QQuickSearchFieldPrivate::popupVisibleChanged);
|
|
// QQuickPopup does not derive from QQuickItemChangeListener, so we cannot use
|
|
// QQuickItemChangeListener::itemDestroyed so we have to use QObject::destroyed
|
|
QObjectPrivate::connect(popup, &QQuickPopup::destroyed, d,
|
|
&QQuickSearchFieldPrivate::popupDestroyed);
|
|
|
|
#if QT_CONFIG(quick_itemview)
|
|
if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
|
|
itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
|
|
#endif
|
|
}
|
|
|
|
d->popup = popup;
|
|
if (!d->popup.isExecuting())
|
|
emit popupChanged();
|
|
}
|
|
|
|
/*!
|
|
\qmlproperty Component QtQuick.Controls::SearchField::delegate
|
|
|
|
This property holds a delegate that presents an item in the search field popup.
|
|
|
|
It is recommended to use \l ItemDelegate (or any other \l AbstractButton
|
|
derivatives) as the delegate. This ensures that the interaction works as
|
|
expected, and the popup will automatically close when appropriate. When
|
|
other types are used as the delegate, the popup must be closed manually.
|
|
For example, if \l MouseArea is used:
|
|
|
|
\code
|
|
delegate: Rectangle {
|
|
// ...
|
|
MouseArea {
|
|
// ...
|
|
onClicked: searchField.popup.close()
|
|
}
|
|
}
|
|
\endcode
|
|
|
|
\include delegate-ownership.qdocinc {no-ownership-since-6.11} {SearchField}
|
|
*/
|
|
QQmlComponent *QQuickSearchField::delegate() const
|
|
{
|
|
Q_D(const QQuickSearchField);
|
|
return d->delegate;
|
|
}
|
|
|
|
void QQuickSearchField::setDelegate(QQmlComponent *delegate)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
if (d->delegate == delegate)
|
|
return;
|
|
|
|
d->delegate = delegate;
|
|
QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel *>(d->delegateModel);
|
|
if (delegateModel)
|
|
delegateModel->setDelegate(d->delegate);
|
|
emit delegateChanged();
|
|
}
|
|
|
|
bool QQuickSearchField::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
|
|
switch (event->type()) {
|
|
case QEvent::MouseButtonRelease: {
|
|
QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem);
|
|
if (input->hasFocus()) {
|
|
if (!d->text.isEmpty() && !d->isPopupVisible() && (d->delegateModel && d->delegateModel->count() > 0))
|
|
d->showPopup();
|
|
}
|
|
break;
|
|
}
|
|
case QEvent::FocusOut: {
|
|
const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
|
|
const bool usingPopupWindows =
|
|
d->popup ? QQuickPopupPrivate::get(d->popup)->usePopupWindow() : false;
|
|
if (qGuiApp->focusObject() != this && !(hasActiveFocus && !usingPopupWindows))
|
|
d->hidePopup(false);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return QQuickControl::eventFilter(object, event);
|
|
}
|
|
|
|
void QQuickSearchField::focusInEvent(QFocusEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::focusInEvent(event);
|
|
|
|
if ((event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason
|
|
|| event->reason() == Qt::ShortcutFocusReason)
|
|
&& d->contentItem)
|
|
d->contentItem->forceActiveFocus(event->reason());
|
|
}
|
|
|
|
void QQuickSearchField::focusOutEvent(QFocusEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::focusOutEvent(event);
|
|
|
|
const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
|
|
const bool usingPopupWindows = d->popup && QQuickPopupPrivate::get(d->popup)->usePopupWindow();
|
|
|
|
if (qGuiApp->focusObject() != d->contentItem && !(hasActiveFocus && !usingPopupWindows))
|
|
d->hidePopup(false);
|
|
}
|
|
|
|
void QQuickSearchField::hoverEnterEvent(QHoverEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::hoverEnterEvent(event);
|
|
QQuickItem *si = d->searchIndicator->indicator();
|
|
QQuickItem *ci = d->clearIndicator->indicator();
|
|
d->searchIndicator->setHovered(si && si->isEnabled() && si->contains(mapToItem(si, event->position())));
|
|
d->clearIndicator->setHovered(ci && ci->isEnabled() && ci->contains(mapToItem(ci, event->position())));
|
|
event->ignore();
|
|
}
|
|
|
|
void QQuickSearchField::hoverMoveEvent(QHoverEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::hoverMoveEvent(event);
|
|
QQuickItem *si = d->searchIndicator->indicator();
|
|
QQuickItem *ci = d->clearIndicator->indicator();
|
|
d->searchIndicator->setHovered(si && si->isEnabled() && si->contains(mapToItem(si, event->position())));
|
|
d->clearIndicator->setHovered(ci && ci->isEnabled() && ci->contains(mapToItem(ci, event->position())));
|
|
event->ignore();
|
|
}
|
|
|
|
void QQuickSearchField::hoverLeaveEvent(QHoverEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::hoverLeaveEvent(event);
|
|
d->searchIndicator->setHovered(false);
|
|
d->clearIndicator->setHovered(false);
|
|
event->ignore();
|
|
}
|
|
|
|
void QQuickSearchField::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
|
|
const auto key = event->key();
|
|
|
|
if (!d->suggestionModel.isNull() && !d->text.isEmpty()) {
|
|
switch (key) {
|
|
case Qt::Key_Escape:
|
|
case Qt::Key_Back:
|
|
if (d->isPopupVisible()) {
|
|
d->hidePopup(false);
|
|
event->accept();
|
|
} else {
|
|
setText(QString());
|
|
}
|
|
break;
|
|
case Qt::Key_Return:
|
|
case Qt::Key_Enter:
|
|
if (d->isPopupVisible())
|
|
d->hidePopup(true);
|
|
emit accepted();
|
|
emit searchTriggered();
|
|
event->accept();
|
|
break;
|
|
case Qt::Key_Up:
|
|
d->decreaseCurrentIndex();
|
|
event->accept();
|
|
break;
|
|
case Qt::Key_Down:
|
|
d->increaseCurrentIndex();
|
|
event->accept();
|
|
break;
|
|
case Qt::Key_Home:
|
|
if (d->isPopupVisible())
|
|
d->setHighlightedIndex(0, Highlight);
|
|
event->accept();
|
|
break;
|
|
case Qt::Key_End:
|
|
if (d->isPopupVisible())
|
|
d->setHighlightedIndex(suggestionCount() - 1, Highlight);
|
|
event->accept();
|
|
break;
|
|
default:
|
|
QQuickControl::keyPressEvent(event);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void QQuickSearchField::classBegin()
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::classBegin();
|
|
|
|
QQmlContext *context = qmlContext(this);
|
|
if (context) {
|
|
QQmlEngine::setContextForObject(d->searchIndicator, context);
|
|
QQmlEngine::setContextForObject(d->clearIndicator, context);
|
|
}
|
|
}
|
|
|
|
void QQuickSearchField::componentComplete()
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickIndicatorButtonPrivate::get(d->searchIndicator)->executeIndicator(true);
|
|
QQuickIndicatorButtonPrivate::get(d->clearIndicator)->executeIndicator(true);
|
|
QQuickControl::componentComplete();
|
|
|
|
if (d->popup)
|
|
d->executePopup(true);
|
|
|
|
if (d->delegateModel && d->ownModel)
|
|
static_cast<QQmlDelegateModel *>(d->delegateModel)->componentComplete();
|
|
}
|
|
|
|
void QQuickSearchField::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
if (oldItem) {
|
|
oldItem->removeEventFilter(this);
|
|
if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem)) {
|
|
QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d,
|
|
&QQuickSearchFieldPrivate::updateText);
|
|
}
|
|
}
|
|
|
|
if (newItem) {
|
|
newItem->installEventFilter(this);
|
|
if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem)) {
|
|
QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d,
|
|
&QQuickSearchFieldPrivate::updateText);
|
|
}
|
|
#if QT_CONFIG(cursor)
|
|
newItem->setCursor(Qt::IBeamCursor);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void QQuickSearchField::itemChange(ItemChange change, const ItemChangeData &data)
|
|
{
|
|
Q_D(QQuickSearchField);
|
|
QQuickControl::itemChange(change, data);
|
|
if (change == ItemVisibleHasChanged && !data.boolValue) {
|
|
d->hidePopup(false);
|
|
d->setCurrentItemAtIndex(-1, NoActivate);
|
|
}
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
#include "moc_qquicksearchfield_p.cpp"
|