on xenial help sign in
added a filter model for apps
commitb83f3846df63e6e3f00c045aa124ecfc2b83a8ba authorMichael Zanetti <michael.zanetti@canonical.com> dateFri 9 Oct 2015, 11:57 (11 years ago) parent66908ee
8 files changed+280
plugins/Utils/CMakeLists.txt+1 plugins/Utils/applicationsfiltermodel.cpp+74 plugins/Utils/applicationsfiltermodel.h+48 plugins/Utils/plugin.cpp+2 qml/Components/ModeSwitchWarningDialog.qml+74 qml/Shell.qml+5 tests/qmltests/CMakeLists.txt+1 tests/qmltests/Components/tst_ModeSwitchWarningDialog.qml+75
plugins/Utils/CMakeLists.txt+1
@@ -10,6 +10,7 @@ include_directories(
1010
1111set(QMLPLUGIN_SRC
1212 activefocuslogger.cpp
13+ applicationsfiltermodel.cpp
1314 constants.cpp
1415 HomeKeyWatcher.cpp
1516 inputwatcher.cpp
plugins/Utils/applicationsfiltermodel.cppnew file+74
@@ -0,0 +1,74 @@
1+// unity-api
2+#include <unity/shell/application/ApplicationManagerInterface.h>
3+#include <unity/shell/application/ApplicationInfoInterface.h>
4+
5+#include "applicationsfiltermodel.h"
6+
7+using namespace unity::shell::application;
8+
9+ApplicationsFilterModel::ApplicationsFilterModel(QObject *parent):
10+ QSortFilterProxyModel(parent),
11+ m_appModel(nullptr),
12+ m_filterTouchApps(false),
13+ m_filterLegacyApps(false)
14+{
15+
16+}
17+
18+ApplicationManagerInterface *ApplicationsFilterModel::applicationsModel() const
19+{
20+ return m_appModel;
21+}
22+
23+void ApplicationsFilterModel::setApplicationsModel(ApplicationManagerInterface *applicationsModel)
24+{
25+ if (m_appModel != applicationsModel) {
26+ m_appModel = applicationsModel;
27+ Q_EMIT applicationsModelChanged();
28+ }
29+}
30+
31+bool ApplicationsFilterModel::filterTouchApps() const
32+{
33+ return m_filterTouchApps;
34+}
35+
36+void ApplicationsFilterModel::setFilterTouchApps(bool filterTouchApps)
37+{
38+ if (m_filterTouchApps != filterTouchApps) {
39+ m_filterTouchApps = filterTouchApps;
40+ Q_EMIT filterTouchAppsChanged();
41+
42+ invalidateFilter();
43+ }
44+}
45+
46+bool ApplicationsFilterModel::filterLegacyApps() const
47+{
48+ return m_filterLegacyApps;
49+}
50+
51+void ApplicationsFilterModel::setFilterLegacyApps(bool filterLegacyApps)
52+{
53+ if (m_filterLegacyApps != filterLegacyApps) {
54+ m_filterLegacyApps = filterLegacyApps;
55+ Q_EMIT filterLegacyAppsChanged();
56+
57+ invalidateFilter();
58+ }
59+}
60+
61+bool ApplicationsFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
62+{
63+ Q_UNUSED(source_parent);
64+
65+ ApplicationInfoInterface *app = m_appModel->get(source_row);
66+ Q_ASSERT(app);
67+ if (m_filterLegacyApps && !app->isTouchApp()) {
68+ return false;
69+ }
70+ if (m_filterTouchApps && app->isTouchApp()) {
71+ return false;
72+ }
73+ return true;
74+}
plugins/Utils/applicationsfiltermodel.hnew file+48
@@ -0,0 +1,48 @@
1+#ifndef APPLICATIONSFILTERMODEL_H
2+#define APPLICATIONSFILTERMODEL_H
3+
4+#include <QSortFilterProxyModel>
5+
6+namespace unity {
7+namespace shell {
8+namespace application {
9+class ApplicationManagerInterface;
10+}
11+}
12+}
13+using namespace unity::shell::application;
14+
15+class ApplicationsFilterModel: public QSortFilterProxyModel
16+{
17+ Q_OBJECT
18+
19+ Q_PROPERTY(ApplicationManagerInterface* applicationsModel READ applicationsModel WRITE setApplicationsModel NOTIFY applicationsModelChanged)
20+ Q_PROPERTY(bool filterTouchApps READ filterTouchApps WRITE setFilterTouchApps NOTIFY filterTouchAppsChanged)
21+ Q_PROPERTY(bool filterLegacyApps READ filterLegacyApps WRITE setFilterLegacyApps NOTIFY filterLegacyAppsChanged)
22+
23+public:
24+ ApplicationsFilterModel(QObject *parent = 0);
25+
26+ ApplicationManagerInterface* applicationsModel() const;
27+ void setApplicationsModel(ApplicationManagerInterface* applicationsModel);
28+
29+ bool filterTouchApps() const;
30+ void setFilterTouchApps(bool filterTouchApps);
31+
32+ bool filterLegacyApps() const;
33+ void setFilterLegacyApps(bool filterLegacyApps);
34+
35+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
36+
37+Q_SIGNALS:
38+ void applicationsModelChanged();
39+ void filterTouchAppsChanged();
40+ void filterLegacyAppsChanged();
41+
42+private:
43+ ApplicationManagerInterface* m_appModel;
44+ bool m_filterTouchApps;
45+ bool m_filterLegacyApps;
46+};
47+
48+#endif
plugins/Utils/plugin.cpp+2
@@ -37,6 +37,7 @@
3737#include "windowstatestorage.h"
3838#include "constants.h"
3939#include "timezoneFormatter.h"
40+#include "applicationsfiltermodel.h"
4041
4142static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
4243{
@@ -71,6 +72,7 @@ void UtilsPlugin::registerTypes(const char *uri)
7172 qmlRegisterSingletonType<TimezoneFormatter>(uri, 0, 1, "TimezoneFormatter",
7273 [](QQmlEngine*, QJSEngine*) -> QObject* { return new TimezoneFormatter; });
7374 qmlRegisterType<ActiveFocusLogger>(uri, 0, 1, "ActiveFocusLogger");
75+ qmlRegisterType<ApplicationsFilterModel>(uri, 0, 1, "ApplicationsFilterModel");
7476}
7577
7678void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
qml/Components/ModeSwitchWarningDialog.qmlnew file+74
@@ -0,0 +1,74 @@
1+import QtQuick 2.4
2+import QtQuick.Layouts 1.1
3+import Ubuntu.Components 1.2
4+import Ubuntu.Components.ListItems 1.2
5+import Ubuntu.Components.Popups 1.2
6+
7+Dialog {
8+ id: root
9+
10+ property alias model: appRepeater.model
11+
12+ signal forceClose();
13+
14+ Label {
15+ text: i18n.tr("Apps may have unsaved data:")
16+ fontSize: "large"
17+ }
18+
19+ Repeater {
20+ id: appRepeater
21+ RowLayout {
22+ spacing: units.gu(2)
23+ Image {
24+ Layout.preferredHeight: units.gu(2)
25+ Layout.preferredWidth: units.gu(2)
26+ source: model.icon
27+ sourceSize.width: width
28+ sourceSize.height: height
29+ }
30+ Label {
31+ Layout.fillWidth: true
32+ text: model.name
33+ }
34+ }
35+ }
36+
37+ Label {
38+ text: i18n.tr("Re-dock, save your work and close these apps to continue.")
39+ wrapMode: Text.WordWrap
40+ }
41+
42+ Label {
43+ text: i18n.tr("Or force close now (unsaved data will be lost).")
44+ wrapMode: Text.WordWrap
45+ }
46+
47+ ThinDivider {}
48+
49+ RowLayout {
50+ Label {
51+ objectName: "reconnectLabel"
52+ Layout.fillWidth: true
53+ property bool clicked: false
54+ property string notClickedText: i18n.tr("OK, I will reconnect")
55+ property string clickedText: i18n.tr("Reconnect now!")
56+ text: clicked ? clickedText : notClickedText
57+
58+ MouseArea {
59+ anchors.fill: parent
60+ onClicked: parent.clicked = true;
61+ }
62+ }
63+
64+ Button {
65+ objectName: "forceCloseButton"
66+ text: i18n.tr("Close all")
67+ color: UbuntuColors.red
68+ onClicked: {
69+ root.forceClose();
70+ PopupUtils.close(root);
71+ }
72+ }
73+ }
74+}
qml/Shell.qml+5
@@ -729,4 +729,9 @@ Item {
729729 }
730730 }
731731
732+ ApplicationsFilterModel {
733+ id: legacyAppsModel
734+ applicationsModel: ApplicationManager
735+ filterTouchApps: true
736+ }
732737}
tests/qmltests/CMakeLists.txt+1
@@ -10,6 +10,7 @@ add_unity8_qmltest(Components Dialogs LIGHTDM)
1010add_unity8_qmltest(Components DraggingArea)
1111add_unity8_qmltest(Components LazyImage)
1212add_unity8_qmltest(Components Lockscreen)
13+add_unity8_qmltest(Components ModeSwitchWarningDialog)
1314add_unity8_qmlunittest(Components PhysicalKeysMapper)
1415add_unity8_qmltest(Components Rating)
1516add_unity8_qmltest(Components ResponsiveGridView)
tests/qmltests/Components/tst_ModeSwitchWarningDialog.qmlnew file+75
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright 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+import QtQuick 2.0
18+import QtTest 1.0
19+import "../../../qml/Components"
20+import Unity.Test 0.1 as UT
21+import Ubuntu.Components 1.2
22+import Ubuntu.Components.Popups 1.2
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(40)
27+ height: units.gu(70)
28+ color: "lightgrey"
29+
30+ ListModel {
31+ id: fakeModel
32+ ListElement { icon: "../graphics/applicationIcons/facebook.png"; name: "Facebook" }
33+ ListElement { icon: "../graphics/applicationIcons/gmail.png"; name: "Mail" }
34+ }
35+
36+ function openWarning() {
37+ return PopupUtils.open(Qt.resolvedUrl("../../../qml/Components/ModeSwitchWarningDialog.qml"), root, { model: fakeModel })
38+ }
39+
40+ Button {
41+ anchors.centerIn: parent
42+ text: "trigger warning"
43+ onClicked: {
44+ openWarning();
45+ }
46+ }
47+
48+ SignalSpy {
49+ id: spy
50+ signalName: "forceClose"
51+ }
52+
53+ UT.UnityTestCase {
54+ name: "ModeSwitchWarning"
55+ when: windowShown
56+
57+ function test_labelChangesOnClick() {
58+ var popup = openWarning();
59+ var reconnectLabel = findChild(popup, "reconnectLabel");
60+ tryCompare(reconnectLabel, "text", reconnectLabel.notClickedText)
61+ mouseClick(reconnectLabel, reconnectLabel.width / 2, reconnectLabel.height / 2)
62+ tryCompare(reconnectLabel, "text", reconnectLabel.clickedText)
63+ }
64+
65+ function test_closeButtonEmitsSignal() {
66+ var popup = openWarning();
67+ spy.target = popup;
68+ spy.clear();
69+ var closeButton = findChild(popup, "forceCloseButton");
70+ mouseClick(closeButton, closeButton.width / 2, closeButton.height / 2)
71+ tryCompare(spy, "count", 1)
72+
73+ }
74+ }
75+}