on xenial help sign in
Add Scope::isActive property and corresponding tests. Fixes: https://bugs.launchpad.net/bugs/1230352.

Approved by PS Jenkins bot, Michał Sawicz.

commit93221a703ba8c64d6f39d8ace094b5d19f976a9f authorMichał Sawicz <michal.sawicz@canonical.com> dateTue 8 Oct 2013, 12:50 (13 years ago) parent00ff8e23059be9
15 files changed+171−27
Dash/Dash.qml+3 Dash/DashContent.qml+1−1 Dash/GenericScopeView.qml+1 Dash/ScopeView.qml+11−3 Panel/Panel.qml+1 plugins/Unity/CMakeLists.txt+1−1 plugins/Unity/scope.cpp+43−6 plugins/Unity/scope.h+7 tests/mocks/Unity/fake_scope.cpp+13 tests/mocks/Unity/fake_scope.h+5 tests/plugins/Unity/CMakeLists.txt+1−1 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Dash/qml/FakeScopeView.qml+3−9 tests/qmltests/Dash/tst_DashContent.qml+29−5 tests/qmltests/tst_Shell.qml+51
Dash/Dash.qml+3
@@ -22,6 +22,9 @@ import "../Components"
2222
2323Showable {
2424 id: dash
25+ objectName: "dash"
26+
27+ visible: shown
2528
2629 property alias contentProgress: dashContent.contentProgress
2730 property string showScopeOnLoaded: "home.scope"
Dash/DashContent.qml+1−1
@@ -123,7 +123,7 @@ Item {
123123
124124 onLoaded: {
125125 item.scope = Qt.binding(function() { return scope })
126− item.isCurrent = Qt.binding(function() { return ListView.isCurrentItem })
126+ item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
127127 item.searchHistory = Qt.binding(function() { return shell.searchHistory })
128128 dashContentList.movementStarted.connect(item.movementStarted)
129129 dashContent.positionedAtBeginning.connect(item.positionedAtBeginning)
Dash/GenericScopeView.qml+1
@@ -97,6 +97,7 @@ ScopeView {
9797 // TODO: the running apps grid doesn't support standard scope results model yet
9898 item.firstModel = Qt.binding(function() { return results.firstModel })
9999 item.secondModel = Qt.binding(function() { return results.secondModel })
100+ item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
100101 } else {
101102 item.model = Qt.binding(function() { return results })
102103 }
Dash/ScopeView.qml+11−3
@@ -31,14 +31,22 @@ FocusScope {
3131 // FIXME delay the search so that daemons have time to settle, note that
3232 // removing this will break ScopeView::test_changeScope
3333 onScopeChanged: {
34− timer.restart();
35− scope.activateApplication.connect(activateApp);
34+ if (scope) {
35+ timer.restart();
36+ scope.activateApplication.connect(activateApp);
37+ }
3638 }
3739
3840 function activateApp(desktopFilePath) {
3941 shell.activateApplication(desktopFilePath);
4042 }
4143
44+ Binding {
45+ target: scope
46+ property: "isActive"
47+ value: isCurrent
48+ }
49+
4250 Timer {
4351 id: timer
4452 interval: 2000
@@ -47,7 +55,7 @@ FocusScope {
4755
4856 SortFilterProxyModel {
4957 id: categoryFilter
50− model: scope.categories
58+ model: scope ? scope.categories : null
5159 dynamicSortFilter: true
5260 filterRole: Categories.RoleCount
5361 filterRegExp: /^0$/
Panel/Panel.qml+1
@@ -73,6 +73,7 @@ Item {
7373
7474 Indicators {
7575 id: indicatorsMenu
76+ objectName: "indicators"
7677
7778 anchors.right: parent.right
7879 y: panelBackground.y
plugins/Unity/CMakeLists.txt+1−1
@@ -6,7 +6,7 @@ add_subdirectory(Indicators)
66# Dependencies
77include(FindPkgConfig)
88pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
9−pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
9+pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0>=7.1.1)
1010
1111include_directories(
1212 ${CMAKE_CURRENT_SOURCE_DIR}
plugins/Unity/scope.cpp+43−6
@@ -43,6 +43,8 @@ Scope::Scope(QObject *parent) : QObject(parent)
4343 , m_searchInProgress(false)
4444{
4545 m_categories.reset(new Categories(this));
46+
47+ connect(this, &Scope::isActiveChanged, this, &Scope::scopeIsActiveChanged);
4648}
4749
4850QString Scope::id() const
@@ -110,6 +112,11 @@ QString Scope::formFactor() const
110112 return m_formFactor;
111113}
112114
115+bool Scope::isActive() const
116+{
117+ return m_isActive;
118+}
119+
113120Filters* Scope::filters() const
114121{
115122 return m_filters.get();
@@ -127,10 +134,12 @@ void Scope::setSearchQuery(const QString& search_query)
127134 if (m_searchQuery.isNull() || search_query != m_searchQuery) {
128135 m_searchQuery = search_query;
129136 m_cancellable.Renew();
130− m_searchInProgress = true;
131137 m_unityScope->Search(search_query.toStdString(), std::bind(&Scope::onSearchFinished, this, _1, _2, _3), m_cancellable);
132138 Q_EMIT searchQueryChanged();
133− Q_EMIT searchInProgressChanged();
139+ if (!m_searchInProgress) {
140+ m_searchInProgress = true;
141+ Q_EMIT searchInProgressChanged();
142+ }
134143 }
135144}
136145
@@ -152,6 +161,13 @@ void Scope::setFormFactor(const QString& form_factor) {
152161 }
153162}
154163
164+void Scope::setActive(const bool active) {
165+ if (active != m_isActive) {
166+ m_isActive = active;
167+ Q_EMIT isActiveChanged(m_isActive);
168+ }
169+}
170+
155171unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
156172 const QVariant &category, const QVariant &result_type,
157173 const QVariant &mimetype, const QVariant &title,
@@ -306,6 +322,7 @@ void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
306322 m_unityScope->visible.changed.connect(sigc::mem_fun(this, &Scope::visibleChanged));
307323 m_unityScope->shortcut.changed.connect(sigc::mem_fun(this, &Scope::shortcutChanged));
308324 m_unityScope->connected.changed.connect(sigc::mem_fun(this, &Scope::connectedChanged));
325+ m_unityScope->results_dirty.changed.connect(sigc::mem_fun(this, &Scope::resultsDirtyToggled));
309326
310327 /* FIXME: signal should be forwarded instead of calling the handler directly */
311328 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
@@ -332,13 +349,31 @@ void Scope::synchronizeStates()
332349 /* Forward local states to m_unityScope */
333350 if (!m_searchQuery.isNull()) {
334351 m_cancellable.Renew();
335− m_searchInProgress = true;
336352 m_unityScope->Search(m_searchQuery.toStdString(), std::bind(&Scope::onSearchFinished, this, _1, _2, _3), m_cancellable);
337− Q_EMIT searchInProgressChanged();
353+ if (!m_searchInProgress) {
354+ m_searchInProgress = true;
355+ Q_EMIT searchInProgressChanged();
356+ }
338357 }
339358 }
340359}
341360
361+void Scope::scopeIsActiveChanged()
362+{
363+ if (!isActive() || !m_unityScope || !m_unityScope->results_dirty()) return;
364+
365+ // force new search
366+ synchronizeStates();
367+}
368+
369+void Scope::resultsDirtyToggled(bool results_dirty)
370+{
371+ if (!results_dirty || !isActive()) return;
372+
373+ // force new search
374+ synchronizeStates();
375+}
376+
342377void Scope::onSearchFinished(std::string const& /* query */, unity::glib::HintsMap const& hints, unity::glib::Error const& err)
343378{
344379 QString hint;
@@ -346,8 +381,10 @@ void Scope::onSearchFinished(std::string const& /* query */, unity::glib::HintsM
346381 GError* error = const_cast<unity::glib::Error&>(err);
347382
348383 if (!err || !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
349− m_searchInProgress = false;
350− Q_EMIT searchInProgressChanged();
384+ if (m_searchInProgress) {
385+ m_searchInProgress = false;
386+ Q_EMIT searchInProgressChanged();
387+ }
351388 } else {
352389 // no need to check the results hint, we're still searching
353390 return;
plugins/Unity/scope.h+7
@@ -54,6 +54,7 @@ class Scope : public QObject
5454 Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
5555 Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
5656 Q_PROPERTY(QString formFactor READ formFactor WRITE setFormFactor NOTIFY formFactorChanged)
57+ Q_PROPERTY(bool isActive READ isActive WRITE setActive NOTIFY isActiveChanged)
5758
5859public:
5960 explicit Scope(QObject *parent = 0);
@@ -73,11 +74,13 @@ public:
7374 QString searchQuery() const;
7475 QString noResultsHint() const;
7576 QString formFactor() const;
77+ bool isActive() const;
7678
7779 /* setters */
7880 void setSearchQuery(const QString& search_query);
7981 void setNoResultsHint(const QString& hint);
8082 void setFormFactor(const QString& form_factor);
83+ void setActive(const bool);
8184
8285 Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
8386 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
@@ -106,6 +109,7 @@ Q_SIGNALS:
106109 void searchQueryChanged();
107110 void noResultsHintChanged();
108111 void formFactorChanged();
112+ void isActiveChanged(bool);
109113 void filtersChanged();
110114
111115 // signals triggered by activate(..) or preview(..) requests.
@@ -118,6 +122,7 @@ Q_SIGNALS:
118122
119123private Q_SLOTS:
120124 void synchronizeStates();
125+ void scopeIsActiveChanged();
121126 void onSearchFinished(std::string const &, unity::glib::HintsMap const &, unity::glib::Error const&);
122127
123128private:
@@ -129,6 +134,7 @@ private:
129134 void onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints);
130135 void onPreviewReady(unity::dash::LocalResult const& result, unity::dash::Preview::Ptr const& preview);
131136 void fallbackActivate(const QString& uri);
137+ void resultsDirtyToggled(bool);
132138
133139 unity::dash::Scope::Ptr m_unityScope;
134140 std::unique_ptr<Categories> m_categories;
@@ -136,6 +142,7 @@ private:
136142 QString m_searchQuery;
137143 QString m_noResultsHint;
138144 QString m_formFactor;
145+ bool m_isActive;
139146 bool m_searchInProgress;
140147 unity::glib::Cancellable m_cancellable;
141148 unity::glib::Cancellable m_previewCancellable;
tests/mocks/Unity/fake_scope.cpp+13
@@ -31,6 +31,7 @@ Scope::Scope(QObject* parent)
3131 : QObject(parent)
3232 , m_visible(false)
3333 , m_searching(false)
34+ , m_isActive(false)
3435 , m_categories(new Categories(this))
3536 , m_results(new DeeListModel(this))
3637{
@@ -46,6 +47,7 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
4647 , m_name(name)
4748 , m_visible(visible)
4849 , m_searching(false)
50+ , m_isActive(false)
4951 , m_categories(new Categories(this))
5052 , m_results(new DeeListModel(this))
5153{
@@ -107,6 +109,10 @@ bool Scope::visible() const {
107109 return m_visible;
108110}
109111
112+bool Scope::isActive() const {
113+ return m_isActive;
114+}
115+
110116void Scope::setName(const QString &str) {
111117 if (str != m_name) {
112118 m_name = str;
@@ -128,6 +134,13 @@ void Scope::setFormFactor(const QString &str) {
128134 }
129135}
130136
137+void Scope::setActive(const bool active) {
138+ if (active != m_isActive) {
139+ m_isActive = active;
140+ Q_EMIT isActiveChanged();
141+ }
142+}
143+
131144void Scope::setSearchInProgress(const bool inProg) {
132145 if (inProg != m_searching) {
133146 m_searching = inProg;
tests/mocks/Unity/fake_scope.h+5
@@ -41,6 +41,7 @@ class Scope : public QObject
4141 Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
4242 Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
4343 Q_PROPERTY(QString formFactor READ formFactor WRITE setFormFactor NOTIFY formFactorChanged)
44+ Q_PROPERTY(bool isActive READ isActive WRITE setActive NOTIFY isActiveChanged)
4445
4546public:
4647 Scope(QObject* parent = 0);
@@ -60,12 +61,14 @@ public:
6061 QString searchQuery() const;
6162 QString noResultsHint() const;
6263 QString formFactor() const;
64+ bool isActive() const;
6365
6466 /* setters */
6567 void setName(const QString& name);
6668 void setSearchQuery(const QString& search_query);
6769 void setNoResultsHint(const QString& hint);
6870 void setFormFactor(const QString& form_factor);
71+ void setActive(const bool);
6972 void setSearchInProgress(const bool inProg);
7073
7174 Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
@@ -89,6 +92,7 @@ Q_SIGNALS:
8992 void searchQueryChanged();
9093 void noResultsHintChanged();
9194 void formFactorChanged();
95+ void isActiveChanged();
9296
9397 // signals triggered by activate(..) or preview(..) requests.
9498 void previewReady(Preview *preview);
@@ -107,6 +111,7 @@ protected:
107111 QString m_formFactor;
108112 bool m_visible;
109113 bool m_searching;
114+ bool m_isActive;
110115
111116 Categories* m_categories;
112117 DeeListModel* m_results;
tests/plugins/Unity/CMakeLists.txt+1−1
@@ -1,7 +1,7 @@
11add_subdirectory(Indicators)
22add_subdirectory(Launcher)
33
4−pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
4+pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0>=7.1.1)
55pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
66pkg_check_modules(LIBUNITY REQUIRED unity)
77pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
tests/qmltests/CMakeLists.txt+1−1
@@ -43,7 +43,7 @@ add_qml_test(Components Tile)
4343add_qml_test(Components PageHeader)
4444add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4545add_qml_test(Dash DashBar IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
46−add_qml_test(Dash DashContent IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
46+add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4747add_qml_test(Dash DashPreview)
4848add_qml_test(Dash GenericPreview)
4949add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
tests/qmltests/Dash/qml/FakeScopeView.qml+3−9
@@ -17,16 +17,10 @@
1717import QtQuick 2.0
1818import Unity 0.1
1919
20−FocusScope {
21− id: fakeScopeView
22− property Scope scope : null
23− property bool isCurrent : false
24−
25− property ListModel searchHistory
20+import "../../../../Dash"
2621
27− signal endReached
28− signal movementStarted
29− signal positionedAtBeginning
22+ScopeView {
23+ id: fakeScopeView
3024
3125 property alias backColor : back.color
3226
tests/qmltests/Dash/tst_DashContent.qml+29−5
@@ -101,17 +101,21 @@ Item {
101101 when: windowShown
102102
103103 function init() {
104+ scopesModel.load();
105+ }
106+
107+ function cleanup() {
104108 scopeLoadedSpy.clear();
105109 movementStartedSpy.clear();
106− contentEndReachedSpy.clear()
110+ contentEndReachedSpy.clear();
107111 clear_scope_status();
112+ dashContent.visible = true;
108113
109− // clear, wait for dash to empty and load scopes.
110− var dashContentList = findChild(dashContent, "dashContentList");
111− verify(dashContentList != undefined)
112114 scopesModel.clear();
115+ // wait for dash to empty scopes.
116+ var dashContentList = findChild(dashContent, "dashContentList");
117+ verify(dashContentList != undefined);
113118 tryCompare(dashContentList, "count", 0);
114− scopesModel.load();
115119 }
116120
117121 function test_movement_started_signal() {
@@ -205,5 +209,25 @@ Item {
205209 tryCompareFunction(get_current_item_object_name, data.objectName)
206210 }
207211
212+ function test_is_active_data() {
213+ return [
214+ {tag: "select 0", select: 0, visible: true, active0: true, active1: false, active2: false, active3: false},
215+ {tag: "select 2", select: 2, visible: true, active0: false, active1: false, active2: true, active3: false},
216+ {tag: "invisible", select: 0, visible: false, active0: false, active1: false, active2: false, active3: false},
217+ ]
218+ }
219+
220+ function test_is_active(data) {
221+ var dashContentList = findChild(dashContent, "dashContentList");
222+
223+ tryCompare(scopeLoadedSpy, "count", 5);
224+
225+ dashContent.setCurrentScopeAtIndex(data.select, true, false);
226+ dashContent.visible = data.visible;
227+
228+ tryCompare(scopesModel.get(0), "isActive", data.active0);
229+ tryCompare(scopesModel.get(1), "isActive", data.active1);
230+ tryCompare(scopesModel.get(2), "isActive", data.active2);
231+ }
208232 }
209233}
tests/qmltests/tst_Shell.qml+51
@@ -82,6 +82,8 @@ Item {
8282
8383 var dashHome = findChild(shell, "DashHome");
8484 swipeUntilScopeViewIsReached(dashHome);
85+
86+ hideIndicators();
8587 }
8688
8789 function killApps(apps) {
@@ -336,6 +338,19 @@ Item {
336338 mouseClick(appIcon, appIcon.width / 2, appIcon.height / 2);
337339 }
338340
341+ function showIndicators() {
342+ var indicators = findChild(shell, "indicators");
343+ indicators.show();
344+ tryCompare(indicators, "fullyOpened", true);
345+ }
346+
347+ function hideIndicators() {
348+ var indicators = findChild(shell, "indicators");
349+ if (indicators.fullyOpened) {
350+ indicators.hide();
351+ }
352+ }
353+
339354 function waitUntilApplicationWindowIsFullyVisible() {
340355 var underlay = findChild(shell, "underlay");
341356 tryCompare(underlay, "visible", false);
@@ -428,5 +443,41 @@ Item {
428443 tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.expectedUrl) !== -1; }, true)
429444 tryCompare(backgroundImage, "status", Image.Ready)
430445 }
446+
447+ function test_DashShown_data() {
448+ return [
449+ {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
450+ {tag: "under greeter", greeter: true, app: false, launcher: false, indicators: false, expectedShown: false},
451+ {tag: "under app", greeter: false, app: true, launcher: false, indicators: false, expectedShown: false},
452+ {tag: "under launcher", greeter: false, app: false, launcher: true, indicators: false, expectedShown: true},
453+ {tag: "under indicators", greeter: false, app: false, launcher: false, indicators: true, expectedShown: true},
454+ ]
455+ }
456+
457+ function test_DashShown(data) {
458+
459+ if (data.greeter) {
460+ // Swipe the greeter in
461+ var greeter = findChild(shell, "greeter");
462+ Powerd.displayPowerStateChange(Powerd.Off, 0);
463+ tryCompare(greeter, "showProgress", 1);
464+ }
465+
466+ if (data.app) {
467+ dragLauncherIntoView();
468+ tapOnAppIconInLauncher();
469+ }
470+
471+ if (data.launcher) {
472+ dragLauncherIntoView();
473+ }
474+
475+ if (data.indicators) {
476+ showIndicators();
477+ }
478+
479+ var dash = findChild(shell, "dash");
480+ tryCompare(dash, "shown", data.expectedShown);
481+ }
431482 }
432483}