on xenial help sign in
use model for surfaces
698b707Nick Dedekind
qml/Stages/AppSurfaceContainer.qml+37−14
@@ -18,7 +18,7 @@ import QtQuick 2.0
18import "Animations"
18import "Animations"
19
19
20SurfaceContainer {
20SurfaceContainer {
21− id: container
21+ id: root
22 property var promptSurfaces
22 property var promptSurfaces
23
23
24 property bool appHasCreatedASurface: false
24 property bool appHasCreatedASurface: false
@@ -40,32 +40,55 @@ SurfaceContainer {
40 Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
40 Timer { //FIXME - need to delay removing splash screen to allow surface resize to complete
41 id: surfaceRevealDelay
41 id: surfaceRevealDelay
42 interval: 100
42 interval: 100
43− onTriggered: surfaceContainer.revealSurface()
43+ onTriggered: root.revealSurface()
44 }
44 }
45
45
46 Loader {
46 Loader {
47− z: 3
48 id: splashLoader
47 id: splashLoader
49 anchors.fill: parent
48 anchors.fill: parent
49+ z: 3
50 }
50 }
51
51
52 Repeater {
52 Repeater {
53+ id: promptRepeater
53− model: container.promptSurfaces
54+ model: root.promptSurfaces
54
55
55 delegate: SurfaceContainer {
56 delegate: SurfaceContainer {
57+ objectName: "promptDelegate" + index
58+ id: prompt
59+
56 anchors {
60 anchors {
57− fill: container
61+ fill: root
58− topMargin: container.surface.anchors.topMargin
62+ topMargin: root.surface.anchors.topMargin
59− rightMargin: container.surface.anchors.rightMargin
63+ rightMargin: root.surface.anchors.rightMargin
60− bottomMargin: container.surface.anchors.bottomMargin
64+ bottomMargin: root.surface.anchors.bottomMargin
61− leftMargin: container.surface.anchors.leftMargin
65+ leftMargin: root.surface.anchors.leftMargin
62 }
66 }
63−
64 z: 4 + index
67 z: 4 + index
68+
65 surface: modelData
69 surface: modelData
66
70
67 Component.onCompleted: {
71 Component.onCompleted: {
68− animateIn();
72+ prompt.animateIn(swipeFromBottom);
73+ }
74+
75+ Connections {
76+ target: prompt.surface
77+ onRemoved: {
78+ // remove all prompts after this one.
79+ if (index !== promptRepeater.count-1) {
80+ var nextSurface = promptRepeater.itemAt(index+1).surface;
81+ nextSurface.removed();
82+ }
83+
84+ prompt.removing = true;
85+ prompt.animateOut();
86+ }
87+ }
88+
89+ Component {
90+ id: swipeFromBottom
91+ SwipeFromBottomAnimation {}
69 }
92 }
70 }
93 }
71 }
94 }
@@ -75,19 +98,19 @@ SurfaceContainer {
75 states: [
98 states: [
76 State {
99 State {
77 name: "noSurfaceYet"
100 name: "noSurfaceYet"
78− when: !surfaceContainer.appHasCreatedASurface
101+ when: !root.appHasCreatedASurface
79 StateChangeScript {
102 StateChangeScript {
80 script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
103 script: { splashLoader.setSource("Splash.qml", { "name": model.name, "image": model.icon }); }
81 }
104 }
82 },
105 },
83 State {
106 State {
84 name: "hasSurface"
107 name: "hasSurface"
85− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface !== null)
108+ when: root.appHasCreatedASurface && (root.surface !== null)
86 StateChangeScript { script: { surfaceRevealDelay.start(); } }
109 StateChangeScript { script: { surfaceRevealDelay.start(); } }
87 },
110 },
88 State {
111 State {
89 name: "surfaceLostButAppStillAlive"
112 name: "surfaceLostButAppStillAlive"
90− when: surfaceContainer.appHasCreatedASurface && (surfaceContainer.surface === null)
113+ when: root.appHasCreatedASurface && (root.surface === null)
91 // TODO - use app snapshot
114 // TODO - use app snapshot
92 }
115 }
93 ]
116 ]
qml/Stages/SpreadDelegate.qml+2−1
@@ -46,7 +46,8 @@ Item {
46 target: surfaceContainer.surface
46 target: surfaceContainer.surface
47 property: "anchors.topMargin"
47 property: "anchors.topMargin"
48 value: {
48 value: {
49+ return surfaceContainer.surface == null ||
49− return surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin;
50+ surfaceContainer.surface.state === MirSurfaceItem.Fullscreen ? 0 : maximizedAppTopMargin;
50 }
51 }
51 }
52 }
52
53
qml/Stages/SurfaceContainer.qml+23−28
@@ -18,56 +18,51 @@ import QtQuick 2.0
18import "Animations"
18import "Animations"
19
19
20Item {
20Item {
21− id: container
21+ id: root
22+ objectName: "surfaceContainer"
22 property Item surface: null
23 property Item surface: null
24+ property var childSurfaces: surface ? surface.childSurfaces : 0
23 property bool removing: false
25 property bool removing: false
24
26
25 onSurfaceChanged: {
27 onSurfaceChanged: {
26 if (surface) {
28 if (surface) {
27− surface.parent = container;
29+ surface.parent = root;
28 surface.z = 1;
30 surface.z = 1;
29 state = "initial"
31 state = "initial"
30 }
32 }
31 }
33 }
32
34
33− Connections {
34− target: surface
35− onRemoved: {
36− container.removing = true;
37−
38− var childSurfaces = surface.childSurfaces;
39− for (var i=0; i<childSurfaces.length; i++) {
40− childSurfaces[i].removed();
41− }
42−
43− animateOut();
44− }
45− }
46−
47 Repeater {
35 Repeater {
48− model: surface.childSurfaces
36+ model: root.childSurfaces
49
37
50 delegate: Loader {
38 delegate: Loader {
51− z: 2
39+ objectName: "childDelegate" + index
52 anchors {
40 anchors {
53− fill: container
41+ fill: root
54− topMargin: container.surface.anchors.topMargin
42+ topMargin: root.surface.anchors.topMargin
55− rightMargin: container.surface.anchors.rightMargin
43+ rightMargin: root.surface.anchors.rightMargin
56− bottomMargin: container.surface.anchors.bottomMargin
44+ bottomMargin: root.surface.anchors.bottomMargin
57− leftMargin: container.surface.anchors.leftMargin
45+ leftMargin: root.surface.anchors.leftMargin
58 }
46 }
47+ z: 2
59
48
60 // Only way to do recursive qml items.
49 // Only way to do recursive qml items.
61 source: Qt.resolvedUrl("SurfaceContainer.qml")
50 source: Qt.resolvedUrl("SurfaceContainer.qml")
62 onLoaded: {
51 onLoaded: {
63 item.surface = modelData;
52 item.surface = modelData;
64− item.animateIn();
53+ }
54+
55+ Connections {
56+ target: modelData
57+ onRemoved: {
58+ modelData.release()
59+ }
65 }
60 }
66 }
61 }
67 }
62 }
68
63
69− function animateIn() {
64+ function animateIn(animationComponent) {
70− var animation = swipeFromBottom.createObject(container, { "surface": container.surface });
65+ var animation = animationComponent.createObject(root, { "surface": root.surface });
71 animation.start();
66 animation.start();
72
67
73 var tmp = d.animations;
68 var tmp = d.animations;
@@ -82,7 +77,7 @@ Item {
82 popped.end();
77 popped.end();
83 d.animations = tmp;
78 d.animations = tmp;
84 } else {
79 } else {
85− container.state = "initial";
80+ root.state = "initial";
86 }
81 }
87 }
82 }
88
83
@@ -100,7 +95,7 @@ Item {
100 states: [
95 states: [
101 State {
96 State {
102 name: "initial"
97 name: "initial"
103− PropertyChanges { target: surface; anchors.fill: container }
98+ PropertyChanges { target: surface; anchors.fill: root }
104 }
99 }
105 ]
100 ]
106}
101}
tests/mocks/Unity/Application/ApplicationDBusAdaptor.cppdeleted−81
@@ -1,81 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "ApplicationInfo.h"
18−#include "ApplicationDBusAdaptor.h"
19−#include "ApplicationManager.h"
20−#include "SurfaceManager.h"
21−#include "MirSurfaceItem.h"
22−
23−quint32 nextId = 0;
24−
25−ApplicationDBusAdaptor::ApplicationDBusAdaptor(ApplicationManager* applicationManager)
26− : QDBusAbstractAdaptor(applicationManager)
27− , m_applicationManager(applicationManager)
28−{
29−}
30−
31−MirSurfaceItem* topSurface(MirSurfaceItem* surface)
32−{
33− if (!surface)
34− return nullptr;
35−
36− MirSurfaceItem* child = NULL;
37− Q_FOREACH (MirSurfaceItem *childSurface, surface->childSurfaceList()) {
38− child = topSurface(childSurface);
39− if (child) {
40− break;
41− }
42− }
43− return child ? child : surface;
44−}
45−
46−quint32 ApplicationDBusAdaptor::addPromptSurface(const QString &appId, const QString &surfaceImage)
47−{
48− qDebug() << "ApplicationDBusAdaptor::addPromptSurface to " << appId;
49−
50− ApplicationInfo* application = m_applicationManager->findApplication(appId);
51− if (!application) {
52− qDebug() << "ApplicationDBusAdaptor::addChildSurface - No application found for " << appId;
53− return 0;
54− }
55− quint32 surfaceId = ++nextId;
56− MirSurfaceItem* surface = new MirSurfaceItem(QString("%1-ChildSurface%2").arg(appId).arg(surfaceId),
57− MirSurfaceItem::Normal,
58− MirSurfaceItem::Maximized,
59− QUrl(surfaceImage));
60− m_childItems[surfaceId] = surface;
61−
62− if (application->promptSurfaceList().count() > 0) {
63− surface->setParentSurface(topSurface(application->promptSurfaceList()[0]));
64− } else {
65− application->addPromptSurface(surface);
66− }
67−
68− return surfaceId;
69−}
70−
71−void ApplicationDBusAdaptor::removeChildSurface(int surfaceId)
72−{
73− qDebug() << "ApplicationDBusAdaptor::removeChildSurface - " << surfaceId;
74−
75− if (!m_childItems.contains(surfaceId)) {
76− qDebug() << "ApplicationDBusAdaptor::removeChildSurface - No added surface for " << surfaceId;
77− return;
78− }
79− MirSurfaceItem* surface = m_childItems.take(surfaceId);
80− Q_EMIT surface->removed();
81−}
tests/mocks/Unity/Application/ApplicationInfo.cpp+22−42
@@ -16,7 +16,7 @@
16
16
17#include "ApplicationInfo.h"
17#include "ApplicationInfo.h"
18#include "MirSurfaceItem.h"
18#include "MirSurfaceItem.h"
19−#include "SurfaceManager.h"
19+#include "MirSurfaceItemModel.h"
20
20
21#include <QGuiApplication>
21#include <QGuiApplication>
22#include <QQuickItem>
22#include <QQuickItem>
@@ -33,6 +33,7 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
33 , m_fullscreen(false)
33 , m_fullscreen(false)
34 , m_parentItem(0)
34 , m_parentItem(0)
35 , m_surface(0)
35 , m_surface(0)
36+ , m_promptSurfaces(new MirSurfaceItemModel(this))
36{
37{
37 connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
38 connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
38}
39}
@@ -45,16 +46,20 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
45 , m_fullscreen(false)
46 , m_fullscreen(false)
46 , m_parentItem(0)
47 , m_parentItem(0)
47 , m_surface(0)
48 , m_surface(0)
49+ , m_promptSurfaces(new MirSurfaceItemModel(this))
48{
50{
49 connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
51 connect(this, &ApplicationInfo::stateChanged, this, &ApplicationInfo::onStateChanged);
50}
52}
51
53
52ApplicationInfo::~ApplicationInfo()
54ApplicationInfo::~ApplicationInfo()
53{
55{
54− if (m_surface) {
56+ QList<MirSurfaceItem*> promptSurfaces(m_promptSurfaces->list());
55− Q_EMIT SurfaceManager::singleton()->surfaceDestroyed(m_surface);
57+ for (MirSurfaceItem* promptSurface : promptSurfaces) {
56− m_surface->deleteLater();
58+ delete promptSurface;
57 }
59 }
60+
61+ delete m_surface;
62+ delete m_promptSurfaces;
58}
63}
59
64
60void ApplicationInfo::onStateChanged(State state)
65void ApplicationInfo::onStateChanged(State state)
@@ -70,7 +75,7 @@ void ApplicationInfo::createSurface()
70{
75{
71 if (m_surface || state() == ApplicationInfo::Stopped) return;
76 if (m_surface || state() == ApplicationInfo::Stopped) return;
72
77
73− setSurface(new MirSurfaceItem(name(),
78+ setSurface(SurfaceManager::singleton()->createSurface(name(),
74 MirSurfaceItem::Normal,
79 MirSurfaceItem::Normal,
75 fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
80 fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
76 screenshot()));
81 screenshot()));
@@ -85,7 +90,6 @@ void ApplicationInfo::setSurface(MirSurfaceItem* surface)
85 if (m_surface) {
90 if (m_surface) {
86 m_surface->setApplication(nullptr);
91 m_surface->setApplication(nullptr);
87 m_surface->setParent(nullptr);
92 m_surface->setParent(nullptr);
88− SurfaceManager::singleton()->unregisterSurface(m_surface);
89 }
93 }
90
94
91 m_surface = surface;
95 m_surface = surface;
@@ -93,61 +97,37 @@ void ApplicationInfo::setSurface(MirSurfaceItem* surface)
93 if (m_surface) {
97 if (m_surface) {
94 m_surface->setApplication(this);
98 m_surface->setApplication(this);
95 m_surface->setParent(this);
99 m_surface->setParent(this);
96− SurfaceManager::singleton()->registerSurface(m_surface);
97 }
100 }
98
101
99 Q_EMIT surfaceChanged(m_surface);
102 Q_EMIT surfaceChanged(m_surface);
100− SurfaceManager::singleton()->registerSurface(m_surface);
101}
103}
102
104
103void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
105void ApplicationInfo::addPromptSurface(MirSurfaceItem* surface)
104{
106{
107+ insertPromptSurface(m_promptSurfaces->count(), surface);
108+}
109+
110+void ApplicationInfo::insertPromptSurface(uint index, MirSurfaceItem* surface)
111+{
105− qDebug() << "ApplicationInfo::addPromptSurface " << surface->name() << " to " << name();
112+ qDebug() << "ApplicationInfo::insertPromptSurface - " << surface->name() << " to " << name() << " @ " << index;
106− if (surface == m_surface || m_promptSurfaces.contains(surface)) return;
107
113
108 surface->setApplication(this);
114 surface->setApplication(this);
109− m_promptSurfaces.append(surface);
115+ m_promptSurfaces->insertSurface(index, surface);
110− Q_EMIT promptSurfacesChanged();
111}
116}
112
117
113void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
118void ApplicationInfo::removeSurface(MirSurfaceItem* surface)
114{
119{
120+ qDebug() << "Application::removeSurface - " << surface->name() << " from " << name();
121+
115 if (m_surface == surface) {
122 if (m_surface == surface) {
116 setSurface(nullptr);
123 setSurface(nullptr);
117− } else if (m_promptSurfaces.contains(surface)) {
124+ } else {
118− qDebug() << "Application::removeSurface " << surface->name() << " from " << name();
125+ m_promptSurfaces->removeSurface(surface);
119−
120− m_promptSurfaces.removeAll(surface);
121 surface->setApplication(nullptr);
126 surface->setApplication(nullptr);
122−
123− Q_EMIT promptSurfacesChanged();
124 }
127 }
125}
128}
126
129
127−QList<MirSurfaceItem*> ApplicationInfo::promptSurfaceList() const
130+MirSurfaceItemModel* ApplicationInfo::promptSurfaces() const
128{
131{
129 return m_promptSurfaces;
132 return m_promptSurfaces;
130}
133}
131−
132−QQmlListProperty<MirSurfaceItem> ApplicationInfo::promptSurfaces()
133−{
134− return QQmlListProperty<MirSurfaceItem>(this,
135− 0,
136− ApplicationInfo::promptSurfaceCount,
137− ApplicationInfo::promptSurfaceAt);
138−}
139−
140−int ApplicationInfo::promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
141−{
142− ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
143− return p->m_promptSurfaces.count();
144−}
145−
146−MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
147−{
148− ApplicationInfo *p = qobject_cast<ApplicationInfo*>(prop->object);
149−
150− if (index < 0 || index >= p->m_promptSurfaces.count())
151− return nullptr;
152− return p->m_promptSurfaces[index];
153−}
tests/mocks/Unity/Application/ApplicationInfo.h+7−7
@@ -17,11 +17,14 @@
17#ifndef APPLICATION_H
17#ifndef APPLICATION_H
18#define APPLICATION_H
18#define APPLICATION_H
19
19
20+#include "SurfaceManager.h"
21+
20#include <QObject>
22#include <QObject>
21#include <QQmlComponent>
23#include <QQmlComponent>
22
24
23class QQuickItem;
25class QQuickItem;
24class MirSurfaceItem;
26class MirSurfaceItem;
27+class MirSurfaceItemModel;
25
28
26// unity-api
29// unity-api
27#include <unity/shell/application/ApplicationInfoInterface.h>
30#include <unity/shell/application/ApplicationInfoInterface.h>
@@ -38,7 +41,7 @@ class ApplicationInfo : public ApplicationInfoInterface {
38 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
41 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
39 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
42 Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
40 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
43 Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
41− Q_PROPERTY(QQmlListProperty<MirSurfaceItem> promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
44+ Q_PROPERTY(MirSurfaceItemModel* promptSurfaces READ promptSurfaces NOTIFY promptSurfacesChanged DESIGNABLE false)
42
45
43 // Only exists in this fake implementation
46 // Only exists in this fake implementation
44
47
@@ -89,8 +92,8 @@ public:
89 void removeSurface(MirSurfaceItem* surface);
92 void removeSurface(MirSurfaceItem* surface);
90
93
91 void addPromptSurface(MirSurfaceItem* surface);
94 void addPromptSurface(MirSurfaceItem* surface);
92− QList<MirSurfaceItem*> promptSurfaceList() const;
95+ void insertPromptSurface(uint index, MirSurfaceItem* surface);
93− QQmlListProperty<MirSurfaceItem> promptSurfaces();
96+ MirSurfaceItemModel* promptSurfaces() const;
94
97
95Q_SIGNALS:
98Q_SIGNALS:
96 void surfaceChanged(MirSurfaceItem*);
99 void surfaceChanged(MirSurfaceItem*);
@@ -102,12 +105,9 @@ private Q_SLOTS:
102 void createSurface();
105 void createSurface();
103
106
104private:
107private:
105− static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
106− static MirSurfaceItem* promptSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
107−
108 QQuickItem *m_parentItem;
108 QQuickItem *m_parentItem;
109 MirSurfaceItem* m_surface;
109 MirSurfaceItem* m_surface;
110− QList<MirSurfaceItem*> m_promptSurfaces;
110+ MirSurfaceItemModel* m_promptSurfaces;
111};
111};
112
112
113Q_DECLARE_METATYPE(ApplicationInfo*)
113Q_DECLARE_METATYPE(ApplicationInfo*)
tests/mocks/Unity/Application/ApplicationManager.cpp+2−6
@@ -15,9 +15,10 @@
15 */
15 */
16
16
17#include "ApplicationManager.h"
17#include "ApplicationManager.h"
18−#include "ApplicationDBusAdaptor.h"
19#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
20#include "MirSurfaceItem.h"
19#include "MirSurfaceItem.h"
20+#include "MirSurfaceItemModel.h"
21+#include "ApplicationTestInterface.h"
21
22
22#include <paths.h>
23#include <paths.h>
23
24
@@ -36,11 +37,6 @@ ApplicationManager *ApplicationManager::singleton()
36{
37{
37 if (!the_application_manager) {
38 if (!the_application_manager) {
38 the_application_manager = new ApplicationManager();
39 the_application_manager = new ApplicationManager();
39− new ApplicationDBusAdaptor(the_application_manager);
40−
41− QDBusConnection connection = QDBusConnection::sessionBus();
42− connection.registerService("com.canonical.Unity8");
43− connection.registerObject("/com/canonical/Unity8/Mocks", the_application_manager);
44 }
40 }
45 return the_application_manager;
41 return the_application_manager;
46}
42}
tests/mocks/Unity/Application/ApplicationTestInterface.cppnew file+99
@@ -0,0 +1,99 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "ApplicationInfo.h"
18+#include "ApplicationTestInterface.h"
19+#include "ApplicationManager.h"
20+#include "SurfaceManager.h"
21+#include "MirSurfaceItem.h"
22+#include "MirSurfaceItemModel.h"
23+
24+quint32 nextId = 0;
25+
26+ApplicationTestInterface::ApplicationTestInterface(QObject* parent)
27+ : QDBusAbstractAdaptor(parent)
28+{
29+ QDBusConnection connection = QDBusConnection::sessionBus();
30+ connection.registerService("com.canonical.Unity8");
31+ connection.registerObject("/com/canonical/Unity8/Mocks", parent);
32+}
33+
34+quint32 ApplicationTestInterface::addPromptSurface(const QString &appId, const QString &surfaceImage)
35+{
36+ qDebug() << "ApplicationTestInterface::addPromptSurface to " << appId;
37+
38+ ApplicationInfo* application = ApplicationManager::singleton()->findApplication(appId);
39+ if (!application) {
40+ qDebug() << "ApplicationTestInterface::addPromptSurface - No application found for " << appId;
41+ return 0;
42+ }
43+ quint32 surfaceId = ++nextId;
44+ MirSurfaceItem* surface = SurfaceManager::singleton()->createSurface(
45+ QString("%1-Prompt%2").arg(appId)
46+ .arg(surfaceId),
47+ MirSurfaceItem::Normal,
48+ MirSurfaceItem::Maximized,
49+ QUrl(surfaceImage));
50+ m_childItems[surfaceId] = surface;
51+ application->addPromptSurface(surface);
52+
53+ return surfaceId;
54+}
55+
56+quint32 ApplicationTestInterface::addChildSurface(const QString& appId, const quint32 existingSurfaceId, const QString& surfaceImage)
57+{
58+ qDebug() << "ApplicationTestInterface::addChildSurface to " << appId;
59+
60+ ApplicationInfo* application = ApplicationManager::singleton()->findApplication(appId);
61+ if (!application) {
62+ qDebug() << "ApplicationTestInterface::addChildSurface - No application found for " << appId;
63+ return 0;
64+ }
65+
66+ MirSurfaceItem* parentSurface = nullptr;
67+ if (m_childItems.contains(existingSurfaceId)) {
68+ parentSurface = m_childItems[existingSurfaceId];
69+ } else if (application->surface()) {
70+ parentSurface = application->surface();
71+ } else {
72+ qDebug() << "ApplicationTestInterface::addChildSurface - No surface for " << appId << ":" << existingSurfaceId;
73+ return 0;
74+ }
75+
76+ quint32 surfaceId = ++nextId;
77+ MirSurfaceItem* surface = SurfaceManager::singleton()->createSurface(
78+ QString("%1-Child%2").arg(parentSurface->name())
79+ .arg(surfaceId),
80+ MirSurfaceItem::Normal,
81+ MirSurfaceItem::Maximized,
82+ QUrl(surfaceImage));
83+ parentSurface->addChildSurface(surface);
84+ m_childItems[surfaceId] = surface;
85+
86+ return surfaceId;
87+}
88+
89+void ApplicationTestInterface::removeSurface(int surfaceId)
90+{
91+ qDebug() << "ApplicationTestInterface::removeSurface - " << surfaceId;
92+
93+ if (!m_childItems.contains(surfaceId)) {
94+ qDebug() << "ApplicationTestInterface::removeSurface - No added surface for " << surfaceId;
95+ return;
96+ }
97+ MirSurfaceItem* surface = m_childItems.take(surfaceId);
98+ Q_EMIT surface->removed();
99+}
tests/mocks/Unity/Application/ApplicationDBusAdaptor.h → tests/mocks/Unity/Application/ApplicationTestInterface.hrenamed+8−9
@@ -14,8 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−#ifndef APPLICATIONDBUSADAPTOR_H
17+#ifndef APPLICATIONTESTINTERFACE_H
18−#define APPLICATIONDBUSADAPTOR_H
18+#define APPLICATIONTESTINTERFACE_H
19
19
20#include <QtDBus/QtDBus>
20#include <QtDBus/QtDBus>
21
21
@@ -23,21 +23,20 @@ class ApplicationManager;
23class SurfaceManager;
23class SurfaceManager;
24class MirSurfaceItem;
24class MirSurfaceItem;
25
25
26−class ApplicationDBusAdaptor : public QDBusAbstractAdaptor
26+class ApplicationTestInterface : public QDBusAbstractAdaptor
27{
27{
28 Q_OBJECT
28 Q_OBJECT
29 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Mocks.Application")
29 Q_CLASSINFO("D-Bus Interface", "com.canonical.Unity8.Mocks.Application")
30public:
30public:
31− ApplicationDBusAdaptor(ApplicationManager* applicationManager);
31+ ApplicationTestInterface(QObject* parent = 0);
32
32
33public Q_SLOTS:
33public Q_SLOTS:
34− quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
34+ Q_INVOKABLE quint32 addPromptSurface(const QString& appId, const QString& surfaceImage);
35+ Q_INVOKABLE quint32 addChildSurface(const QString& appId, const quint32 existingSurfaceId, const QString& surfaceImage);
35− void removeChildSurface(int surfaceId);
36+ Q_INVOKABLE void removeSurface(int surfaceId);
36
37
37private:
38private:
38− ApplicationManager* m_applicationManager;
39−
40 QHash<quint32, MirSurfaceItem*> m_childItems;
39 QHash<quint32, MirSurfaceItem*> m_childItems;
41};
40};
42
41
43−#endif // APPLICATIONDBUSADAPTOR_H
42+#endif // APPLICATIONTESTINTERFACE_H
tests/mocks/Unity/Application/CMakeLists.txt+2−1
@@ -2,12 +2,13 @@ pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application)
2
2
3set(FakeUnityApplicationQml_SOURCES
3set(FakeUnityApplicationQml_SOURCES
4 plugin.cpp
4 plugin.cpp
5− ApplicationDBusAdaptor.cpp
6 ApplicationInfo.cpp
5 ApplicationInfo.cpp
7 ApplicationImage.cpp
6 ApplicationImage.cpp
8 ApplicationManager.cpp
7 ApplicationManager.cpp
9 ApplicationScreenshotProvider.cpp
8 ApplicationScreenshotProvider.cpp
9+ ApplicationTestInterface.cpp
10 MirSurfaceItem.cpp
10 MirSurfaceItem.cpp
11+ MirSurfaceItemModel.cpp
11 SurfaceManager.cpp
12 SurfaceManager.cpp
12 VirtualKeyboard.cpp
13 VirtualKeyboard.cpp
13 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
14 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
tests/mocks/Unity/Application/MirSurfaceItem.cpp+25−48
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17#include "MirSurfaceItem.h"
17#include "MirSurfaceItem.h"
18+#include "MirSurfaceItemModel.h"
18#include "ApplicationInfo.h"
19#include "ApplicationInfo.h"
19
20
20#include <QPainter>
21#include <QPainter>
@@ -32,6 +33,7 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
32 , m_state(state)
33 , m_state(state)
33 , m_img(screenshot.isLocalFile() ? screenshot.toLocalFile() : screenshot.toString())
34 , m_img(screenshot.isLocalFile() ? screenshot.toLocalFile() : screenshot.toString())
34 , m_parentSurface(nullptr)
35 , m_parentSurface(nullptr)
36+ , m_children(new MirSurfaceItemModel(this))
35 , m_haveInputMethod(false)
37 , m_haveInputMethod(false)
36{
38{
37 qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
39 qDebug() << "MirSurfaceItem::MirSurfaceItem() " << this->name();
@@ -49,16 +51,19 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
49MirSurfaceItem::~MirSurfaceItem()
51MirSurfaceItem::~MirSurfaceItem()
50{
52{
51 qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
53 qDebug() << "MirSurfaceItem::~MirSurfaceItem() " << name();
54+ Q_EMIT aboutToBeDestroyed();
52
55
53− QList<MirSurfaceItem*> children(m_children);
56+ QList<MirSurfaceItem*> children(m_children->list());
54 for (MirSurfaceItem* child : children) {
57 for (MirSurfaceItem* child : children) {
55− child->setParentSurface(nullptr);
58+ delete child;
56 }
59 }
57− if (m_parentSurface)
60+ if (m_parentSurface) {
58 m_parentSurface->removeChildSurface(this);
61 m_parentSurface->removeChildSurface(this);
59−
62+ }
60− if (m_application)
63+ if (m_application) {
61 m_application->removeSurface(this);
64 m_application->removeSurface(this);
65+ }
66+ delete m_children;
62}
67}
63
68
64void MirSurfaceItem::paint(QPainter * painter)
69void MirSurfaceItem::paint(QPainter * painter)
@@ -70,10 +75,8 @@ void MirSurfaceItem::paint(QPainter * painter)
70
75
71void MirSurfaceItem::release()
76void MirSurfaceItem::release()
72{
77{
73− QList<MirSurfaceItem*> children(m_children);
78+ qDebug() << "MirSurfaceItem::release " << name();
74− for (MirSurfaceItem* child : children) {
79+
75− child->release();
76− }
77 if (m_parentSurface) {
80 if (m_parentSurface) {
78 m_parentSurface->removeChildSurface(this);
81 m_parentSurface->removeChildSurface(this);
79 }
82 }
@@ -96,62 +99,36 @@ void MirSurfaceItem::setParentSurface(MirSurfaceItem* surface)
96 if (m_parentSurface == surface || surface == this)
99 if (m_parentSurface == surface || surface == this)
97 return;
100 return;
98
101
99− if (m_parentSurface) {
100− m_parentSurface->removeChildSurface(this);
101− }
102−
103 m_parentSurface = surface;
102 m_parentSurface = surface;
104−
105− if (m_parentSurface) {
106− m_parentSurface->addChildSurface(this);
107− }
108 Q_EMIT parentSurfaceChanged(surface);
103 Q_EMIT parentSurfaceChanged(surface);
109}
104}
110
105
111void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
106void MirSurfaceItem::addChildSurface(MirSurfaceItem* surface)
112{
107{
113− qDebug() << "MirSurfaceItem::addChildSurface " << surface->name() << " to " << name();
108+ insertChildSurface(m_children->count(), surface);
114−
115− m_children.append(surface);
116− Q_EMIT childSurfacesChanged();
117}
109}
118
110
119−void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
111+void MirSurfaceItem::insertChildSurface(uint index, MirSurfaceItem* surface)
120{
112{
121− qDebug() << "MirSurfaceItem::removeChildSurface " << surface->name() << " from " << name();
113+ qDebug() << "MirSurfaceItem::insertChildSurface - " << surface->name() << " to " << name() << " @ " << index;
122
114
123− if (m_children.contains(surface)) {
115+ surface->setParentSurface(this);
124− m_children.removeOne(surface);
116+ m_children->insertSurface(index, surface);
125− Q_EMIT childSurfacesChanged();
126− }
127−}
128−
129−QList<MirSurfaceItem*> MirSurfaceItem::childSurfaceList()
130−{
131− return m_children;
132}
117}
133
118
134−QQmlListProperty<MirSurfaceItem> MirSurfaceItem::childSurfaces()
119+void MirSurfaceItem::removeChildSurface(MirSurfaceItem* surface)
135{
120{
136− return QQmlListProperty<MirSurfaceItem>(this,
121+ qDebug() << "MirSurfaceItem::removeChildSurface - " << surface->name() << " from " << name();
137− 0,
138− MirSurfaceItem::childSurfaceCount,
139− MirSurfaceItem::childSurfaceAt);
140−}
141
122
142−int MirSurfaceItem::childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop)
123+ if (m_children->contains(surface)) {
143−{
124+ m_children->removeSurface(surface);
144− MirSurfaceItem *p = qobject_cast<MirSurfaceItem*>(prop->object);
125+ surface->setParentSurface(nullptr);
145− return p->m_children.count();
126+ }
146}
127}
147
128
148−MirSurfaceItem* MirSurfaceItem::childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index)
129+MirSurfaceItemModel* MirSurfaceItem::childSurfaces() const
149{
130{
150− MirSurfaceItem *p = qobject_cast<MirSurfaceItem*>(prop->object);
151−
152− if (index < 0 || index >= p->m_children.count())
153− return nullptr;
154− return p->m_children[index];
131+ return m_children;
155}
132}
156
133
157
134
tests/mocks/Unity/Application/MirSurfaceItem.h+22−16
@@ -20,7 +20,10 @@
20#include <QQuickPaintedItem>
20#include <QQuickPaintedItem>
21#include <QImage>
21#include <QImage>
22
22
23+#include <functional>
24+
23class ApplicationInfo;
25class ApplicationInfo;
26+class MirSurfaceItemModel;
24
27
25class MirSurfaceItem : public QQuickPaintedItem
28class MirSurfaceItem : public QQuickPaintedItem
26{
29{
@@ -32,7 +35,7 @@ class MirSurfaceItem : public QQuickPaintedItem
32 Q_PROPERTY(State state READ state NOTIFY stateChanged)
35 Q_PROPERTY(State state READ state NOTIFY stateChanged)
33 Q_PROPERTY(QString name READ name NOTIFY nameChanged)
36 Q_PROPERTY(QString name READ name NOTIFY nameChanged)
34 Q_PROPERTY(MirSurfaceItem* parentSurface READ parentSurface NOTIFY parentSurfaceChanged)
37 Q_PROPERTY(MirSurfaceItem* parentSurface READ parentSurface NOTIFY parentSurfaceChanged)
35− Q_PROPERTY(QQmlListProperty<MirSurfaceItem> childSurfaces READ childSurfaces NOTIFY childSurfacesChanged DESIGNABLE false)
38+ Q_PROPERTY(MirSurfaceItemModel* childSurfaces READ childSurfaces NOTIFY childSurfacesChanged DESIGNABLE false)
36
39
37public:
40public:
38 enum Type {
41 enum Type {
@@ -55,11 +58,6 @@ public:
55 Fullscreen,
58 Fullscreen,
56 };
59 };
57
60
58− explicit MirSurfaceItem(const QString& name,
59− Type type,
60− State state,
61− const QUrl& screenshot,
62− QQuickItem *parent = 0);
63 ~MirSurfaceItem();
61 ~MirSurfaceItem();
64
62
65 //getters
63 //getters
@@ -68,10 +66,8 @@ public:
68 State state() const { return m_state; }
66 State state() const { return m_state; }
69 QString name() const { return m_name; }
67 QString name() const { return m_name; }
70 MirSurfaceItem* parentSurface() const { return m_parentSurface; }
68 MirSurfaceItem* parentSurface() const { return m_parentSurface; }
71− QList<MirSurfaceItem*> childSurfaceList();
72
69
73 void setApplication(ApplicationInfo* item);
70 void setApplication(ApplicationInfo* item);
74− void setParentSurface(MirSurfaceItem* item);
75
71
76 Q_INVOKABLE void setState(State newState);
72 Q_INVOKABLE void setState(State newState);
77 Q_INVOKABLE void release();
73 Q_INVOKABLE void release();
@@ -79,6 +75,10 @@ public:
79 void paint(QPainter * painter) override;
75 void paint(QPainter * painter) override;
80 void touchEvent(QTouchEvent * event) override;
76 void touchEvent(QTouchEvent * event) override;
81
77
78+ void addChildSurface(MirSurfaceItem* surface);
79+ void insertChildSurface(uint index, MirSurfaceItem* surface);
80+ void removeChildSurface(MirSurfaceItem* surface);
81+
82Q_SIGNALS:
82Q_SIGNALS:
83 void typeChanged(Type);
83 void typeChanged(Type);
84 void stateChanged(State);
84 void stateChanged(State);
@@ -91,20 +91,24 @@ Q_SIGNALS:
91 void inputMethodRequested();
91 void inputMethodRequested();
92 void inputMethodDismissed();
92 void inputMethodDismissed();
93
93
94+ void aboutToBeDestroyed();
95+
94private Q_SLOTS:
96private Q_SLOTS:
95 void onFocusChanged();
97 void onFocusChanged();
96
98
97protected:
99protected:
98− const QImage &screenshotImage() { return m_img; }
100+ explicit MirSurfaceItem(const QString& name,
101+ Type type,
102+ State state,
103+ const QUrl& screenshot,
104+ QQuickItem *parent = 0);
99
105
100−private:
106+ const QImage &screenshotImage() { return m_img; }
101− void addChildSurface(MirSurfaceItem* surface);
102− void removeChildSurface(MirSurfaceItem* surface);
103
107
104− QQmlListProperty<MirSurfaceItem> childSurfaces();
108+ MirSurfaceItemModel* childSurfaces() const;
105− static int childSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
109+ void setParentSurface(MirSurfaceItem* surface);
106− static MirSurfaceItem* childSurfaceAt(QQmlListProperty<MirSurfaceItem> *prop, int index);
107
110
111+private:
108 ApplicationInfo* m_application;
112 ApplicationInfo* m_application;
109 const QString m_name;
113 const QString m_name;
110 const Type m_type;
114 const Type m_type;
@@ -112,8 +116,10 @@ private:
112 const QImage m_img;
116 const QImage m_img;
113
117
114 MirSurfaceItem* m_parentSurface;
118 MirSurfaceItem* m_parentSurface;
115− QList<MirSurfaceItem*> m_children;
119+ MirSurfaceItemModel* m_children;
116 bool m_haveInputMethod;
120 bool m_haveInputMethod;
121+
122+ friend class SurfaceManager;
117};
123};
118
124
119Q_DECLARE_METATYPE(MirSurfaceItem*)
125Q_DECLARE_METATYPE(MirSurfaceItem*)
tests/mocks/Unity/Application/MirSurfaceItemModel.cppnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QQmlEngine>
18+
19+// local
20+#include "MirSurfaceItemModel.h"
21+#include "MirSurfaceItem.h"
22+
23+MirSurfaceItemModel::MirSurfaceItemModel(
24+ QObject *parent)
25+ : QAbstractListModel(parent)
26+{
27+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
28+}
29+
30+void MirSurfaceItemModel::insertSurface(uint index, MirSurfaceItem* surface)
31+{
32+ index = qMax(index, (uint)count());
33+
34+ int existingSurfaceIndex = m_surfaceItems.indexOf(surface);
35+ if (existingSurfaceIndex != -1) {
36+ move(existingSurfaceIndex, index);
37+ } else {
38+ beginInsertRows(QModelIndex(), index, index);
39+ m_surfaceItems.insert(index, surface);
40+ endInsertRows();
41+ Q_EMIT countChanged();
42+ }
43+}
44+
45+void MirSurfaceItemModel::removeSurface(MirSurfaceItem* surface)
46+{
47+ int existingSurfaceIndex = m_surfaceItems.indexOf(surface);
48+ if (existingSurfaceIndex != -1) {
49+ beginRemoveRows(QModelIndex(), existingSurfaceIndex, existingSurfaceIndex);
50+ m_surfaceItems.removeAt(existingSurfaceIndex);
51+ endRemoveRows();
52+ Q_EMIT countChanged();
53+ }
54+}
55+
56+void MirSurfaceItemModel::move(int from, int to)
57+{
58+ if (from == to) return;
59+
60+ if (from >= 0 && from < m_surfaceItems.size() && to >= 0 && to < m_surfaceItems.size()) {
61+ QModelIndex parent;
62+ /* When moving an item down, the destination index needs to be incremented
63+ by one, as explained in the documentation:
64+ http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
65+
66+ beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
67+ m_surfaceItems.move(from, to);
68+ endMoveRows();
69+ }
70+}
71+
72+QHash<int, QByteArray> MirSurfaceItemModel::roleNames() const
73+{
74+ QHash<int, QByteArray> roleNames;
75+ roleNames.insert(RoleSurface, "surface");
76+ return roleNames;
77+}
78+
79+int MirSurfaceItemModel::rowCount(const QModelIndex & /*parent*/) const
80+{
81+ return m_surfaceItems.count();
82+}
83+
84+QVariant MirSurfaceItemModel::data(const QModelIndex & index, int role) const
85+{
86+ if (index.row() >= 0 && index.row() < m_surfaceItems.count()) {
87+ MirSurfaceItem *surfaceItem = m_surfaceItems.at(index.row());
88+ switch (role) {
89+ case RoleSurface:
90+ return QVariant::fromValue(surfaceItem);
91+ default:
92+ return QVariant();
93+ }
94+ } else {
95+ return QVariant();
96+ }
97+}
98+
99+MirSurfaceItem* MirSurfaceItemModel::getSurface(int index)
100+{
101+ return m_surfaceItems[index];
102+}
tests/mocks/Unity/Application/MirSurfaceItemModel.hnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MIRSURFACEITEMMODEL_H
18+#define MIRSURFACEITEMMODEL_H
19+
20+// Qt
21+#include <QAbstractListModel>
22+
23+class MirSurfaceItem;
24+
25+class MirSurfaceItemModel : public QAbstractListModel
26+{
27+ Q_OBJECT
28+ Q_ENUMS(Roles)
29+ Q_PROPERTY(int count READ count NOTIFY countChanged)
30+
31+public:
32+ enum Roles {
33+ RoleSurface = Qt::UserRole,
34+ };
35+
36+ explicit MirSurfaceItemModel(QObject *parent = 0);
37+
38+ const QList<MirSurfaceItem*>& list() const { return m_surfaceItems; }
39+ bool contains(MirSurfaceItem* surface) const { return m_surfaceItems.contains(surface); }
40+ int count() const { return rowCount(); }
41+
42+ void insertSurface(uint index, MirSurfaceItem* surface);
43+ void removeSurface(MirSurfaceItem* surface);
44+
45+ // from QAbstractItemModel
46+ int rowCount(const QModelIndex & parent = QModelIndex()) const override;
47+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
48+ QHash<int, QByteArray> roleNames() const override;
49+
50+ Q_INVOKABLE MirSurfaceItem* getSurface(int index);
51+
52+Q_SIGNALS:
53+ void countChanged();
54+
55+private:
56+ void move(int from, int to);
57+ QList<MirSurfaceItem*> m_surfaceItems;
58+};
59+
60+Q_DECLARE_METATYPE(MirSurfaceItemModel*)
61+
62+#endif // MIRSURFACEITEMMODEL_H
tests/mocks/Unity/Application/SurfaceManager.cpp+17−4
@@ -36,19 +36,32 @@ SurfaceManager::SurfaceManager(QObject *parent) :
36{
36{
37}
37}
38
38
39+MirSurfaceItem *SurfaceManager::createSurface(const QString& name,
40+ MirSurfaceItem::Type type,
41+ MirSurfaceItem::State state,
42+ const QUrl& screenshot)
43+{
44+ MirSurfaceItem* surface = new MirSurfaceItem(name,
45+ type,
46+ state,
47+ screenshot);
48+ registerSurface(surface);
49+ connect(surface, &MirSurfaceItem::aboutToBeDestroyed, this, &SurfaceManager::onSurfaceAboutToBeDestroyed);
50+ Q_EMIT surfaceCreated(surface);
51+ return surface;
52+}
53+
39void SurfaceManager::registerSurface(MirSurfaceItem *surface)
54void SurfaceManager::registerSurface(MirSurfaceItem *surface)
40{
55{
41 connect(surface, &MirSurfaceItem::inputMethodRequested,
56 connect(surface, &MirSurfaceItem::inputMethodRequested,
42 this, &SurfaceManager::showInputMethod);
57 this, &SurfaceManager::showInputMethod);
43 connect(surface, &MirSurfaceItem::inputMethodDismissed,
58 connect(surface, &MirSurfaceItem::inputMethodDismissed,
44 this, &SurfaceManager::hideInputMethod);
59 this, &SurfaceManager::hideInputMethod);
45− Q_EMIT surfaceCreated(surface);
46}
60}
47
61
48−void SurfaceManager::unregisterSurface(MirSurfaceItem *surface)
62+void SurfaceManager::onSurfaceAboutToBeDestroyed()
49{
63{
50− disconnect(surface, 0, this, 0);
51− Q_EMIT surfaceDestroyed(surface);
64+ Q_EMIT surfaceDestroyed(qobject_cast<MirSurfaceItem*>(sender()));
52}
65}
53
66
54void SurfaceManager::showInputMethod()
67void SurfaceManager::showInputMethod()
tests/mocks/Unity/Application/SurfaceManager.h+9−1
@@ -19,7 +19,8 @@
19
19
20#include <QObject>
20#include <QObject>
21
21
22−class MirSurfaceItem;
22+#include "MirSurfaceItem.h"
23+
23class VirtualKeyboard;
24class VirtualKeyboard;
24
25
25class SurfaceManager : public QObject
26class SurfaceManager : public QObject
@@ -30,6 +31,11 @@ public:
30
31
31 static SurfaceManager *singleton();
32 static SurfaceManager *singleton();
32
33
34+ MirSurfaceItem *createSurface(const QString& name,
35+ MirSurfaceItem::Type type,
36+ MirSurfaceItem::State state,
37+ const QUrl& screenshot);
38+
33 // Internal mock use
39 // Internal mock use
34 void registerSurface(MirSurfaceItem *surface);
40 void registerSurface(MirSurfaceItem *surface);
35 void unregisterSurface(MirSurfaceItem *surface);
41 void unregisterSurface(MirSurfaceItem *surface);
@@ -46,6 +52,8 @@ private Q_SLOTS:
46 void showInputMethod();
52 void showInputMethod();
47 void hideInputMethod();
53 void hideInputMethod();
48
54
55+ void onSurfaceAboutToBeDestroyed();
56+
49private:
57private:
50 static SurfaceManager *the_surface_manager;
58 static SurfaceManager *the_surface_manager;
51 VirtualKeyboard *m_virtualKeyboard;
59 VirtualKeyboard *m_virtualKeyboard;
tests/mocks/Unity/Application/plugin.cpp+21−5
@@ -20,7 +20,9 @@
20#include "ApplicationManager.h"
20#include "ApplicationManager.h"
21#include "ApplicationScreenshotProvider.h"
21#include "ApplicationScreenshotProvider.h"
22#include "MirSurfaceItem.h"
22#include "MirSurfaceItem.h"
23+#include "MirSurfaceItemModel.h"
23#include "SurfaceManager.h"
24#include "SurfaceManager.h"
25+#include "ApplicationTestInterface.h"
24
26
25#include <qqml.h>
27#include <qqml.h>
26#include <QQmlEngine>
28#include <QQmlEngine>
@@ -37,20 +39,32 @@ static QObject* surfaceManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEng
37 return SurfaceManager::singleton();
39 return SurfaceManager::singleton();
38}
40}
39
41
42+ApplicationTestInterface* s_appTestInterface = nullptr;
43+
44+static QObject* applicationTestInterface(QQmlEngine* engine, QJSEngine* scriptEngine) {
45+ Q_UNUSED(engine);
46+ Q_UNUSED(scriptEngine);
47+ if (!s_appTestInterface) {
48+ s_appTestInterface = new ApplicationTestInterface(engine);
49+ }
50+ return s_appTestInterface;
51+}
52+
40void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
53void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
41{
54{
42 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
55 qRegisterMetaType<MirSurfaceItem*>("MirSurfaceItem*");
56+ qRegisterMetaType<MirSurfaceItemModel*>("MirSurfaceItemModel*");
43
57
44 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
58 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
45− qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
46− qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
47−
48 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
59 qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
49− qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
50−
51 qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
60 qmlRegisterUncreatableType<MirSurfaceItem>(uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
52
61
62+ qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
53 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
63 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
64+
65+ qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
66+ qmlRegisterSingletonType<SurfaceManager>(uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
67+ qmlRegisterSingletonType<ApplicationTestInterface>(uri, 0, 1, "ApplicationTest", applicationTestInterface);
54}
68}
55
69
56void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
70void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
@@ -58,4 +72,6 @@ void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const c
58 QQmlExtensionPlugin::initializeEngine(engine, uri);
72 QQmlExtensionPlugin::initializeEngine(engine, uri);
59
73
60 engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(ApplicationManager::singleton()));
74 engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(ApplicationManager::singleton()));
75+ // make sure we initialise our test interface.
76+ applicationTestInterface(engine, nullptr);
61}
77}
tests/qmltests/tst_Shell.qml+128
@@ -61,6 +61,12 @@ Item {
61 signalName: "setCurrentScopeCalled"
61 signalName: "setCurrentScopeCalled"
62 }
62 }
63
63
64+ SignalSpy {
65+ id: surfaceSpy
66+ target: SurfaceManager
67+ signalName: "surfaceDestroyed"
68+ }
69+
64 UT.UnityTestCase {
70 UT.UnityTestCase {
65 name: "Shell"
71 name: "Shell"
66 when: windowShown
72 when: windowShown
@@ -431,5 +437,127 @@ Item {
431
437
432 touchRelease(shell);
438 touchRelease(shell);
433 }
439 }
440+
441+ function test_promptSurfaces_data() {
442+ return [ { tag: "1", count: 1 },
443+ { tag: "4", count: 4 } ];
444+ }
445+
446+ function test_promptSurfaces(data) {
447+ ApplicationManager.requestFocusApplication("unity8-dash");
448+ waitUntilDashIsFocused();
449+
450+ var appDelegate = findChild(shell, "appDelegate0")
451+ var surfaceContainer = findChild(appDelegate, "surfaceContainer");
452+
453+ var i;
454+ var surfaces = [];
455+ compare(surfaceContainer.promptSurfaces.count, 0);
456+ for (i = 0; i < data.count; i++) {
457+ surfaces.push(ApplicationTest.addPromptSurface("unity8-dash", Qt.resolvedUrl("Dash/artwork/music-player-design.png")));
458+ compare(surfaceContainer.promptSurfaces.count, i+1);
459+ }
460+
461+ surfaceSpy.clear();
462+ for (i = data.count-1; i >= 0; i--) {
463+ ApplicationTest.removeSurface(surfaces[i]);
464+ tryCompare(surfaceContainer.promptSurfaces, "count", i);
465+ }
466+ tryCompare(surfaceSpy, "count", data.count)
467+ }
468+
469+ function test_removeFirstPromptSurface_data() {
470+ return [ { tag: "1", count: 1 },
471+ { tag: "4", count: 4 } ];
472+ }
473+
474+ function test_removeFirstPromptSurface(data) {
475+ ApplicationManager.requestFocusApplication("unity8-dash");
476+ waitUntilDashIsFocused();
477+
478+ var appDelegate = findChild(shell, "appDelegate0")
479+ var surfaceContainer = findChild(appDelegate, "surfaceContainer");
480+
481+ var i;
482+ var surfaces = [];
483+ compare(surfaceContainer.promptSurfaces.count, 0);
484+ for (i = 0; i < data.count; i++) {
485+ surfaces.push(ApplicationTest.addPromptSurface("unity8-dash", Qt.resolvedUrl("Dash/artwork/music-player-design.png")));
486+ compare(surfaceContainer.promptSurfaces.count, i+1);
487+ }
488+
489+ surfaceSpy.clear();
490+ ApplicationTest.removeSurface(surfaces[0]);
491+ tryCompare(surfaceContainer.promptSurfaces, "count", 0);
492+ tryCompare(surfaceSpy, "count", data.count)
493+ }
494+
495+ function test_childSurfaces_data() {
496+ return [ { tag: "1", count: 1 },
497+ { tag: "4", count: 4 } ];
498+ }
499+
500+ function test_childSurfaces(data) {
501+ ApplicationManager.requestFocusApplication("unity8-dash");
502+ waitUntilDashIsFocused();
503+
504+ var appDelegate = findChild(shell, "appDelegate0")
505+ var surfaceContainer = findChild(appDelegate, "surfaceContainer");
506+
507+ var i;
508+ var surfaces = [];
509+ compare(surfaceContainer.childSurfaces.count, 0);
510+ for (i = 0; i < data.count; i++) {
511+ surfaces.push(ApplicationTest.addChildSurface("unity8-dash", 0, Qt.resolvedUrl("Dash/artwork/music-player-design.png")));
512+ compare(surfaceContainer.childSurfaces.count, i+1);
513+ }
514+
515+ surfaceSpy.clear();
516+ for (i = data.count-1; i >= 0; i--) {
517+ ApplicationTest.removeSurface(surfaces[i]);
518+ tryCompare(surfaceContainer.childSurfaces, "count", i);
519+ }
520+ tryCompare(surfaceSpy, "count", data.count)
521+ }
522+
523+ function test_tieredChildSurfaces_data() {
524+ return [
525+ { tag: "2", count: 2 },
526+ { tag: "10", count: 10 }
527+ ];
528+ }
529+
530+ function test_tieredChildSurfaces(data) {
531+ ApplicationManager.requestFocusApplication("unity8-dash");
532+ waitUntilDashIsFocused();
533+
534+ var delegate = findChild(shell, "appDelegate0")
535+ var surfaceContainer = findChild(delegate, "surfaceContainer");
536+
537+ var i;
538+ var surfaces = [];
539+ var lastSurfaceId = 0;
540+ compare(surfaceContainer.childSurfaces.count, 0);
541+ for (i = 0; i < data.count; i++) {
542+ lastSurfaceId = ApplicationTest.addChildSurface("unity8-dash", lastSurfaceId, Qt.resolvedUrl("Dash/artwork/music-player-design.png"))
543+ surfaces.push(lastSurfaceId);
544+
545+ compare(surfaceContainer.childSurfaces.count, 1);
546+
547+ delegate = findChild(surfaceContainer, "childDelegate0");
548+ surfaceContainer = findChild(delegate, "surfaceContainer");
549+ }
550+
551+ surfaceSpy.clear();
552+ for (i = data.count-1; i >= 0; i--) {
553+ ApplicationTest.removeSurface(surfaces[i]);
554+ }
555+
556+ delegate = findChild(shell, "appDelegate0")
557+ surfaceContainer = findChild(delegate, "surfaceContainer");
558+
559+ compare(surfaceContainer.childSurfaces.count, 0);
560+ tryCompare(surfaceSpy, "count", data.count)
561+ }
434 }
562 }
435}
563}