on xenial help sign in
More autopilot for indicators
8c60ce9Nick Dedekind
plugins/IndicatorsClient/client/indicatorsclient.cpp+2−2
@@ -45,7 +45,7 @@ void IndicatorsClient::setupUI()
45{
45{
46 m_view = new QQuickView;
46 m_view = new QQuickView;
47
47
48− m_view->setSource(QUrl("qrc:qml/indicatorsclient.qml"));
48+ m_view->setSource(QUrl("qrc:qml/IndicatorsClient.qml"));
49 m_view->setResizeMode(QQuickView::SizeRootObjectToView);
49 m_view->setResizeMode(QQuickView::SizeRootObjectToView);
50
50
51 //Usable size on desktop
51 //Usable size on desktop
@@ -55,6 +55,6 @@ void IndicatorsClient::setupUI()
55int IndicatorsClient::run()
55int IndicatorsClient::run()
56{
56{
57 setupUI();
57 setupUI();
58− m_view->showMaximized();
58+ m_view->show();
59 return m_application->exec();
59 return m_application->exec();
60}
60}
plugins/IndicatorsClient/client/indicatorsclient.qrc+3−3
@@ -1,7 +1,7 @@
1<RCC>
1<RCC>
2 <qresource prefix="/">
2 <qresource prefix="/">
3− <file>qml/indicatorsclient.qml</file>
3+ <file>qml/IndicatorsClient.qml</file>
4− <file>qml/indicatorslist.qml</file>
4+ <file>qml/IndicatorsList.qml</file>
5− <file>qml/indicatorspage.qml</file>
5+ <file>qml/IndicatorsPage.qml</file>
6 </qresource>
6 </qresource>
7</RCC>
7</RCC>
plugins/IndicatorsClient/client/qml/indicatorsclient.qml → plugins/IndicatorsClient/client/qml/IndicatorsClient.qmlrenamed+9−1
@@ -23,10 +23,18 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
23
23
24Rectangle {
24Rectangle {
25 color: "black"
25 color: "black"
26+ id: root
27+
26 PageStack {
28 PageStack {
27 id: pages
29 id: pages
28
30
29 anchors.fill: parent
31 anchors.fill: parent
30− Component.onCompleted: push(Qt.createComponent("indicatorslist.qml"))
32+ Component.onCompleted: root.reset()
33+ }
34+
35+ function reset() {
36+ pages.clear();
37+ var component = Qt.createComponent("IndicatorsList.qml")
38+ pages.push(component.createObject(pages));
31 }
39 }
32}
40}
plugins/IndicatorsClient/client/qml/indicatorslist.qml → plugins/IndicatorsClient/client/qml/IndicatorsList.qmlrenamed+4−3
@@ -35,6 +35,7 @@ Page {
35
35
36 ListView {
36 ListView {
37 id: mainMenu
37 id: mainMenu
38+ objectName: "mainMenu"
38 anchors.fill: parent
39 anchors.fill: parent
39 model: indicators
40 model: indicators
40
41
@@ -43,7 +44,7 @@ Page {
43 anchors.right: parent.right
44 anchors.right: parent.right
44 height: implicitHeight
45 height: implicitHeight
45 progression: isValid
46 progression: isValid
46− objectName: title
47+ objectName: identifier
47
48
48 // Used basic components instead of 'ListItem.Standard' properties because it does not support image resize
49 // Used basic components instead of 'ListItem.Standard' properties because it does not support image resize
49 Image {
50 Image {
@@ -68,8 +69,8 @@ Page {
68 var props = model.initialProperties
69 var props = model.initialProperties
69 props["widgetsMap"] = indicators.widgetsMap
70 props["widgetsMap"] = indicators.widgetsMap
70
71
71− var page = Qt.createComponent("indicatorspage.qml")
72+ var page = Qt.createComponent("IndicatorsPage.qml")
72− pages.push(page, {"initialProperties" : props, "component" : model.component})
73+ pages.push(page.createObject(pages), {"initialProperties" : props, "component" : model.component})
73 }
74 }
74 }
75 }
75 }
76 }
plugins/IndicatorsClient/client/qml/indicatorspage.qml → plugins/IndicatorsClient/client/qml/IndicatorsPage.qmlrenamed+3−2
@@ -25,12 +25,13 @@ Page {
25
25
26 title: initialProperties && initialProperties.title ? initialProperties.title : ""
26 title: initialProperties && initialProperties.title ? initialProperties.title : ""
27 property variant initialProperties
27 property variant initialProperties
28− property alias component : _loader.sourceComponent
28+ property alias component : page_loader.sourceComponent
29
29
30 anchors.fill: parent
30 anchors.fill: parent
31
31
32 Loader {
32 Loader {
33− id: _loader
33+ id: page_loader
34+ objectName: "page_loader"
34
35
35 anchors.fill: parent
36 anchors.fill: parent
36
37
plugins/IndicatorsClient/indicatorclientinterface.h+8−1
@@ -56,6 +56,14 @@ public:
56 */
56 */
57 virtual void shutdown() = 0;
57 virtual void shutdown() = 0;
58
58
59+ /**
60+ * @brief Used to retrieve the current plugin identifier
61+ * @return The identifier
62+ *
63+ * This function can be used to retrieve the indicator identifier
64+ */
65+ virtual QString identifier() const = 0;
66+
59 /**
67 /**
60 * @brief Used to retrieve the current plugin icon
68 * @brief Used to retrieve the current plugin icon
61 * @return The icon url
69 * @return The icon url
@@ -64,7 +72,6 @@ public:
64 */
72 */
65 virtual QUrl icon() const = 0;
73 virtual QUrl icon() const = 0;
66
74
67−
68 /**
75 /**
69 * @brief Used to retrieve the current plugin title
76 * @brief Used to retrieve the current plugin title
70 * @return The title
77 * @return The title
plugins/IndicatorsClient/indicators/common/indicatorclient_common.cpp+14
@@ -57,6 +57,7 @@ void IndicatorClientCommon::init(const QSettings& settings)
57{
57{
58 Q_INIT_RESOURCE(indicatorclient_common);
58 Q_INIT_RESOURCE(indicatorclient_common);
59
59
60+ setId(settings.value("Indicator Service/Name").toString());
60 QString dbusService = settings.value("Indicator Service/DBusName").toString();
61 QString dbusService = settings.value("Indicator Service/DBusName").toString();
61 QString objectPath = settings.value("Indicator Service/ObjectPath").toString();
62 QString objectPath = settings.value("Indicator Service/ObjectPath").toString();
62
63
@@ -165,6 +166,19 @@ void IndicatorClientCommon::shutdown()
165 m_actionGroup = 0;
166 m_actionGroup = 0;
166}
167}
167
168
169+QString IndicatorClientCommon::identifier() const
170+{
171+ return m_identifier;
172+}
173+
174+void IndicatorClientCommon::setId(const QString &identifier)
175+{
176+ if (identifier != m_identifier) {
177+ m_identifier = identifier;
178+ Q_EMIT identifierChanged(m_identifier);
179+ }
180+}
181+
168QUrl IndicatorClientCommon::icon() const
182QUrl IndicatorClientCommon::icon() const
169{
183{
170 if (!m_icon.isEmpty() && m_icon.scheme().isEmpty()) {
184 if (!m_icon.isEmpty() && m_icon.scheme().isEmpty()) {
plugins/IndicatorsClient/indicators/common/indicatorclient_common.h+5
@@ -31,6 +31,7 @@ class QStateAction;
31class IndicatorClientCommon : public QObject, public IndicatorClientInterface
31class IndicatorClientCommon : public QObject, public IndicatorClientInterface
32{
32{
33 Q_OBJECT
33 Q_OBJECT
34+ Q_PROPERTY(QString identifier READ identifier NOTIFY identifierChanged)
34 Q_PROPERTY(QString title READ title NOTIFY titleChanged)
35 Q_PROPERTY(QString title READ title NOTIFY titleChanged)
35 Q_PROPERTY(QString label READ label NOTIFY labelChanged)
36 Q_PROPERTY(QString label READ label NOTIFY labelChanged)
36 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
37 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
@@ -46,6 +47,7 @@ public:
46 void init(const QSettings& settings);
47 void init(const QSettings& settings);
47 void shutdown();
48 void shutdown();
48
49
50+ QString identifier() const;
49 QUrl icon() const;
51 QUrl icon() const;
50 QString title() const;
52 QString title() const;
51 bool visible() const;
53 bool visible() const;
@@ -59,6 +61,7 @@ public:
59 WidgetsMap widgets();
61 WidgetsMap widgets();
60
62
61Q_SIGNALS:
63Q_SIGNALS:
64+ void identifierChanged(const QString &identifier);
62 void iconChanged(const QUrl &icon);
65 void iconChanged(const QUrl &icon);
63 void titleChanged(const QString &title);
66 void titleChanged(const QString &title);
64 void visibleChanged(bool visible);
67 void visibleChanged(bool visible);
@@ -70,6 +73,7 @@ Q_SIGNALS:
70protected:
73protected:
71 PropertiesMap m_initialProperties;
74 PropertiesMap m_initialProperties;
72
75
76+ void setId(const QString &id);
73 void setIcon(const QUrl &icon);
77 void setIcon(const QUrl &icon);
74 void setTitle(const QString &title);
78 void setTitle(const QString &title);
75 void setDescription(const QString &description);
79 void setDescription(const QString &description);
@@ -86,6 +90,7 @@ private Q_SLOTS:
86 void updateState(const QVariant &state);
90 void updateState(const QVariant &state);
87
91
88private:
92private:
93+ QString m_identifier;
89 QUrl m_icon;
94 QUrl m_icon;
90 QString m_title;
95 QString m_title;
91 QString m_description;
96 QString m_description;
plugins/IndicatorsClient/indicatorsmodel.cpp+16−2
@@ -70,8 +70,9 @@ IndicatorsModel::IndicatorsModel(QObject *parent)
70/*! \internal */
70/*! \internal */
71IndicatorsModel::~IndicatorsModel()
71IndicatorsModel::~IndicatorsModel()
72{
72{
73+ disconnect(m_manager, 0, 0, 0);
74+ m_manager->deleteLater();
73− delete m_widgetsMap;
75+ m_widgetsMap->deleteLater();
74− delete m_manager;
75}
76}
76
77
77/*!
78/*!
@@ -155,6 +156,7 @@ void IndicatorsModel::onIndicatorLoaded(const QString& indicator)
155 QObject* obj = dynamic_cast<QObject*>(plugin.get());
156 QObject* obj = dynamic_cast<QObject*>(plugin.get());
156 if (obj)
157 if (obj)
157 {
158 {
159+ QObject::connect(obj, SIGNAL(idChanged(const QString&)), this, SLOT(onIdChanged()));
158 QObject::connect(obj, SIGNAL(iconChanged(const QUrl&)), this, SLOT(onIconChanged()));
160 QObject::connect(obj, SIGNAL(iconChanged(const QUrl&)), this, SLOT(onIconChanged()));
159 QObject::connect(obj, SIGNAL(titleChanged(const QString&)), this, SLOT(onTitleChanged()));
161 QObject::connect(obj, SIGNAL(titleChanged(const QString&)), this, SLOT(onTitleChanged()));
160 QObject::connect(obj, SIGNAL(labelChanged(const QString&)), this, SLOT(onLabelChanged()));
162 QObject::connect(obj, SIGNAL(labelChanged(const QString&)), this, SLOT(onLabelChanged()));
@@ -189,6 +191,12 @@ void IndicatorsModel::onIndicatorAboutToBeUnloaded(const QString& indicator)
189
191
190}
192}
191
193
194+/*! \internal */
195+void IndicatorsModel::onIdChanged()
196+{
197+ notifyDataChanged(QObject::sender(), Identifier);
198+}
199+
192/*! \internal */
200/*! \internal */
193void IndicatorsModel::onIconChanged()
201void IndicatorsModel::onIconChanged()
194{
202{
@@ -233,6 +241,7 @@ QHash<int, QByteArray> IndicatorsModel::roleNames() const
233{
241{
234 static QHash<int, QByteArray> roles;
242 static QHash<int, QByteArray> roles;
235 if (roles.isEmpty()) {
243 if (roles.isEmpty()) {
244+ roles[Identifier] = "identifier";
236 roles[Title] = "title";
245 roles[Title] = "title";
237 roles[IconSource] = "iconSource";
246 roles[IconSource] = "iconSource";
238 roles[Label] = "label";
247 roles[Label] = "label";
@@ -261,6 +270,11 @@ QVariant IndicatorsModel::data(const QModelIndex &index, int role) const
261 IndicatorClientInterface::Ptr plugin = m_plugins[index.row()];
270 IndicatorClientInterface::Ptr plugin = m_plugins[index.row()];
262
271
263 switch (role) {
272 switch (role) {
273+ case Identifier:
274+ if (plugin) {
275+ attribute = QVariant(plugin->identifier());
276+ }
277+ break;
264 case Title:
278 case Title:
265 if (plugin) {
279 if (plugin) {
266 attribute = QVariant(plugin->title());
280 attribute = QVariant(plugin->title());
plugins/IndicatorsClient/indicatorsmodel.h+3−1
@@ -37,7 +37,8 @@ class IndicatorsModel : public QAbstractListModel
37
37
38public:
38public:
39 enum ModelRoles {
39 enum ModelRoles {
40− Title = 0,
40+ Identifier = 0,
41+ Title,
41 IconSource,
42 IconSource,
42 Label,
43 Label,
43 Description,
44 Description,
@@ -68,6 +69,7 @@ Q_SIGNALS:
68 void countChanged();
69 void countChanged();
69
70
70private Q_SLOTS:
71private Q_SLOTS:
72+ void onIdChanged();
71 void onIconChanged();
73 void onIconChanged();
72 void onTitleChanged();
74 void onTitleChanged();
73 void onLabelChanged();
75 void onLabelChanged();
plugins/IndicatorsClient/qml/FactoryMenu.qml+1
@@ -40,6 +40,7 @@ Item {
40 if (!__menuFactory.menu || !__menuFactory.menu.extra || !__menuFactory.widgetsMap) {
40 if (!__menuFactory.menu || !__menuFactory.menu.extra || !__menuFactory.widgetsMap) {
41 return ''
41 return ''
42 }
42 }
43+
43 var widgetType = __menuFactory.menu.extra.canonical_type
44 var widgetType = __menuFactory.menu.extra.canonical_type
44 var sourceFile = null
45 var sourceFile = null
45 if (widgetType) {
46 if (widgetType) {
plugins/IndicatorsClient/qml/Menu.qml+1−1
@@ -23,7 +23,7 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
23
23
24BasicMenu {
24BasicMenu {
25 id: __menu
25 id: __menu
26−
26+ objectName: menu ? menu.action : ""
27 progression: menu && (menu.linkSubMenu !== undefined)
27 progression: menu && (menu.linkSubMenu !== undefined)
28 text: menu && menu.label ? menu.label : ""
28 text: menu && menu.label ? menu.label : ""
29 color: "#221e1c"
29 color: "#221e1c"
plugins/IndicatorsClient/qml/ProgressMenu.qml+2
@@ -22,6 +22,8 @@ import Ubuntu.Components 0.1
22
22
23Menu {
23Menu {
24
24
25+ property alias value : progressBar.value
26+
25 // TODO: Replace this with the official ProgressBar component as soon as
27 // TODO: Replace this with the official ProgressBar component as soon as
26 // it is available. For now, this rebuilds the Mockup as close as possible.
28 // it is available. For now, this rebuilds the Mockup as close as possible.
27 UbuntuShape {
29 UbuntuShape {
plugins/IndicatorsClient/qml/SwitchMenu.qml+4
@@ -21,6 +21,10 @@ import QtQuick 2.0
21import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
22
22
23Menu {
23Menu {
24+ id: _switchMenu
25+
26+ property alias checked: switcher.checked
27+
24 control: Switch {
28 control: Switch {
25 id: switcher
29 id: switcher
26
30
tests/autopilot/indicators_client/emulators/__init__.py+25
@@ -4,3 +4,28 @@
4# This program is free software: you can redistribute it and/or modify it
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
6# by the Free Software Foundation.
7+
8+from autopilot.introspection.dbus import DBusIntrospectionObject
9+from autopilot.input import Mouse, Touch, Pointer
10+from autopilot.platform import model
11+
12+from time import sleep
13+
14+from autopilot.introspection.dbus import IntrospectableObjectMetaclass
15+
16+class IndicatorsIntrospectionObject(DBusIntrospectionObject):
17+
18+ """A common class that provides introspection and other helpers to indictors."""
19+
20+ if model() == 'Desktop':
21+ scenarios = [
22+ ('with mouse', dict(input_device_class=Mouse)),
23+ ]
24+ else:
25+ scenarios = [
26+ ('with touch', dict(input_device_class=Touch)),
27+ ]
28+
29+ def setUp(self):
30+ self.pointing_device = Pointer(self.input_device_class.create())
31+ super(IndicatorsTestCase, self).setUp()
tests/autopilot/indicators_client/emulators/common.pynew file+14
@@ -0,0 +1,14 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+# Copyright 2013 Canonical
3+#
4+# This program is free software: you can redistribute it and/or modify it
5+# under the terms of the GNU General Public License version 3, as published
6+# by the Free Software Foundation.
7+
8+from indicators_client.emulators import IndicatorsIntrospectionObject
9+
10+class SwitchMenu(IndicatorsIntrospectionObject):
11+ """A switch menu control."""
12+
13+ def get_checked(self):
14+ return self.checked
tests/autopilot/indicators_client/emulators/main_window.py+15−4
@@ -5,14 +5,25 @@
5# under the terms of the GNU General Public License version 3, as published
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
6# by the Free Software Foundation.
7
7
8+from indicators_client.emulators import IndicatorsIntrospectionObject
9+
8class MainWindow(object):
10class MainWindow(object):
9 """An emulator class that makes it easy to interact with the shell"""
11 """An emulator class that makes it easy to interact with the shell"""
10
12
11 def __init__(self, app):
13 def __init__(self, app):
12 self.app = app
14 self.app = app
13
15
14− def get_panel(self):
16+ def get_qml_view(self):
17+ """Get the main QML view"""
18+ return self.app.select_single("QQuickView")
19+
20+ def get_indicators_client(self):
21+ return self.app.select_single("IndicatorsClient")
22+
23+ def get_page_stack(self):
24+ """Get the page stack"""
15− return self.app.select_single("Panel")
25+ return self.app.select_single("PageStack")
16
26
17− def get_indicator(self):
27+ def get_power_menu(self):
28+ """Get the power menu from the list"""
18− return self.app.select_single("Indicator")
29+ return self.app.select_single("BasicMenu", objectName="indicator-power");
tests/autopilot/indicators_client/tests/__init__.py+22−7
@@ -9,29 +9,44 @@
9
9
10import os.path
10import os.path
11
11
12+from autopilot.input import Mouse, Touch, Pointer
12from autopilot.testcase import AutopilotTestCase
13from autopilot.testcase import AutopilotTestCase
13from autopilot.matchers import Eventually
14from autopilot.matchers import Eventually
14from autopilot.platform import model
15from autopilot.platform import model
15from testtools.matchers import Equals
16from testtools.matchers import Equals
16
17
17from indicators_client.emulators.main_window import MainWindow
18from indicators_client.emulators.main_window import MainWindow
19+from logging import getLogger
20+import sys
21+from time import sleep
22+
23+log = getLogger(__name__)
18
24
19class FormFactors(object):
25class FormFactors(object):
20 Phone, Tablet, Desktop = range(3)
26 Phone, Tablet, Desktop = range(3)
21
27
22class IndicatorsTestCase(AutopilotTestCase):
28class IndicatorsTestCase(AutopilotTestCase):
23
29
24− """A common test case class that provides several useful methods for shell tests."""
30+ """A common test case class that provides several useful methods for indicator tests."""
31+
32+ if model() == 'Desktop':
33+ scenarios = [
34+ ('with mouse', dict(input_device_class=Mouse)),
35+ ]
36+ else:
37+ scenarios = [
38+ ('with touch', dict(input_device_class=Touch)),
39+ ]
25
40
26− def setUp(self, geometry, grid_size):
41+ def setUp(self):
27− super(ShellTestCase, self).setUp()
42+ self.pointing_device = Pointer(self.input_device_class.create())
28− self.launch_test_local(geometry)
43+ self.launch_test_local()
44+ super(IndicatorsTestCase, self).setUp()
29
45
30− def launch_test_local(self, geometry):
46+ def launch_test_local(self):
31 os.environ['LD_LIBRARY_PATH'] = "../../../unity_build/build/lib"
47 os.environ['LD_LIBRARY_PATH'] = "../../../unity_build/build/lib"
32 os.environ['QML2_IMPORT_PATH'] = "../../builddir/plugins:../../builddir/tests/mocks"
48 os.environ['QML2_IMPORT_PATH'] = "../../builddir/plugins:../../builddir/tests/mocks"
33− self.app = self.launch_test_application(
34− "../../builddir/plugins/IndicatorsClient/client/indicators-client")
49+ self.app = self.launch_test_application("../../builddir/plugins/IndicatorsClient/client/indicators-client")
35
50
36 def skipWrapper(*args, **kwargs):
51 def skipWrapper(*args, **kwargs):
37 pass
52 pass
tests/autopilot/indicators_client/tests/test_power.pynew file+48
@@ -0,0 +1,48 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+# Copyright 2013 Canonical
3+#
4+# This program is free software: you can redistribute it and/or modify it
5+# under the terms of the GNU General Public License version 3, as published
6+# by the Free Software Foundation.
7+
8+"""Add tests here if you want to ensure the behaviour of the power indicator menus are correct"""
9+
10+from testtools.matchers import Equals, NotEquals
11+from autopilot.matchers import Eventually
12+
13+from indicators_client.tests import IndicatorsTestCase
14+from indicators_client.emulators.common import SwitchMenu
15+from time import sleep
16+
17+class TestDisplayMenus(IndicatorsTestCase):
18+ def setUp(self):
19+ super(TestDisplayMenus, self).setUp()
20+
21+ # This opens the messaging menu so you don't have to do that in
22+ # every test case
23+ power = self.main_window.get_power_menu()
24+ self.pointing_device.move_to_object(power)
25+ self.pointing_device.click()
26+
27+ self.page = self.app.select_single("IndicatorsPage");
28+ page_loader = self.app.select_single("IndicatorsPage/QQuickLoader", objectName="page_loader");
29+ self.assertThat(page_loader.progress, Eventually(Equals(1.0)))
30+
31+ def tearDown(self):
32+ # self.main_window.get_indicators_client().reset()
33+ super(TestDisplayMenus, self).tearDown()
34+
35+ def test_auto_bright_switch(self):
36+ """Test the auto-bright switch"""
37+
38+ auto_brightness = self.app.select_single("SwitchMenu", objectName="auto-brightness")
39+ self.assertThat(auto_brightness, NotEquals(None))
40+
41+ old_value = auto_brightness.checked
42+
43+ print auto_brightness.get_checked()
44+
45+
46+
47+
48+