blob: fcf23db51d61dde1c89c17279be4447e8945871d [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL3$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPLv3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or later as published by the Free
** Software Foundation and appearing in the file LICENSE.GPL included in
** the packaging of this file. Please review the following information to
** ensure the GNU General Public License version 2.0 requirements will be
** met: http://www.gnu.org/licenses/gpl-2.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickpopupitem_p_p.h"
#include "qquickapplicationwindow_p.h"
#include "qquickshortcutcontext_p_p.h"
#include "qquickpage_p_p.h"
#include "qquickcontentitem_p.h"
#include "qquickpopup_p_p.h"
#include "qquickdeferredexecute_p_p.h"
#include <QtGui/private/qshortcutmap_p.h>
#include <QtGui/private/qguiapplication_p.h>
#if QT_CONFIG(accessibility)
#include <QtQuick/private/qquickaccessibleattached_p.h>
#endif
QT_BEGIN_NAMESPACE
class QQuickPopupItemPrivate : public QQuickPagePrivate
{
Q_DECLARE_PUBLIC(QQuickPopupItem)
public:
QQuickPopupItemPrivate(QQuickPopup *popup);
void implicitWidthChanged() override;
void implicitHeightChanged() override;
void resolveFont() override;
void resolvePalette() override;
QQuickItem *getContentItem() override;
void cancelContentItem() override;
void executeContentItem(bool complete = false) override;
void cancelBackground() override;
void executeBackground(bool complete = false) override;
int backId = 0;
int escapeId = 0;
QQuickPopup *popup = nullptr;
};
QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
: popup(popup)
{
isTabFence = true;
}
void QQuickPopupItemPrivate::implicitWidthChanged()
{
QQuickPagePrivate::implicitWidthChanged();
emit popup->implicitWidthChanged();
}
void QQuickPopupItemPrivate::implicitHeightChanged()
{
QQuickPagePrivate::implicitHeightChanged();
emit popup->implicitHeightChanged();
}
void QQuickPopupItemPrivate::resolveFont()
{
if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(popup->window()))
inheritFont(window->font());
else
inheritFont(QQuickTheme::font(QQuickTheme::System));
}
void QQuickPopupItemPrivate::resolvePalette()
{
if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(popup->window()))
inheritPalette(window->palette());
else
inheritPalette(QQuickTheme::palette(QQuickTheme::System));
}
QQuickItem *QQuickPopupItemPrivate::getContentItem()
{
Q_Q(QQuickPopupItem);
if (QQuickItem *item = QQuickPagePrivate::getContentItem())
return item;
return new QQuickContentItem(popup, q);
}
static inline QString contentItemName() { return QStringLiteral("contentItem"); }
void QQuickPopupItemPrivate::cancelContentItem()
{
quickCancelDeferred(popup, contentItemName());
}
void QQuickPopupItemPrivate::executeContentItem(bool complete)
{
if (contentItem.wasExecuted())
return;
if (!contentItem || complete)
quickBeginDeferred(popup, contentItemName(), contentItem);
if (complete)
quickCompleteDeferred(popup, contentItemName(), contentItem);
}
static inline QString backgroundName() { return QStringLiteral("background"); }
void QQuickPopupItemPrivate::cancelBackground()
{
quickCancelDeferred(popup, backgroundName());
}
void QQuickPopupItemPrivate::executeBackground(bool complete)
{
if (background.wasExecuted())
return;
if (!background || complete)
quickBeginDeferred(popup, backgroundName(), background);
if (complete)
quickCompleteDeferred(popup, backgroundName(), background);
}
QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup)
: QQuickPage(*(new QQuickPopupItemPrivate(popup)), nullptr)
{
setParent(popup);
setFlag(ItemIsFocusScope);
setAcceptedMouseButtons(Qt::AllButtons);
#if QT_CONFIG(cursor)
setCursor(Qt::ArrowCursor);
#endif
#if QT_CONFIG(quicktemplates2_hover)
// TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
setHoverEnabled(true);
// setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
// connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents);
#endif
}
void QQuickPopupItem::grabShortcut()
{
#if QT_CONFIG(shortcut)
Q_D(QQuickPopupItem);
QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
if (!d->backId)
d->backId = pApp->shortcutMap.addShortcut(this, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher);
if (!d->escapeId)
d->escapeId = pApp->shortcutMap.addShortcut(this, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher);
#endif
}
void QQuickPopupItem::ungrabShortcut()
{
#if QT_CONFIG(shortcut)
Q_D(QQuickPopupItem);
QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
if (d->backId) {
pApp->shortcutMap.removeShortcut(d->backId, this);
d->backId = 0;
}
if (d->escapeId) {
pApp->shortcutMap.removeShortcut(d->escapeId, this);
d->escapeId = 0;
}
#endif
}
void QQuickPopupItem::updatePolish()
{
Q_D(QQuickPopupItem);
return QQuickPopupPrivate::get(d->popup)->reposition();
}
bool QQuickPopupItem::event(QEvent *event)
{
#if QT_CONFIG(shortcut)
Q_D(QQuickPopupItem);
if (event->type() == QEvent::Shortcut) {
QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) {
QQuickPopupPrivate *p = QQuickPopupPrivate::get(d->popup);
if (p->interactive) {
p->closeOrReject();
return true;
}
}
}
#endif
return QQuickItem::event(event);
}
bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
{
Q_D(QQuickPopupItem);
return d->popup->childMouseEventFilter(child, event);
}
void QQuickPopupItem::focusInEvent(QFocusEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->focusInEvent(event);
}
void QQuickPopupItem::focusOutEvent(QFocusEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->focusOutEvent(event);
}
void QQuickPopupItem::keyPressEvent(QKeyEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->keyPressEvent(event);
}
void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->keyReleaseEvent(event);
}
void QQuickPopupItem::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->mousePressEvent(event);
}
void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->mouseMoveEvent(event);
}
void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->mouseReleaseEvent(event);
}
void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->mouseDoubleClickEvent(event);
}
void QQuickPopupItem::mouseUngrabEvent()
{
Q_D(QQuickPopupItem);
d->popup->mouseUngrabEvent();
}
#if QT_CONFIG(quicktemplates2_multitouch)
void QQuickPopupItem::touchEvent(QTouchEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->touchEvent(event);
}
void QQuickPopupItem::touchUngrabEvent()
{
Q_D(QQuickPopupItem);
d->popup->touchUngrabEvent();
}
#endif
#if QT_CONFIG(wheelevent)
void QQuickPopupItem::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickPopupItem);
d->popup->wheelEvent(event);
}
#endif
void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
{
Q_D(QQuickPopupItem);
QQuickPage::contentItemChange(newItem, oldItem);
d->popup->contentItemChange(newItem, oldItem);
}
void QQuickPopupItem::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
{
Q_D(QQuickPopupItem);
QQuickPage::contentSizeChange(newSize, oldSize);
d->popup->contentSizeChange(newSize, oldSize);
}
void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont)
{
Q_D(QQuickPopupItem);
QQuickPage::fontChange(newFont, oldFont);
d->popup->fontChange(newFont, oldFont);
}
void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
Q_D(QQuickPopupItem);
QQuickPage::geometryChanged(newGeometry, oldGeometry);
d->popup->geometryChanged(newGeometry, oldGeometry);
}
void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
{
Q_D(QQuickPopupItem);
QQuickPage::localeChange(newLocale, oldLocale);
d->popup->localeChange(newLocale, oldLocale);
}
void QQuickPopupItem::mirrorChange()
{
Q_D(QQuickPopupItem);
emit d->popup->mirroredChanged();
}
void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data)
{
Q_D(QQuickPopupItem);
QQuickPage::itemChange(change, data);
d->popup->itemChange(change, data);
}
void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
{
Q_D(QQuickPopupItem);
QQuickPage::paddingChange(newPadding, oldPadding);
d->popup->paddingChange(newPadding, oldPadding);
}
void QQuickPopupItem::paletteChange(const QPalette &newPalette, const QPalette &oldPalette)
{
Q_D(QQuickPopupItem);
QQuickPage::paletteChange(newPalette, oldPalette);
d->popup->paletteChange(newPalette, oldPalette);
}
void QQuickPopupItem::enabledChange()
{
Q_D(QQuickPopupItem);
// Just having QQuickPopup connect our QQuickItem::enabledChanged() signal
// to its enabledChanged() signal is enough for the enabled property to work,
// but we must also ensure that its paletteChanged() signal is emitted
// so that bindings to palette are re-evaluated, because QQuickControl::palette()
// returns a different palette depending on whether or not the control is enabled.
// To save a connection, we also emit enabledChanged here.
emit d->popup->enabledChanged();
emit d->popup->paletteChanged();
}
QFont QQuickPopupItem::defaultFont() const
{
Q_D(const QQuickPopupItem);
return d->popup->defaultFont();
}
QPalette QQuickPopupItem::defaultPalette() const
{
Q_D(const QQuickPopupItem);
return d->popup->defaultPalette();
}
#if QT_CONFIG(accessibility)
QAccessible::Role QQuickPopupItem::accessibleRole() const
{
Q_D(const QQuickPopupItem);
return d->popup->accessibleRole();
}
void QQuickPopupItem::accessibilityActiveChanged(bool active)
{
Q_D(const QQuickPopupItem);
// Can't just use d->popup->accessibleName() here, because that refers to the accessible
// name of us, the popup item, which is not what we want.
const QQuickAccessibleAttached *popupAccessibleAttached = QQuickControlPrivate::accessibleAttached(d->popup);
const QString oldPopupName = popupAccessibleAttached ? popupAccessibleAttached->name() : QString();
const bool wasNameExplicitlySetOnPopup = popupAccessibleAttached && popupAccessibleAttached->wasNameExplicitlySet();
QQuickPage::accessibilityActiveChanged(active);
QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this);
const QString ourName = accessibleAttached ? accessibleAttached->name() : QString();
if (wasNameExplicitlySetOnPopup && accessibleAttached && ourName != oldPopupName) {
// The user set Accessible.name on the Popup. Since the Popup and its popup item
// have different accessible attached properties, the popup item doesn't know that
// a name was set on the Popup by the user, and that it should use that, rather than
// whatever QQuickPage sets. That's why we need to do it here.
// To avoid it being overridden by the call to accessibilityActiveChanged() below,
// we set it explicitly. It's safe to do this as the popup item is an internal implementation detail.
accessibleAttached->setName(oldPopupName);
}
// This allows the different popup types to set a name on their popup item accordingly.
// For example: Dialog uses its title and ToolTip uses its text.
d->popup->accessibilityActiveChanged(active);
}
#endif
QT_END_NAMESPACE