aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2016-01-30 17:21:55 +0100
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2016-01-30 22:13:11 +0000
commit7fc567eda8a187e365f4c29c6e8f08440bf31218 (patch)
tree9aabcb48b936d94f52369f8f110fe7cd916f2af1
parentcb86fefb321a05eb50b905a696401542acf7d441 (diff)
Make popups work without ApplicationWindow, to some degreev5.6.0-rc1v5.6.0
Using ApplicationWindow is highly recommended. First of all, with a plain Window, QQuickPopup attempts to set a high z-value, but cannot guarantee correct stacking order. Secondly, we cannot provide style- specific background dimming for modal popups, because it is styled as part of ApplicationWindow. Last but not least, QQuickPopup has to install a window-level event filter, which is far less efficient than how event handling done in QQuickOverlay. Change-Id: I08915abce7a1764177b92f7539eef77c054a405a Task-number: QTBUG-49921 Reviewed-by: J-P Nurmi <jpnurmi@theqtcompany.com>
-rw-r--r--src/imports/controls/Drawer.qml3
-rw-r--r--src/imports/controls/material/Drawer.qml3
-rw-r--r--src/templates/qquickcombobox.cpp4
-rw-r--r--src/templates/qquickmenu.cpp9
-rw-r--r--src/templates/qquickoverlay.cpp59
-rw-r--r--src/templates/qquickpopup.cpp129
-rw-r--r--src/templates/qquickpopup_p.h1
-rw-r--r--src/templates/qquickpopup_p_p.h4
8 files changed, 118 insertions, 94 deletions
diff --git a/src/imports/controls/Drawer.qml b/src/imports/controls/Drawer.qml
index eb4e3e57..60abeb0c 100644
--- a/src/imports/controls/Drawer.qml
+++ b/src/imports/controls/Drawer.qml
@@ -35,12 +35,13 @@
****************************************************************************/
import QtQuick 2.6
+import QtQuick.Window 2.2
import Qt.labs.templates 1.0 as T
T.Drawer {
id: control
- parent: T.ApplicationWindow.overlay
+ parent: T.ApplicationWindow.overlay || Window.contentItem
width: parent ? parent.width : 0 // TODO: Window.width
height: parent ? parent.height : 0 // TODO: Window.height
diff --git a/src/imports/controls/material/Drawer.qml b/src/imports/controls/material/Drawer.qml
index cb00096d..133ea9c8 100644
--- a/src/imports/controls/material/Drawer.qml
+++ b/src/imports/controls/material/Drawer.qml
@@ -35,13 +35,14 @@
****************************************************************************/
import QtQuick 2.6
+import QtQuick.Window 2.2
import Qt.labs.templates 1.0 as T
import Qt.labs.controls.material 1.0
T.Drawer {
id: control
- parent: T.ApplicationWindow.overlay
+ parent: T.ApplicationWindow.overlay || Window.contentItem
width: parent ? parent.width : 0 // TODO: Window.width
height: parent ? parent.height : 0 // TODO: Window.height
diff --git a/src/templates/qquickcombobox.cpp b/src/templates/qquickcombobox.cpp
index f4cb17af..dfb01e83 100644
--- a/src/templates/qquickcombobox.cpp
+++ b/src/templates/qquickcombobox.cpp
@@ -711,6 +711,10 @@ void QQuickComboBox::keyPressEvent(QKeyEvent *event)
return;
switch (event->key()) {
+ case Qt::Key_Escape:
+ if (d->isPopupVisible())
+ event->accept();
+ break;
case Qt::Key_Space:
if (!event->isAutoRepeat())
setPressed(true);
diff --git a/src/templates/qquickmenu.cpp b/src/templates/qquickmenu.cpp
index 692395ff..d3fc88d9 100644
--- a/src/templates/qquickmenu.cpp
+++ b/src/templates/qquickmenu.cpp
@@ -489,11 +489,8 @@ void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
bool QQuickMenu::eventFilter(QObject *object, QEvent *event)
{
Q_D(QQuickMenu);
- if (d->contentModel->count() == 0)
- return false;
-
- if (object != d->contentItem || event->type() != QEvent::KeyRelease)
- return false;
+ if (object != d->contentItem || event->type() != QEvent::KeyRelease || d->contentModel->count() == 0)
+ return QQuickPopup::eventFilter(object, event);
// QTBUG-17051
// Work around the fact that ListView has no way of distinguishing between
@@ -517,7 +514,7 @@ bool QQuickMenu::eventFilter(QObject *object, QEvent *event)
break;
}
- return false;
+ return QQuickPopup::eventFilter(object, event);
}
QT_END_NAMESPACE
diff --git a/src/templates/qquickoverlay.cpp b/src/templates/qquickoverlay.cpp
index 589cafdf..dd9d2c5d 100644
--- a/src/templates/qquickoverlay.cpp
+++ b/src/templates/qquickoverlay.cpp
@@ -35,7 +35,7 @@
****************************************************************************/
#include "qquickoverlay_p.h"
-#include "qquickpopup_p.h"
+#include "qquickpopup_p_p.h"
#include "qquickdrawer_p.h"
#include <QtQml/qqmlinfo.h>
#include <QtQml/qqmlproperty.h>
@@ -52,13 +52,12 @@ public:
void popupAboutToShow();
void popupAboutToHide();
- void closePopup(QQuickPopup *popup, QMouseEvent *event);
void drawerPositionChange();
void resizeBackground();
QQuickItem *background;
QVector<QQuickDrawer *> drawers;
- QHash<QQuickItem *, QQuickPopup *> popups;
+ QVector<QQuickPopup *> popups;
int modalPopups;
};
@@ -90,30 +89,6 @@ void QQuickOverlayPrivate::popupAboutToHide()
QQmlProperty::write(background, QStringLiteral("opacity"), 0.0);
}
-void QQuickOverlayPrivate::closePopup(QQuickPopup *popup, QMouseEvent *event)
-{
- Q_Q(QQuickOverlay);
- const bool isPress = event->type() == QEvent::MouseButtonPress;
- const bool onOutside = popup->closePolicy().testFlag(isPress ? QQuickPopup::OnPressOutside : QQuickPopup::OnReleaseOutside);
- const bool onOutsideParent = popup->closePolicy().testFlag(isPress ? QQuickPopup::OnPressOutsideParent : QQuickPopup::OnReleaseOutsideParent);
- if (onOutside || onOutsideParent) {
- QQuickItem *popupItem = popup->popupItem();
- QQuickItem *parentItem = popup->parentItem();
-
- if (onOutside && onOutsideParent) {
- if (!popupItem->contains(q->mapToItem(popupItem, event->pos())) &&
- (!parentItem || !parentItem->contains(q->mapToItem(parentItem, event->pos()))))
- popup->close();
- } else if (onOutside) {
- if (!popupItem->contains(q->mapToItem(popupItem, event->pos())))
- popup->close();
- } else if (onOutsideParent) {
- if (!parentItem || !parentItem->contains(q->mapToItem(parentItem, event->pos())))
- popup->close();
- }
- }
-}
-
void QQuickOverlayPrivate::drawerPositionChange()
{
Q_Q(QQuickOverlay);
@@ -197,27 +172,19 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data)
return;
if (change == ItemChildAddedChange) {
- if (QQuickPopup *prevPopup = d->popups.value(data.item)) {
- qmlInfo(popup).nospace() << "Popup is sharing item " << data.item << " with " << prevPopup
- << ". This is not supported and strange things are about to happen.";
- return;
- }
-
- d->popups.insert(data.item, popup);
+ d->popups.append(popup);
if (popup->isModal())
++d->modalPopups;
QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow);
QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide);
} else if (change == ItemChildRemovedChange) {
- Q_ASSERT(popup == d->popups.value(data.item));
+ d->popups.removeOne(popup);
+ if (popup->isModal())
+ --d->modalPopups;
QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow);
QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide);
-
- if (popup->isModal())
- --d->modalPopups;
- d->popups.remove(data.item);
}
}
@@ -247,8 +214,10 @@ void QQuickOverlay::mousePressEvent(QMouseEvent *event)
event->setAccepted(d->modalPopups > 0);
emit pressed();
- foreach (QQuickPopup *popup, d->popups)
- d->closePopup(popup, event);
+ for (int i = d->popups.count() - 1; i >= 0; --i) {
+ if (QQuickPopupPrivate::get(d->popups.at(i))->tryClose(this, event))
+ break;
+ }
}
void QQuickOverlay::mouseMoveEvent(QMouseEvent *event)
@@ -263,8 +232,10 @@ void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event)
event->setAccepted(d->modalPopups > 0);
emit released();
- foreach (QQuickPopup *popup, d->popups)
- d->closePopup(popup, event);
+ for (int i = d->popups.count() - 1; i >= 0; --i) {
+ if (QQuickPopupPrivate::get(d->popups.at(i))->tryClose(this, event))
+ break;
+ }
}
void QQuickOverlay::wheelEvent(QWheelEvent *event)
@@ -292,7 +263,7 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
if (popupItem == item)
break;
- QQuickPopup *popup = d->popups.value(popupItem);
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(popupItem->parent());
if (popup) {
QQuickPopup::ClosePolicy policy = popup->closePolicy();
if (policy.testFlag(QQuickPopup::OnPressOutside) || policy.testFlag(QQuickPopup::OnPressOutsideParent))
diff --git a/src/templates/qquickpopup.cpp b/src/templates/qquickpopup.cpp
index 8937eb1f..99525986 100644
--- a/src/templates/qquickpopup.cpp
+++ b/src/templates/qquickpopup.cpp
@@ -95,7 +95,6 @@ QQuickPopupPrivate::QQuickPopupPrivate()
, parentItem(Q_NULLPTR)
, background(Q_NULLPTR)
, contentItem(Q_NULLPTR)
- , overlay(Q_NULLPTR)
, enter(Q_NULLPTR)
, exit(Q_NULLPTR)
, popupItem(Q_NULLPTR)
@@ -108,10 +107,32 @@ void QQuickPopupPrivate::init()
{
Q_Q(QQuickPopup);
popupItem = new QQuickPopupItem(q);
- popupItem->setParent(q);
q->setParentItem(qobject_cast<QQuickItem *>(parent));
}
+bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event)
+{
+ Q_Q(QQuickPopup);
+ const bool isPress = event->type() == QEvent::MouseButtonPress;
+ const bool onOutside = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutside : QQuickPopup::OnReleaseOutside);
+ const bool onOutsideParent = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutsideParent : QQuickPopup::OnReleaseOutsideParent);
+ if (onOutside || onOutsideParent) {
+ if (onOutsideParent) {
+ if (!popupItem->contains(item->mapToItem(popupItem, event->pos())) &&
+ (!parentItem || !parentItem->contains(item->mapToItem(parentItem, event->pos())))) {
+ q->close();
+ return true;
+ }
+ } else if (onOutside) {
+ if (!popupItem->contains(item->mapToItem(popupItem, event->pos()))) {
+ q->close();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void QQuickPopupPrivate::finalizeEnterTransition()
{
if (focus)
@@ -120,11 +141,9 @@ void QQuickPopupPrivate::finalizeEnterTransition()
void QQuickPopupPrivate::finalizeExitTransition()
{
- Q_Q(QQuickPopup);
- overlay = Q_NULLPTR;
positioner.setParentItem(Q_NULLPTR);
popupItem->setParentItem(Q_NULLPTR);
- emit q->visibleChanged();
+ popupItem->setVisible(false);
}
void QQuickPopupPrivate::resizeBackground()
@@ -281,6 +300,7 @@ public:
QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup)
{
+ isTabFence = true;
}
void QQuickPopupItemPrivate::implicitWidthChanged()
@@ -296,6 +316,9 @@ void QQuickPopupItemPrivate::implicitHeightChanged()
QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) :
QQuickItem(*(new QQuickPopupItemPrivate(popup)))
{
+ setParent(popup);
+ setVisible(false);
+ setFlag(ItemIsFocusScope);
setAcceptedMouseButtons(Qt::AllButtons);
}
@@ -365,6 +388,19 @@ void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &o
d->popup->geometryChanged(newGeometry, oldGeometry);
}
+void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ Q_D(QQuickPopupItem);
+ QQuickItem::itemChange(change, data);
+ switch (change) {
+ case ItemVisibleHasChanged:
+ emit d->popup->visibleChanged();
+ break;
+ default:
+ break;
+ }
+}
+
QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopupPrivate *popup) :
m_x(0),
m_y(0),
@@ -390,7 +426,7 @@ void QQuickPopupPositioner::setX(qreal x)
{
if (m_x != x) {
m_x = x;
- if (m_popup->overlay) // isVisible
+ if (m_popup->popupItem->isVisible())
repositionPopup();
}
}
@@ -404,7 +440,7 @@ void QQuickPopupPositioner::setY(qreal y)
{
if (m_y != y) {
m_y = y;
- if (m_popup->overlay) // isVisible
+ if (m_popup->popupItem->isVisible())
repositionPopup();
}
}
@@ -432,13 +468,13 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent)
QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes);
addAncestorListeners(parent->parentItem());
- if (m_popup->overlay) // isVisible
+ if (m_popup->popupItem->isVisible())
repositionPopup();
}
void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
{
- if (m_popup->overlay) // isVisible
+ if (m_popup->popupItem->isVisible())
repositionPopup();
}
@@ -607,24 +643,12 @@ QQuickPopup::~QQuickPopup()
void QQuickPopup::open()
{
Q_D(QQuickPopup);
- if (d->overlay) {
- // popup already open
+ if (d->popupItem->isVisible())
return;
- }
QQuickWindow *window = Q_NULLPTR;
- QObject *p = parent();
- while (p && !window) {
- if (QQuickItem *item = qobject_cast<QQuickItem *>(p)) {
- window = item->window();
- if (!window)
- p = item->parentItem();
- } else {
- window = qobject_cast<QQuickWindow *>(p);
- if (!window)
- p = p->parent();
- }
- }
+ if (d->parentItem)
+ window = d->parentItem->window();
if (!window) {
qmlInfo(this) << "cannot find any window to open popup in.";
return;
@@ -632,17 +656,17 @@ void QQuickPopup::open()
QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window);
if (!applicationWindow) {
- // FIXME Maybe try to open it in that window somehow
- qmlInfo(this) << "is not in an ApplicationWindow.";
- return;
+ window->installEventFilter(this);
+ d->popupItem->setZ(10001); // DefaultWindowDecoration+1
+ d->popupItem->setParentItem(window->contentItem());
+ } else {
+ d->popupItem->setParentItem(applicationWindow->overlay());
}
- d->overlay = static_cast<QQuickOverlay *>(applicationWindow->overlay());
- d->popupItem->setParentItem(d->overlay);
- d->positioner.setParentItem(d->parentItem);
emit aboutToShow();
+ d->popupItem->setVisible(true);
+ d->positioner.setParentItem(d->parentItem);
d->transitionManager.transitionEnter();
- emit visibleChanged();
}
/*!
@@ -653,9 +677,14 @@ void QQuickPopup::open()
void QQuickPopup::close()
{
Q_D(QQuickPopup);
- if (!d->overlay) {
- // popup already closed
+ if (!d->popupItem->isVisible())
return;
+
+ if (d->parentItem) {
+ QQuickWindow *window = d->parentItem->window();
+ if (!qobject_cast<QQuickApplicationWindow *>(window)) {
+ window->removeEventFilter(this);
+ }
}
d->popupItem->setFocus(false);
@@ -1224,18 +1253,12 @@ QQuickItem *QQuickPopup::contentItem() const
void QQuickPopup::setContentItem(QQuickItem *item)
{
Q_D(QQuickPopup);
- if (d->overlay) {
- // FIXME qmlInfo needs to know about QQuickItem and/or QObject
- static_cast<QDebug>(qmlInfo(this) << "cannot set content item") << item << "while Popup is visible.";
- return;
- }
if (d->contentItem != item) {
contentItemChange(item, d->contentItem);
delete d->contentItem;
d->contentItem = item;
if (item) {
item->setParentItem(d->popupItem);
- QQuickItemPrivate::get(item)->isTabFence = true;
if (isComponentComplete())
d->resizeContent();
}
@@ -1326,7 +1349,7 @@ void QQuickPopup::setModal(bool modal)
bool QQuickPopup::isVisible() const
{
Q_D(const QQuickPopup);
- return d->overlay != Q_NULLPTR /*&& !d->transitionManager.isRunning()*/;
+ return d->popupItem->isVisible();
}
void QQuickPopup::setVisible(bool visible)
@@ -1467,6 +1490,32 @@ bool QQuickPopup::isComponentComplete() const
return d->complete;
}
+bool QQuickPopup::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QQuickPopup);
+ Q_UNUSED(object);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ if (d->modal)
+ event->setAccepted(true);
+ if (QQuickWindow *window = qobject_cast<QQuickWindow *>(object)) {
+ if (d->tryClose(window->contentItem(), static_cast<QMouseEvent *>(event)))
+ return true;
+ }
+ return false;
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ if (d->modal)
+ event->setAccepted(true);
+ return false;
+ default:
+ return false;
+ }
+}
+
void QQuickPopup::focusInEvent(QFocusEvent *event)
{
event->accept();
diff --git a/src/templates/qquickpopup_p.h b/src/templates/qquickpopup_p.h
index e2d89c66..ac9a238a 100644
--- a/src/templates/qquickpopup_p.h
+++ b/src/templates/qquickpopup_p.h
@@ -276,6 +276,7 @@ protected:
void componentComplete() Q_DECL_OVERRIDE;
bool isComponentComplete() const;
+ bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE;
virtual void focusInEvent(QFocusEvent *event);
virtual void focusOutEvent(QFocusEvent *event);
virtual void keyPressEvent(QKeyEvent *event);
diff --git a/src/templates/qquickpopup_p_p.h b/src/templates/qquickpopup_p_p.h
index f27ed762..29faa94e 100644
--- a/src/templates/qquickpopup_p_p.h
+++ b/src/templates/qquickpopup_p_p.h
@@ -60,7 +60,6 @@ QT_BEGIN_NAMESPACE
class QQuickTransition;
class QQuickTransitionManager;
class QQuickPopup;
-class QQuickOverlay;
class QQuickPopupPrivate;
class QQuickPopupItemPrivate;
@@ -104,6 +103,7 @@ protected:
void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE;
+ void itemChange(ItemChange change, const ItemChangeData &data) Q_DECL_OVERRIDE;
private:
Q_DECLARE_PRIVATE(QQuickPopupItem)
@@ -157,6 +157,7 @@ public:
}
void init();
+ bool tryClose(QQuickItem *item, QMouseEvent *event);
void finalizeEnterTransition();
void finalizeExitTransition();
@@ -203,7 +204,6 @@ public:
QQuickItem *parentItem;
QQuickItem *background;
QQuickItem *contentItem;
- QQuickOverlay *overlay;
QQuickTransition *enter;
QQuickTransition *exit;
QQuickPopupItem *popupItem;