a nested Window automatically becomes transient for its parent

If you declare Window { Window {}} or Window { Item { Window {}}}
the inner window will automatically become transient for the
outer one.  The transient relationship must be set before the
inner window becomes visible though, so declaring visible: true
doesn't always work, depending on initialization order.  It's OK
if you assign visible (or call show()) later on when the user needs
to see the transient window for the first time.

Also added documentation.

Change-Id: I888c3b9da6d44d11516227c085bcc12a5ccb5e81
Reviewed-by: Shawn Rutledge <shawn.rutledge@digia.com>
Reviewed-by: Jan Arve Sæther <jan-arve.saether@digia.com>
This commit is contained in:
Shawn Rutledge 2013-03-27 09:57:59 +01:00 committed by The Qt Project
parent 8190355557
commit ccbf0560b3
7 changed files with 119 additions and 6 deletions

3
dist/changes-5.1.0 vendored
View File

@ -32,6 +32,9 @@ Third party components
* Important Behavior Changes *
****************************************************************************
- A Window declared nested inside another Item or Window automatically
becomes transient for (centered upon) its parent's window, if x and y
were not explicitly specified
****************************************************************************
* Library *

View File

@ -2685,6 +2685,23 @@ void QQuickItemPrivate::data_append(QQmlListProperty<QObject> *prop, QObject *o)
} else {
if (o->inherits("QGraphicsItem"))
qWarning("Cannot add a QtQuick 1.0 item (%s) into a QtQuick 2.0 scene!", o->metaObject()->className());
else {
QQuickWindow *thisWindow = qmlobject_cast<QQuickWindow *>(o);
QQuickItem *item = that;
QQuickWindow *itemWindow = that->window();
while (!itemWindow && item && item->parentItem()) {
item = item->parentItem();
itemWindow = item->window();
}
if (thisWindow) {
if (itemWindow)
thisWindow->setTransientParent(itemWindow);
else
QObject::connect(item, SIGNAL(windowChanged(QQuickWindow*)),
thisWindow, SLOT(setTransientParent_helper(QQuickWindow*)));
}
}
// XXX todo - do we really want this behavior?
o->setParent(that);
@ -4413,8 +4430,8 @@ void QQuickItemPrivate::deliverDragEvent(QEvent *e)
*/
void QQuickItem::itemChange(ItemChange change, const ItemChangeData &value)
{
Q_UNUSED(change);
Q_UNUSED(value);
if (change == ItemSceneChange)
emit windowChanged(value.window);
}
#ifndef QT_NO_IM

View File

@ -355,6 +355,7 @@ Q_SIGNALS:
void smoothChanged(bool);
void antialiasingChanged(bool);
void clipChanged(bool);
Q_REVISION(1) void windowChanged(QQuickWindow* window);
// XXX todo
void childrenChanged();

View File

@ -414,7 +414,10 @@ void QQuickWindowPrivate::init(QQuickWindow *c)
QQmlListProperty<QObject> QQuickWindowPrivate::data()
{
initContentItem();
return QQuickItemPrivate::get(contentItem)->data();
return QQmlListProperty<QObject>(q_func(), 0, QQuickWindowPrivate::data_append,
QQuickWindowPrivate::data_count,
QQuickWindowPrivate::data_at,
QQuickWindowPrivate::data_clear);
}
void QQuickWindowPrivate::initContentItem()
@ -846,7 +849,21 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
import QtQuick.Window 2.1
\endcode
Restricting this import will allow you to have a QML environment without access to window system features.
Omitting this import will allow you to have a QML environment without
access to window system features.
A Window can be declared inside an Item or inside another Window; in that
case the inner Window will automatically become "transient for" the outer
Window: that is, most platforms will show it centered upon the outer window
by default, and there may be other platform-dependent behaviors, depending
also on the \l flags. If the nested window is intended to be a dialog in
your application, you should also set \l flags to Qt.Dialog, because some
window managers will not provide the centering behavior without that flag.
You can also declare multiple windows inside a top-level \l QtObject, in which
case the windows will have no transient relationship.
Alternatively you can set or bind \l x and \l y to position the Window
explicitly on the screen.
*/
/*!
\class QQuickWindow
@ -1094,7 +1111,10 @@ QQuickItem *QQuickWindow::contentItem() const
}
/*!
Returns the item which currently has active focus.
\property QQuickWindow::activeFocusItem
\brief The item which currently has active focus or \c null if there is
no item with active focus.
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@ -2037,6 +2057,64 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent
return overThreshold;
}
/*!
\qmlproperty list<Object> QtQuick.Window2::Window::data
\default
The data property allows you to freely mix visual children, resources
and other Windows in a Window.
If you assign another Window to the data list, the nested window will
become "transient for" the outer Window.
If you assign an \l Item to the data list, it becomes a child of the
Window's \l contentItem, so that it appears inside the window. The item's
parent will be the window's contentItem, which is the root of the Item
ownership tree within that Window.
If you assign any other object type, it is added as a resource.
It should not generally be necessary to refer to the \c data property,
as it is the default property for Window and thus all child items are
automatically assigned to this property.
\sa QWindow::transientParent()
*/
void QQuickWindowPrivate::data_append(QQmlListProperty<QObject> *property, QObject *o)
{
if (!o)
return;
QQuickWindow *that = static_cast<QQuickWindow *>(property->object);
if (QQuickWindow *window = qmlobject_cast<QQuickWindow *>(o))
window->setTransientParent(that);
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(that->contentItem())->data();
itemProperty.append(&itemProperty, o);
}
int QQuickWindowPrivate::data_count(QQmlListProperty<QObject> *property)
{
QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
if (!win || !win->contentItem() || !QQuickItemPrivate::get(win->contentItem())->data().count)
return 0;
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
return itemProperty.count(&itemProperty);
}
QObject *QQuickWindowPrivate::data_at(QQmlListProperty<QObject> *property, int i)
{
QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
return itemProperty.at(&itemProperty, i);
}
void QQuickWindowPrivate::data_clear(QQmlListProperty<QObject> *property)
{
QQuickWindow *win = static_cast<QQuickWindow*>(property->object);
QQmlListProperty<QObject> itemProperty = QQuickItemPrivate::get(win->contentItem())->data();
itemProperty.clear(&itemProperty);
}
bool QQuickWindowPrivate::isRenderable() const
{
const QQuickWindow *q = q_func();
@ -2456,6 +2534,13 @@ void QQuickWindow::cleanupSceneGraph()
d->renderer = 0;
}
void QQuickWindow::setTransientParent_helper(QQuickWindow *window)
{
setTransientParent(window);
disconnect(sender(), SIGNAL(windowChanged(QQuickWindow*)),
this, SLOT(setTransientParent_helper(QQuickWindow*)));
}
/*!
Returns the opengl context used for rendering.

View File

@ -162,6 +162,7 @@ protected:
private Q_SLOTS:
void maybeUpdate();
void cleanupSceneGraph();
void setTransientParent_helper(QQuickWindow *window);
private:
friend class QQuickItem;

View File

@ -224,6 +224,12 @@ public:
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event);
// data property
static void data_append(QQmlListProperty<QObject> *, QObject *);
static int data_count(QQmlListProperty<QObject> *);
static QObject *data_at(QQmlListProperty<QObject> *, int);
static void data_clear(QQmlListProperty<QObject> *);
private:
static void cleanupNodesOnShutdown(QQuickItem *);
};

View File

@ -585,7 +585,7 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QWindow *secondWindow = qvariant_cast<QWindow*>(window->rootObject()->property("secondWindow"));
secondWindow->setProperty("visible", true);
QTest::qWaitForWindowActive(secondWindow);
QTest::qWaitForWindowExposed(secondWindow);
QVERIFY(!window->rootObject()->property("pressed").toBool());
QVERIFY(window->rootObject()->property("canceled").toBool());