on xenial help sign in
Get rid of all mentions to screenshot in the Unity.Application API
commit845cc0eaca8aebe3eebeec8c9a45b10e358ccdcb authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateWed 13 Aug 2014, 16:50 (12 years ago) parentfe2c641
12 files changed+110−181
qml/Stages/ApplicationWindow.qml+14−7 tests/mocks/Unity/Application/ApplicationInfo.cpp+18−22 tests/mocks/Unity/Application/ApplicationInfo.h+13−8 tests/mocks/Unity/Application/ApplicationManager.cpp+17−32 tests/mocks/Unity/Application/ApplicationManager.h+2−2 tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp+4−4 tests/mocks/Unity/Application/MirSurfaceItem.cpp+4−9 tests/mocks/Unity/Application/MirSurfaceItem.qml+9−1 tests/mocks/Unity/Application/VirtualKeyboard.qml+2 tests/plugins/Unity/Launcher/launchermodeltest.cpp−4 tests/qmltests/Stages/tst_ApplicationWindow.qml+24−69 tests/qmltests/Stages/tst_SpreadDelegate.qml+3−23
qml/Stages/ApplicationWindow.qml+14−7
@@ -41,7 +41,7 @@ Item {
4141 && root.applicationState === ApplicationInfo.Stopped
4242 on_NeedToTakeScreenshotChanged: {
4343 if (_needToTakeScreenshot) {
44− application.updateScreenshot();
44+ screenshotImage.take();
4545 }
4646 }
4747
@@ -96,8 +96,18 @@ Item {
9696
9797 Image {
9898 id: screenshotImage
99− source: root.application ? root.application.screenshot : ""
99+ objectName: "screenshotImage"
100+ source: ""
100101 anchors.fill: parent
102+
103+ function take() {
104+ // Format: "image://application/$APP_ID/$CURRENT_TIME_MS"
105+ // eg: "image://application/calculator-app/123456"
106+ var timeMs = new Date().getTime();
107+ source = "image://application/" + root.application.appId + "/" + timeMs;
108+ }
109+
110+ onSourceChanged: { console.log("screenshotImage.source = " + source); }
101111 }
102112
103113 Loader {
@@ -216,11 +226,8 @@ Item {
216226 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
217227 from: 1.0; to: 0.0
218228 duration: UbuntuAnimation.BriskDuration }
219− PropertyAction { target: screenshotImage
220− property: "visible"; value: false }
221− ScriptAction { script: {
222− if (root.application.screenshot) { root.application.discardScreenshot(); }
223− } }
229+ PropertyAction { target: screenshotImage; property: "visible"; value: false }
230+ PropertyAction { target: screenshotImage; property: "source"; value: "" }
224231 }
225232 }
226233 ]
tests/mocks/Unity/Application/ApplicationInfo.cpp+18−22
@@ -35,6 +35,7 @@ ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
3535 , m_focused(false)
3636 , m_fullscreen(false)
3737 , m_surface(0)
38+ , m_manualSurfaceCreation(false)
3839 , m_parentItem(0)
3940{
4041}
@@ -46,6 +47,7 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
4647 , m_focused(false)
4748 , m_fullscreen(false)
4849 , m_surface(0)
50+ , m_manualSurfaceCreation(false)
4951 , m_parentItem(0)
5052{
5153}
@@ -53,6 +55,9 @@ ApplicationInfo::ApplicationInfo(QObject *parent)
5355ApplicationInfo::~ApplicationInfo()
5456{
5557 if (m_surface) {
58+ // break the cyclic reference before destroying it
59+ m_surface->setApplication(nullptr);
60+
5661 Q_EMIT SurfaceManager::singleton()->surfaceDestroyed(m_surface);
5762 m_surface->deleteLater();
5863 }
@@ -62,10 +67,12 @@ void ApplicationInfo::createSurface()
6267{
6368 if (m_surface || state() == ApplicationInfo::Stopped) return;
6469
70+ QUrl screenshotUrl = QString("file://%1").arg(m_screenshotFileName);
71+
6572 setSurface(new MirSurfaceItem(name(),
6673 MirSurfaceItem::Normal,
6774 fullscreen() ? MirSurfaceItem::Fullscreen : MirSurfaceItem::Maximized,
68− m_screenshotUrl));
75+ screenshotUrl));
6976}
7077
7178void ApplicationInfo::setSurface(MirSurfaceItem* surface)
@@ -144,17 +151,6 @@ MirSurfaceItem* ApplicationInfo::promptSurfaceAt(QQmlListProperty<MirSurfaceItem
144151 return p->m_promptSurfaces[index];
145152}
146153
147−void ApplicationInfo::updateScreenshot()
148−{
149− qDebug() << "ApplicationInfo::updateScreenshot()";
150− setScreenshot(m_screenshotUrl);
151−}
152−
153−void ApplicationInfo::discardScreenshot()
154−{
155− setScreenshot(QUrl());
156−}
157−
158154void ApplicationInfo::setIconId(const QString &iconId)
159155{
160156 setIcon(QString("file://%1/graphics/applicationIcons/%2@18.png")
@@ -164,7 +160,7 @@ void ApplicationInfo::setIconId(const QString &iconId)
164160
165161void ApplicationInfo::setScreenshotId(const QString &screenshotId)
166162{
167− m_screenshotUrl = QString("file://%1/Dash/graphics/phone/screenshots/%2@12.png")
163+ m_screenshotFileName = QString("%1/Dash/graphics/phone/screenshots/%2@12.png")
168164 .arg(qmlDirectory())
169165 .arg(screenshotId);
170166}
@@ -199,7 +195,7 @@ void ApplicationInfo::setState(State value)
199195 m_state = value;
200196 Q_EMIT stateChanged(value);
201197
202− if (m_state == ApplicationInfo::Running) {
198+ if (!m_manualSurfaceCreation && m_state == ApplicationInfo::Running) {
203199 QTimer::singleShot(1000, this, SLOT(createSurface()));
204200 }
205201 }
@@ -213,14 +209,6 @@ void ApplicationInfo::setFocused(bool value)
213209 }
214210}
215211
216−void ApplicationInfo::setScreenshot(const QUrl &value)
217−{
218− if (value != m_screenshot) {
219− m_screenshot = value;
220− Q_EMIT screenshotChanged(value);
221− }
222−}
223−
224212void ApplicationInfo::setFullscreen(bool value)
225213{
226214 if (value != m_fullscreen) {
@@ -228,3 +216,11 @@ void ApplicationInfo::setFullscreen(bool value)
228216 Q_EMIT fullscreenChanged(value);
229217 }
230218}
219+
220+void ApplicationInfo::setManualSurfaceCreation(bool value)
221+{
222+ if (value != m_manualSurfaceCreation) {
223+ m_manualSurfaceCreation = value;
224+ Q_EMIT manualSurfaceCreationChanged(value);
225+ }
226+}
tests/mocks/Unity/Application/ApplicationInfo.h+13−8
@@ -37,14 +37,14 @@ class ApplicationInfo : public ApplicationInfoInterface {
3737
3838 // Only exists in this fake implementation
3939
40+ // whether the test code will explicitly control the creation of the application surface
41+ Q_PROPERTY(bool manualSurfaceCreation READ manualSurfaceCreation WRITE setManualSurfaceCreation NOTIFY manualSurfaceCreationChanged)
42+
4043public:
4144 ApplicationInfo(QObject *parent = NULL);
4245 ApplicationInfo(const QString &appId, QObject *parent = NULL);
4346 ~ApplicationInfo();
4447
45− Q_INVOKABLE void updateScreenshot() override;
46− Q_INVOKABLE void discardScreenshot() override;
47−
4848 void setIconId(const QString &iconId);
4949 void setScreenshotId(const QString &screenshotId);
5050
@@ -67,7 +67,7 @@ public:
6767 void setFocused(bool value);
6868 bool focused() const override { return m_focused; }
6969
70− QUrl screenshot() const override { return m_screenshot; }
70+ QString screenshot() const { return m_screenshotFileName; }
7171
7272 void setFullscreen(bool value);
7373 bool fullscreen() const { return m_fullscreen; }
@@ -81,13 +81,17 @@ public:
8181 QList<MirSurfaceItem*> promptSurfaceList() const;
8282 QQmlListProperty<MirSurfaceItem> promptSurfaces();
8383
84+ bool manualSurfaceCreation() const { return m_manualSurfaceCreation; }
85+ void setManualSurfaceCreation(bool value);
86+
8487Q_SIGNALS:
8588 void surfaceChanged(MirSurfaceItem*);
8689 void promptSurfacesChanged();
8790 void fullscreenChanged(bool value);
91+ void manualSurfaceCreationChanged(bool value);
8892
89−private Q_SLOTS:
90− void createSurface();
93+public Q_SLOTS:
94+ Q_INVOKABLE void createSurface();
9195
9296private:
9397 static int promptSurfaceCount(QQmlListProperty<MirSurfaceItem> *prop);
@@ -95,7 +99,7 @@ private:
9599 void setIcon(const QUrl &value);
96100 void setScreenshot(const QUrl &value);
97101
98− QUrl m_screenshotUrl;
102+ QString m_screenshotFileName;
99103
100104 QString m_appId;
101105 QString m_name;
@@ -103,10 +107,11 @@ private:
103107 Stage m_stage;
104108 State m_state;
105109 bool m_focused;
106− QUrl m_screenshot;
107110 bool m_fullscreen;
108111 MirSurfaceItem* m_surface;
109112
113+ bool m_manualSurfaceCreation;
114+
110115 QQuickItem *m_parentItem;
111116 QList<MirSurfaceItem*> m_promptSurfaces;
112117};
tests/mocks/Unity/Application/ApplicationManager.cpp+17−32
@@ -105,8 +105,6 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
105105 return app->state();
106106 case RoleFocused:
107107 return app->focused();
108− case RoleScreenshot:
109− return app->screenshot();
110108 case RoleSurface:
111109 return QVariant::fromValue(app->surface());
112110 case RoleFullscreen:
@@ -226,6 +224,21 @@ ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
226224 const QStringList &arguments)
227225{
228226 Q_UNUSED(arguments)
227+ ApplicationInfo *application = add(appId);
228+ if (!application)
229+ return 0;
230+
231+ if (flags.testFlag(ApplicationManager::ForceMainStage)
232+ && application->stage() == ApplicationInfo::SideStage) {
233+ application->setStage(ApplicationInfo::MainStage);
234+ }
235+ application->setState(ApplicationInfo::Running);
236+
237+ return application;
238+}
239+
240+ApplicationInfo* ApplicationManager::add(QString appId)
241+{
229242 ApplicationInfo *application = 0;
230243
231244 for (ApplicationInfo *availableApp : m_availableApplications) {
@@ -235,15 +248,8 @@ ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
235248 }
236249 }
237250
238− if (!application)
239− return 0;
240−
241− if (flags.testFlag(ApplicationManager::ForceMainStage)
242− && application->stage() == ApplicationInfo::SideStage) {
243− application->setStage(ApplicationInfo::MainStage);
244− }
245− add(application);
246− application->setState(ApplicationInfo::Running);
251+ if (application)
252+ add(application);
247253
248254 return application;
249255}
@@ -266,27 +272,6 @@ bool ApplicationManager::stopApplication(const QString &appId)
266272 return true;
267273}
268274
269−bool ApplicationManager::updateScreenshot(const QString &appId)
270−{
271− int idx = -1;
272− ApplicationInfo *application = nullptr;
273− for (int i = 0; i < m_availableApplications.count(); ++i) {
274− application = m_availableApplications.at(i);
275− if (application->appId() == appId) {
276− idx = i;
277− break;
278− }
279− }
280−
281− if (idx == -1) {
282− return false;
283− }
284−
285− QModelIndex appIndex = index(idx);
286− Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot);
287− return true;
288−}
289−
290275QString ApplicationManager::focusedApplicationId() const {
291276 for (ApplicationInfo *app : m_runningApplications) {
292277 if (app->focused()) {
tests/mocks/Unity/Application/ApplicationManager.h+2−2
@@ -52,7 +52,7 @@ class ApplicationManager : public ApplicationManagerInterface {
5252 static ApplicationManager *singleton();
5353
5454 enum MoreRoles {
55− RoleSurface = RoleScreenshot+1,
55+ RoleSurface = RoleFocused+1,
5656 RoleFullscreen,
5757 RoleApplication,
5858 };
@@ -98,7 +98,6 @@ class ApplicationManager : public ApplicationManagerInterface {
9898 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
9999 Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
100100 Q_INVOKABLE bool stopApplication(const QString &appId) override;
101− Q_INVOKABLE bool updateScreenshot(const QString &appId) override;
102101
103102 QString focusedApplicationId() const override;
104103 bool suspended() const;
@@ -106,6 +105,7 @@ class ApplicationManager : public ApplicationManagerInterface {
106105
107106 // Only for testing
108107 Q_INVOKABLE QStringList availableApplications();
108+ Q_INVOKABLE ApplicationInfo* add(QString appId);
109109
110110 QModelIndex findIndex(ApplicationInfo* application);
111111
tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp+4−4
@@ -34,6 +34,8 @@ ApplicationScreenshotProvider::ApplicationScreenshotProvider(ApplicationManager
3434QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize * size,
3535 const QSize &requestedSize)
3636{
37+ qDebug() << "AppScreenshotProvider::requestImage" << imageId;
38+
3739 // We ignore requestedSize here intentionally to avoid keeping scaled copies around
3840 Q_UNUSED(requestedSize)
3941
@@ -44,11 +46,9 @@ QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize
4446 return QImage();
4547 }
4648
47− QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString());
48−
4949 QImage image;
50− if (!image.load(filePath)) {
51− qWarning() << "failed loading app image" << filePath;
50+ if (!image.load(app->screenshot())) {
51+ qWarning() << "failed loading app image" << app->screenshot();
5252 }
5353
5454
tests/mocks/Unity/Application/MirSurfaceItem.cpp+4−9
@@ -46,14 +46,9 @@ MirSurfaceItem::MirSurfaceItem(const QString& name,
4646
4747 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
4848
49− // The virtual keyboard (input method) has a big transparent area so that
50− // content behind it show through
51− //setFillColor(Qt::transparent);
52−
5349 connect(this, &QQuickItem::focusChanged,
5450 this, &MirSurfaceItem::onFocusChanged);
5551
56−
5752 // The assumptions I make here really should hold.
5853 QQuickView *quickView =
5954 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
@@ -233,13 +228,13 @@ void MirSurfaceItem::onComponentStatusChanged(QQmlComponent::Status status)
233228
234229void MirSurfaceItem::createQmlContentItem()
235230{
231+ qDebug() << "MirSurfaceItem::createQmlContentItem()";
232+
236233 m_qmlItem = qobject_cast<QQuickItem*>(m_qmlContentComponent->create());
237234 m_qmlItem->setParentItem(this);
238235
239− {
240− QQmlProperty anchorsFill(m_qmlItem, "anchors.fill");
241− anchorsFill.write(QVariant::fromValue(this));
242− }
236+ setImplicitWidth(m_qmlItem->width());
237+ setImplicitHeight(m_qmlItem->height());
243238
244239 {
245240 QQmlProperty screenshotSource(m_qmlItem, "screenshotSource");
tests/mocks/Unity/Application/MirSurfaceItem.qml+9−1
@@ -17,13 +17,20 @@
1717import QtQuick 2.0
1818
1919Rectangle {
20+ objectName: "fakeSurfaceQML"
2021 id: root
2122 color: "yellow"
2223
24+ width: units.gu(40)
25+ height: units.gu(70)
26+
2327 property alias screenshotSource: screenshotImage.source
2428
2529 property bool wantInputMethod: false
2630
31+ property int touchPressCount: 0
32+ property int touchReleaseCount: 0
33+
2734 Image {
2835 id: screenshotImage
2936 anchors.fill: parent
@@ -41,6 +48,7 @@ Rectangle {
4148
4249 MultiPointTouchArea {
4350 anchors.fill: parent
44− onPressed: { root.wantInputMethod = true }
51+ onPressed: { root.wantInputMethod = true; root.touchPressCount++; }
52+ onReleased: { root.touchReleaseCount++; }
4553 }
4654}
tests/mocks/Unity/Application/VirtualKeyboard.qml+2
@@ -17,6 +17,8 @@
1717import QtQuick 2.0
1818
1919Item {
20+ width: units.gu(40)
21+ height: units.gu(70)
2022
2123 property alias screenshotSource: screenshotImage.source
2224
tests/plugins/Unity/Launcher/launchermodeltest.cpp−4
@@ -41,9 +41,6 @@ public:
4141 bool focused() const { return m_focused; }
4242 QUrl screenshot() const { return QUrl(); }
4343
44− Q_INVOKABLE void updateScreenshot() override {}
45− Q_INVOKABLE void discardScreenshot() override {}
46−
4744 // Methods used for mocking (not in the interface)
4845 void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
4946private:
@@ -96,7 +93,6 @@ public:
9693 m_list.takeAt(index)->deleteLater();
9794 endRemoveRows();
9895 }
99− bool updateScreenshot(const QString &appId) { Q_UNUSED(appId); return true; }
10096 bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; }
10197 bool suspended() const { return false; }
10298 void setSuspended(bool) {}
tests/qmltests/Stages/tst_ApplicationWindow.qml+24−69
@@ -29,68 +29,17 @@ Rectangle {
2929 width: units.gu(70)
3030 height: units.gu(70)
3131
32− Component {
33− id: fakeSurfaceComponent
34− Image {
35− source: "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png"
36− width: applicationWindowLoader.width
37− height: applicationWindowLoader.height
38−
39− property var application: fakeApplication
40− property int touchPressCount: 0
41− property int touchReleaseCount: 0
42−
43− Text {
44− anchors.fill: parent
45− text: "SURFACE"
46− color: "yellow"
47− font.bold: true
48− fontSizeMode: Text.Fit
49− minimumPixelSize: 10; font.pixelSize: 200
50− verticalAlignment: Text.AlignVCenter
51− }
52−
53− MultiPointTouchArea {
54− anchors.fill: parent
55− onPressed: { touchPressCount++; }
56− onReleased: { touchReleaseCount++; }
57− }
58−
59− signal removed()
60−
61− function release() {
62− fakeApplication.surface = null;
63− parent = null;
64− removed();
65− surfaceCheckbox.checked = false;
66− }
67− }
32+ Component.onCompleted: {
33+ root.fakeApplication = ApplicationManager.add("gallery-app");
34+ root.fakeApplication.manualSurfaceCreation = true;
35+ root.fakeApplication.setState(ApplicationInfo.Starting);
6836 }
37+ property QtObject fakeApplication: null
6938
70− QtObject {
71− id: fakeApplication
72− property url screenshot: ""
73−
74− function updateScreenshot() {
75− fakeScreenshotTimer.start();
76− }
77−
78− function discardScreenshot() {
79− screenshot = "";
80− }
81−
82− property alias state: appStateSelector.selectedApplicationState
83− property string name: "Gallery"
84− property url icon: "../../../qml/graphics/applicationIcons/gallery.png"
85− property var surface: null
86− property bool fullscreen: true
87− property list<Item> childSurfaces
88− }
89− Timer {
90− id: fakeScreenshotTimer
91− interval: 100
92− onTriggered: {
93− fakeApplication.screenshot = "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png";
39+ Connections {
40+ target: fakeApplication
41+ onSurfaceChanged: {
42+ surfaceCheckbox.checked = fakeApplication.surface !== null;
9443 }
9544 }
9645
@@ -133,7 +82,7 @@ Rectangle {
13382 return;
13483
13584 if (checked && !fakeApplication.surface) {
136− fakeApplication.surface = fakeSurfaceComponent.createObject(null, {});
85+ fakeApplication.createSurface();
13786 } else if (!checked && fakeApplication.surface) {
13887 fakeApplication.surface.release();
13988 }
@@ -160,6 +109,10 @@ Rectangle {
160109 return ApplicationInfo.Stopped;
161110 }
162111 }
112+ onSelectedApplicationStateChanged: {
113+ // state is a read-only property, thus we have to call the setter function
114+ fakeApplication.setState(selectedApplicationState);
115+ }
163116 }
164117 }
165118 }
@@ -199,9 +152,8 @@ Rectangle {
199152 appStateSelector.selectedIndex = 0;
200153 surfaceCheckbox.checked = false;
201154
202− fakeScreenshotTimer.stop();
203− fakeApplication.screenshot = "";
204− fakeApplication.surface = null;
155+ if (fakeApplication.surface)
156+ fakeApplication.surface.release();
205157
206158 applicationWindowLoader.active = true;
207159 }
@@ -270,6 +222,7 @@ Rectangle {
270222
271223 function test_restartApp() {
272224 var stateGroup = findInvisibleChild(applicationWindowLoader.item, "applicationWindowStateGroup");
225+ var screenshotImage = findChild(applicationWindowLoader.item, "screenshotImage");
273226
274227 surfaceCheckbox.checked = true;
275228 setApplicationState(appRunning);
@@ -298,7 +251,7 @@ Rectangle {
298251 surfaceCheckbox.checked = true;
299252
300253 tryCompare(stateGroup, "state", "surface");
301− tryCompare(fakeApplication, "screenshot", "");
254+ tryCompare(screenshotImage, "status", Image.Null);
302255 }
303256
304257 function test_appCrashed() {
@@ -347,14 +300,16 @@ Rectangle {
347300 // wait until any transition animation has finished
348301 tryCompare(stateGroup, "transitioning", false, 2000);
349302
350− fakeApplication.surface.touchPressCount = 0;
351− fakeApplication.surface.touchReleaseCount = 0;
303+ // Because doing stuff in C++ is a PITA we keep the counter in the interal qml impl.
304+ var fakeSurface = findChild(fakeApplication.surface, "fakeSurfaceQML");
305+ fakeSurface.touchPressCount = 0;
306+ fakeSurface.touchReleaseCount = 0;
352307
353308 tap(applicationWindowLoader.item,
354309 applicationWindowLoader.item.width / 2, applicationWindowLoader.item.height / 2);
355310
356− verify(fakeApplication.surface.touchPressCount === 1);
357− verify(fakeApplication.surface.touchReleaseCount === 1);
311+ verify(fakeSurface.touchPressCount === 1);
312+ verify(fakeSurface.touchReleaseCount === 1);
358313 }
359314 }
360315}
tests/qmltests/Stages/tst_SpreadDelegate.qml+3−23
@@ -29,30 +29,10 @@ Rectangle {
2929 width: units.gu(70)
3030 height: units.gu(70)
3131
32− QtObject {
33− id: fakeApplication
34− property url screenshot: ""
35−
36− function updateScreenshot() {}
37− function discardScreenshot() {}
38−
39− property int state: ApplicationInfo.Running
40− property string name: "Gallery"
41− property url icon: "../../../qml/graphics/applicationIcons/gallery.png"
42−
43− property var surface: Image {
44− source: "../../../qml/Dash/graphics/phone/screenshots/gallery@12.png"
45− width: spreadDelegateLoader.width
46− height: spreadDelegateLoader.height
47−
48− property var application: fakeApplication
49−
50− signal removed()
51− function release() {}
52− }
53−
54− property bool fullscreen: true
32+ Component.onCompleted: {
33+ root.fakeApplication = ApplicationManager.startApplication("gallery-app");
5534 }
35+ property QtObject fakeApplication: null
5636
5737 Component {
5838 id: spreadDelegateComponent