From 0f4266fbbc45fc311051d9bfb014fb162c383c3e Mon Sep 17 00:00:00 2001
From: Shawn Rutledge <shawn.rutledge@digia.com>
Date: Fri, 24 Oct 2014 09:56:41 +0200
Subject: [PATCH] Dialogs: detect and handle dynamic creation with Window
 parent

When instantiating via Qt.createQmlObject('Dialog { }', window, "path")
the dialog's parent will be the Window.  That was an unanticipated use
case, but also a simpler one: if the platform does not support multiple
windows, then we only need to construct the dialog and its decoration
on top of that window's contentItem.  Or if there is to be a separate
dialog window, then it should be transient for the main window.

Also rearranged the parenting strategy around the fact that the
application is always within a QQuickWindow: parentWindow() is
responsible for finding it, and it's not necessary to recursively go
up the Item hierarchy to find the root item if we are sure that
there is a window, because the root item is that window's contentItem.

Task-number: QTBUG-38578
Change-Id: I79e0cf44f789701f5d40e5e9d0449a55947be907
Reviewed-by: Liang Qi <liang.qi@theqtcompany.com>
---
 src/dialogs/qquickabstractdialog.cpp | 52 +++++++++++++++++-----------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/src/dialogs/qquickabstractdialog.cpp b/src/dialogs/qquickabstractdialog.cpp
index 7c5ef3341..6cad340f7 100644
--- a/src/dialogs/qquickabstractdialog.cpp
+++ b/src/dialogs/qquickabstractdialog.cpp
@@ -35,6 +35,7 @@
 #include "qquickitem.h"
 
 #include <private/qguiapplication_p.h>
+#include <private/qqmlglobal_p.h>
 #include <QWindow>
 #include <QQmlComponent>
 #include <QQuickWindow>
@@ -109,22 +110,28 @@ void QQuickAbstractDialog::setVisible(bool v)
                 connect(win, SIGNAL(heightChanged(int)), this, SLOT(windowGeometryChanged()));
             }
 
-            QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
-
-            // If the platform does not support multiple windows, but the dialog is
-            // implemented as an Item, then try to decorate it as a fake window and make it visible.
-            if (parentItem && !m_dialogWindow && !m_windowDecoration) {
-                if (m_decorationComponent) {
-                    if (m_decorationComponent->isLoading())
-                        connect(m_decorationComponent, SIGNAL(statusChanged(QQmlComponent::Status)),
-                                this, SLOT(decorationLoaded()));
-                    else
-                        decorationLoaded();
+            if (!m_dialogWindow) {
+                if (Q_UNLIKELY(!parentWindow())) {
+                    qWarning("cannot set dialog visible: no window");
+                    return;
                 }
-                // Window decoration wasn't possible, so just reparent it into the scene
-                else {
-                    m_contentItem->setParentItem(parentItem);
-                    m_contentItem->setZ(10000);
+                m_dialogWindow = parentWindow();
+
+                // If the platform does not support multiple windows, but the dialog is
+                // implemented as an Item, then try to decorate it as a fake window and make it visible.
+                if (!m_windowDecoration) {
+                    if (m_decorationComponent) {
+                        if (m_decorationComponent->isLoading())
+                            connect(m_decorationComponent, SIGNAL(statusChanged(QQmlComponent::Status)),
+                                    this, SLOT(decorationLoaded()));
+                        else
+                            decorationLoaded(); // do the reparenting of contentItem on top of it
+                    }
+                    // Window decoration wasn't possible, so just reparent it into the scene
+                    else {
+                        m_contentItem->setParentItem(parentWindow()->contentItem());
+                        m_contentItem->setZ(10000);
+                    }
                 }
             }
         }
@@ -168,9 +175,9 @@ void QQuickAbstractDialog::setVisible(bool v)
 void QQuickAbstractDialog::decorationLoaded()
 {
     bool ok = false;
-    QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
-    while (parentItem->parentItem() && !parentItem->parentItem()->inherits("QQuickRootItem"))
-        parentItem = parentItem->parentItem();
+    Q_ASSERT(parentWindow());
+    QQuickItem *parentItem = parentWindow()->contentItem();
+    Q_ASSERT(parentItem);
     if (m_decorationComponent->isError()) {
         qWarning() << m_decorationComponent->errors();
     } else {
@@ -252,9 +259,12 @@ void QQuickAbstractDialog::implicitHeightChanged()
 
 QQuickWindow *QQuickAbstractDialog::parentWindow()
 {
-    QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
-    if (parentItem)
-        m_parentWindow = parentItem->window();
+    if (!m_parentWindow) {
+        // Usually a dialog is declared inside an Item; but if its QObject parent
+        // is a Window, that's the window we are interested in. (QTBUG-38578)
+        QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+        m_parentWindow = (parentItem ? parentItem->window() : qmlobject_cast<QQuickWindow *>(parent()));
+    }
     return m_parentWindow;
 }
 
-- 
GitLab