on xenial help sign in
merge trunk
commitf7ce8478e2b8d672e258081c3a707311094eb3bf authorMichael Zanetti <michael.zanetti@canonical.com> dateWed 21 Aug 2013, 17:14 (13 years ago) parent682da6a5d43ac0
46 files changed+1639−59
Dash/Apps/FrequentlyUsedAppsModel.qml+1−1 Launcher/LauncherDelegate.qml+73−7 Launcher/LauncherPanel.qml+14−1 Launcher/graphics/notification@30.png Launcher/graphics/notification@30.sci+5 Launcher/graphics/progressbar-fill@30.png Launcher/graphics/progressbar-fill@30.sci+5 Launcher/graphics/progressbar-trough@30.png Launcher/graphics/progressbar-trough@30.sci+5 Panel/Indicators/NetworkIndicatorPage2.qml+82 Panel/IndicatorsDataModel.qml+2−10 build+5−2 debian/changelog+36 debian/control+1 plugins/Unity/Indicators/CMakeLists.txt+1 plugins/Unity/Indicators/Network/CMakeLists.txt+45 plugins/Unity/Indicators/Network/networkagent.cpp+146 plugins/Unity/Indicators/Network/networkagent.h+65 plugins/Unity/Indicators/Network/plugin.cpp+31 plugins/Unity/Indicators/Network/plugin.h+32 plugins/Unity/Indicators/Network/qml/AccessPoint.qml+62 plugins/Unity/Indicators/Network/qml/CMakeLists.txt+5 plugins/Unity/Indicators/Network/qml/PasswordPage.qml+88 plugins/Unity/Indicators/Network/qml/PasswordTextField.qml+68 plugins/Unity/Indicators/Network/qml/WifiSection.qml+28 plugins/Unity/Indicators/Network/qml/qmldir+9 plugins/Unity/Indicators/Network/secret-agent.c+382 plugins/Unity/Indicators/Network/secret-agent.h+102 plugins/Unity/Indicators/qml/MenuItemFactory.qml+21 plugins/Unity/IndicatorsLegacy/Network/CMakeLists.txt+8−8 plugins/Unity/IndicatorsLegacy/Network/qml/qmldir+1−1 plugins/Unity/IndicatorsLegacy/flatmenuproxymodel.cpp+13 plugins/Unity/filters.cpp+4 plugins/Unity/filters.h+2−1 plugins/Unity/genericoptionsmodel.cpp+18 plugins/Unity/genericoptionsmodel.h+3 plugins/Utils/qlimitproxymodelqml.cpp+90−4 plugins/Utils/qlimitproxymodelqml.h+2 src/Panel/Indicators/servicefiles/CMakeLists.txt−1 src/Panel/Indicators/servicefiles/com.canonical.indicator.messages+1−1 src/Panel/Indicators/servicefiles/com.canonical.settings.network−10 tests/mocks/Unity/Launcher/MockLauncherItem.cpp+2−2 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+31−1 tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8 tests/qmltests/Greeter/tst_Clock.qml+1−1 tests/qmltests/Launcher/tst_Launcher.qml+16
Dash/Apps/FrequentlyUsedAppsModel.qml+1−1
@@ -38,7 +38,7 @@ ListModel {
3838 metadata: ""
3939 }
4040 ListElement {
41− uri: "application:///usr/share/applications/galery-app.desktop"
41+ uri: "application:///usr/share/applications/gallery-app.desktop"
4242 icon: "../../graphics/applicationIcons/gallery.png"
4343 category: 0
4444 mimetype: "application/x-desktop"
Launcher/LauncherDelegate.qml+73−7
@@ -21,7 +21,8 @@ Item {
2121 id: root
2222
2323 property string iconName
24−
24+ property int count: -1
25+ property int progress: -1
2526 property bool highlighted: false
2627 property real maxAngle: 0
2728 property bool inverted: false
@@ -38,6 +39,11 @@ Item {
3839 property real itemOpacity: 1
3940 property real brightness: 0
4041
42+ onIconNameChanged: shaderEffectSource.scheduleUpdate();
43+ onCountChanged: shaderEffectSource.scheduleUpdate();
44+ onProgressChanged: shaderEffectSource.scheduleUpdate();
45+ onHighlightedChanged: shaderEffectSource.scheduleUpdate();
46+
4147 Item {
4248 id: iconItem
4349 width: parent.itemWidth
@@ -54,9 +60,7 @@ Item {
5460 id: iconImage
5561 sourceSize.width: iconShape.width
5662 sourceSize.height: iconShape.height
57− source: "../graphics/applicationIcons/" + iconName + ".png"
58− property string iconName: root.iconName
59− onIconNameChanged: shaderEffectSource.scheduleUpdate();
63+ source: "../graphics/applicationIcons/" + root.iconName + ".png"
6064 }
6165 }
6266
@@ -64,11 +68,73 @@ Item {
6468 id: overlayHighlight
6569 anchors.centerIn: iconItem
6670 rotation: inverted ? 180 : 0
67− source: isSelected ? "graphics/selected.sci" : "graphics/non-selected.sci"
71+ source: root.highlighted ? "graphics/selected.sci" : "graphics/non-selected.sci"
6872 width: root.itemWidth + units.gu(0.5)
6973 height: root.itemHeight + units.gu(0.5)
70− property bool isSelected: root.highlighted
71− onIsSelectedChanged: shaderEffectSource.scheduleUpdate();
74+ }
75+
76+ BorderImage {
77+ objectName: "countEmblem"
78+ anchors {
79+ right: parent.right
80+ top: parent.top
81+ margins: -units.dp(1)
82+ }
83+ width: Math.min(units.gu(7.5), Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
84+ height: units.gu(3)
85+ source: "graphics/notification.sci"
86+ visible: root.count > 0
87+
88+ Label {
89+ id: countLabel
90+ text: root.count
91+ anchors.centerIn: parent
92+ width: units.gu(6)
93+ horizontalAlignment: Text.AlignHCenter
94+ elide: Text.ElideRight
95+ color: "white"
96+ fontSize: "small"
97+ font.bold: true
98+ }
99+ }
100+
101+ BorderImage {
102+ id: progressOverlay
103+ objectName: "progressOverlay"
104+ anchors {
105+ left: iconItem.left
106+ right: iconItem.right
107+ bottom: iconItem.bottom
108+ leftMargin: units.gu(0.5)
109+ rightMargin: units.gu(0.5)
110+ bottomMargin: units.gu(0.5)
111+ }
112+ height: units.gu(1.5)
113+ visible: root.progress > -1
114+ source: "graphics/progressbar-trough.sci"
115+
116+ // For fill calculation we need to remove the 2 units of border defined in .sci file
117+ property int adjustedWidth: width - units.gu(2)
118+
119+ Item {
120+ anchors {
121+ left: parent.left
122+ top: parent.top
123+ bottom: parent.bottom
124+ }
125+ width: Math.min(100, root.progress) / 100 * parent.adjustedWidth + units.gu(1)
126+ clip: true
127+
128+ BorderImage {
129+ anchors {
130+ left: parent.left
131+ top: parent.top
132+ bottom: parent.bottom
133+ }
134+ width: progressOverlay.width
135+ source: "graphics/progressbar-fill.sci"
136+ }
137+ }
72138 }
73139 }
74140
Launcher/LauncherPanel.qml+14−1
@@ -135,6 +135,8 @@ Item {
135135 width: itemWidth
136136 height: itemHeight
137137 iconName: model.icon
138+ count: model.count
139+ progress: model.progress
138140 inverted: root.inverted
139141 z: -Math.abs(offset)
140142 maxAngle: 55
@@ -236,7 +238,7 @@ Item {
236238 property int draggedIndex: -1
237239 property var selectedItem
238240 property bool preDragging: false
239− property bool dragging: selectedItem !== undefined && selectedItem.dragging
241+ property bool dragging: selectedItem !== undefined && selectedItem !== null && selectedItem.dragging
240242 property bool postDragging: false
241243 property int startX
242244 property int startY
@@ -250,6 +252,11 @@ Item {
250252 var index = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
251253 var clickedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
252254
255+ // Check if we actually clicked an item or only at the spacing in between
256+ if (clickedItem === null) {
257+ return;
258+ }
259+
253260 // First/last item do the scrolling at more than 12 degrees
254261 if (index == 0 || index == launcherListView.count - 1) {
255262 if (clickedItem.angle > 12) {
@@ -286,6 +293,10 @@ Item {
286293 draggedIndex = -1;
287294 }
288295
296+ if (!selectedItem) {
297+ return;
298+ }
299+
289300 selectedItem.dragging = false;
290301 selectedItem = undefined;
291302 preDragging = false;
@@ -325,6 +336,8 @@ Item {
325336 fakeDragItem.y = mouseY - yOffset + launcherListView.anchors.topMargin + launcherListView.topMargin
326337 fakeDragItem.angle = selectedItem.angle * (root.inverted ? -1 : 1)
327338 fakeDragItem.offset = selectedItem.offset * (root.inverted ? -1 : 1)
339+ fakeDragItem.count = LauncherModel.get(draggedIndex).count
340+ fakeDragItem.progress = LauncherModel.get(draggedIndex).progress
328341 fakeDragItem.flatten()
329342 drag.target = fakeDragItem
330343
Launcher/graphics/notification@30.pngnew file

Binary file not shown.

Launcher/graphics/notification@30.scinew file+5
@@ -0,0 +1,5 @@
1+border.left: 36
2+border.top: 36
3+border.bottom: 36
4+border.right: 36
5+source: notification@30.png
Launcher/graphics/progressbar-fill@30.pngnew file

Binary file not shown.

Launcher/graphics/progressbar-fill@30.scinew file+5
@@ -0,0 +1,5 @@
1+border.left: 36
2+border.top: 16
3+border.bottom: 28
4+border.right: 36
5+source: progressbar-fill@30.png
Launcher/graphics/progressbar-trough@30.pngnew file

Binary file not shown.

Launcher/graphics/progressbar-trough@30.scinew file+5
@@ -0,0 +1,5 @@
1+border.left: 36
2+border.top: 16
3+border.bottom: 26
4+border.right: 36
5+source: progressbar-trough@30.png
Panel/Indicators/NetworkIndicatorPage2.qmlnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Unity.Indicators 0.1 as Indicators
22+import Unity.Indicators.Network 0.1 as ICNetwork
23+import Ubuntu.Components 0.1
24+
25+PageStack {
26+ id: networkPage
27+ // Stops the search for a parent tree node.
28+ // We don't want it going up to the indicator tabs.
29+ // FIXME: need a better way of doing this.
30+ // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1211704
31+ __propagated: null
32+
33+ property alias title: _mainPage.title
34+ property alias emptyText: pluginItem.emptyText
35+ property alias busName: pluginItem.busName
36+ property alias actionsObjectPath : pluginItem.actionsObjectPath
37+ property alias menuObjectPaths : pluginItem.menuObjectPaths
38+
39+ anchors.fill: parent
40+
41+ Page {
42+ id: _mainPage
43+
44+ Indicators.IndicatorPage {
45+ id: pluginItem
46+ anchors.fill: parent
47+ }
48+ }
49+
50+ Component {
51+ id: passwordPageComponent
52+
53+ ICNetwork.PasswordPage {
54+ agent: networkAgent
55+ }
56+ }
57+
58+ ICNetwork.NetworkAgent {
59+ id: networkAgent
60+
61+ onSecretRequested: {
62+ networkPage.push(passwordPageComponent, {"token": token});
63+ }
64+ }
65+
66+ function start()
67+ {
68+ push(_mainPage);
69+ pluginItem.start();
70+ }
71+
72+ function stop()
73+ {
74+ clear();
75+ pluginItem.stop();
76+ }
77+
78+ function reset()
79+ {
80+ pluginItem.reset();
81+ }
82+}
Panel/IndicatorsDataModel.qml+2−10
@@ -33,7 +33,7 @@ Indicators.IndicatorsModel {
3333 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
3434 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
3535 },
36− 'indicator-messaging' : {
36+ 'indicator-messages' : {
3737 'title': 'Messaging',
3838 'description' : '',
3939 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/MessagingIndicatorWidget.qml',
@@ -49,7 +49,7 @@ Indicators.IndicatorsModel {
4949 'title': 'Networks',
5050 'description' : '',
5151 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
52− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
52+ 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorPage2.qml'
5353 },
5454 'indicator-power' : {
5555 'title': 'Battery',
@@ -68,14 +68,6 @@ Indicators.IndicatorsModel {
6868 'description' : '',
6969 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
7070 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
71− },
72−
73− // OLD FORMAT INDICATORS
74− 'chewie-network' : {
75− 'title': 'Networks',
76− 'description' : '',
77− 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorWidget.qml',
78− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorPage.qml'
7971 }
8072 }
8173}
build+5−2
@@ -40,11 +40,14 @@ install_dependencies() {
4040 echo "Installing Unity 8 dependencies.."
4141 sudo apt-get install devscripts \
4242 equivs \
43+ gsettings-desktop-schemas \
4344 qmenumodel-qml \
44− qtdeclarative5-ubuntu-ui-toolkit-plugin \
4545 qtdeclarative5-dee-plugin \
46+ qtdeclarative5-gsettings1.0 \
47+ qtdeclarative5-ubuntu-ui-toolkit-plugin \
48+ unity-notifications-impl \
49+ qtdeclarative5-xmllistmodel-plugin \
4650 ubuntu-mobile-icons \
47− unity-notifications-impl-1 \
4851 unity-scope-home \
4952 unity-lens-applications \
5053 || exit 5
debian/changelog+36
@@ -1,3 +1,39 @@
1+unity8 (7.81.3+13.10.20130821-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Zanetti ]
4+ * added support for count emblems and progress overlays on the
5+ launcher.
6+
7+ [ Pawel Stolowski ]
8+ * Add role for getting filter options model. Add method to activate
9+ option based on index or id.
10+
11+ [ Ted Gould ]
12+ * Mark indicators-client as providing an indicator-renderer.
13+
14+ [ Nick Dedekind ]
15+ * Added flatmenuproxymodel pass-through signals from qmenumodel.
16+ * Renamed indicator-messaging to indicator-messages.
17+
18+ [ Gerry Boland ]
19+ * Typo fix in FrequentlyUsedAppsModel.
20+
21+ [ Ubuntu daily release ]
22+ * Automatic snapshot from revision 224
23+
24+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 21 Aug 2013 08:05:13 +0000
25+
26+unity8 (7.81.3+13.10.20130820.2-0ubuntu1) saucy; urgency=low
27+
28+ [ Michael Zanetti ]
29+ * initial support for quicklists For now they support pinning and
30+ removing of items.
31+
32+ [ Ubuntu daily release ]
33+ * Automatic snapshot from revision 217
34+
35+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 20 Aug 2013 10:09:36 +0000
36+
137unity8 (7.81.3+13.10.20130820-0ubuntu1) saucy; urgency=low
238
339 [ Andrea Cimitan ]
debian/control+1
@@ -60,6 +60,7 @@ Description: Indicators client test application
6060
6161Package: unity8
6262Architecture: any
63+Provides: indicator-renderer,
6364Depends: gsettings-desktop-schemas,
6465 qmenumodel-qml (>= 0.2.7),
6566 qtdeclarative5-dee-plugin,
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -12,6 +12,7 @@ find_package(Qt5Core REQUIRED)
1212find_package(Qt5Quick REQUIRED)
1313
1414add_subdirectory(qml)
15+add_subdirectory(Network)
1516
1617include_directories(
1718 ${CMAKE_CURRENT_SOURCE_DIR}
plugins/Unity/Indicators/Network/CMakeLists.txtnew file+45
@@ -0,0 +1,45 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+project(IndicatorsNetworkQml)
5+
6+pkg_check_modules(GLIB glib-2.0>=2.32)
7+pkg_check_modules(LIBNM_GLIB libnm-glib>=0.9.6)
8+pkg_check_modules(LIBNM_UTIL libnm-util>=0.9.6)
9+
10+if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
11+ set(INDICATORS_NETWORK_SRC
12+ networkagent.cpp
13+ plugin.cpp
14+ secret-agent.c
15+ )
16+
17+ add_library(IndicatorsNetworkQml MODULE
18+ ${INDICATORS_NETWORK_SRC}
19+ )
20+
21+ qt5_use_modules(IndicatorsNetworkQml Core Qml Widgets)
22+
23+ set_target_properties(IndicatorsNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
24+
25+ include_directories(
26+ ${CMAKE_CURRENT_SOURCE_DIR}
27+ ${GLIB_INCLUDE_DIRS}
28+ ${LIBNM_GLIB_INCLUDE_DIRS}
29+ ${LIBNM_UTIL_INCLUDE_DIRS}
30+ )
31+
32+ target_link_libraries(IndicatorsNetworkQml
33+ ${GLIB_LIBRARIES}
34+ ${LIBNM_GLIB_LIBRARIES}
35+ ${LIBNM_UTIL_LIBRARIES}
36+ )
37+
38+ # export the qmltypes and plugin files
39+ export_qmlplugin(Unity.Indicators.Network 0.1 Unity/Indicators/Network TARGETS IndicatorsNetworkQml)
40+
41+else()
42+ message(WARNING "Missing glib or libnm dependency for the network plugin, not building")
43+endif()
44+
45+add_subdirectory(qml)
plugins/Unity/Indicators/Network/networkagent.cppnew file+146
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#include "networkagent.h"
22+
23+#include <QVariant>
24+#include <QApplication>
25+#include <QDebug>
26+
27+class NetworkAgentToken
28+{
29+public:
30+ NMConnection *connection;
31+ NMSettingWirelessSecurity *wisec;
32+ guint id;
33+ QByteArray keyMgmt;
34+
35+ NetworkAgentToken(NMConnection *connection,
36+ NMSettingWirelessSecurity *wisec,
37+ guint id,
38+ QByteArray keyMgmt)
39+ : connection(connection),
40+ wisec(wisec),
41+ id(id),
42+ keyMgmt(keyMgmt)
43+ {
44+ if (connection) {
45+ g_object_ref(connection);
46+ } else {
47+ qWarning() << "invalid connection object";
48+ }
49+ }
50+
51+ ~NetworkAgentToken()
52+ {
53+ if (connection) {
54+ g_object_unref(connection);
55+ }
56+ }
57+};
58+
59+NetworkAgent::NetworkAgent(QObject *parent)
60+ : QObject(parent)
61+{
62+ m_agent = unity_settings_secret_agent_new();
63+ g_signal_connect(G_OBJECT(m_agent),
64+ UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
65+ G_CALLBACK(onSecretRequested),
66+ this);
67+
68+ g_signal_connect(G_OBJECT(m_agent),
69+ UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
70+ G_CALLBACK(onSecretRequestCancelled),
71+ this);
72+}
73+
74+NetworkAgent::~NetworkAgent()
75+{
76+ nm_secret_agent_unregister(NM_SECRET_AGENT(m_agent));
77+ g_object_unref(m_agent);
78+}
79+
80+void NetworkAgent::authenticate(const QVariant &token, const QString &key)
81+{
82+ NetworkAgentToken *pToken = (NetworkAgentToken *) token.value<void *>();
83+ if (pToken == NULL) {
84+ return;
85+ }
86+
87+ if ((pToken->keyMgmt == "wpa-none") || (pToken->keyMgmt == "wpa-psk")) {
88+ g_object_set(G_OBJECT(pToken->wisec),
89+ NM_SETTING_WIRELESS_SECURITY_PSK, qPrintable(key),
90+ NULL);
91+ } else if (pToken->keyMgmt == "none") {
92+ g_object_set(G_OBJECT(pToken->wisec),
93+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, qPrintable(key),
94+ NULL);
95+ }
96+
97+ GHashTable *settings = nm_connection_to_hash(pToken->connection,
98+ NM_SETTING_HASH_FLAG_ALL);
99+
100+ unity_settings_secret_agent_provide_secret(m_agent,
101+ pToken->id, settings);
102+ g_hash_table_unref(settings);
103+ delete pToken;
104+}
105+
106+void NetworkAgent::cancel(const QVariant &token)
107+{
108+ NetworkAgentToken *pToken = (NetworkAgentToken *) token.value<void *>();
109+ if (pToken != NULL) {
110+ unity_settings_secret_agent_cancel_request(m_agent, pToken->id);
111+ delete pToken;
112+ }
113+}
114+
115+void NetworkAgent::onSecretRequested(UnitySettingsSecretAgent* /*agent*/,
116+ guint id,
117+ NMConnection* connection,
118+ const char* /*setting_name*/,
119+ const char** /*hints*/,
120+ NMSecretAgentGetSecretsFlags /*flags*/,
121+ NetworkAgent* self)
122+{
123+ NetworkAgentToken *token = new NetworkAgentToken(connection,
124+ NULL,
125+ id,
126+ NULL);
127+
128+ token->wisec = nm_connection_get_setting_wireless_security(connection);
129+ if (token->wisec) {
130+ token->keyMgmt = nm_setting_wireless_security_get_key_mgmt(token->wisec);
131+ }
132+
133+ QVariant varToken = qVariantFromValue((void *) token);
134+ Q_EMIT self->secretRequested(varToken);
135+}
136+
137+void NetworkAgent::onSecretRequestCancelled(UnitySettingsSecretAgent* /*agent*/,
138+ guint /*id*/,
139+ NMConnection* /*connection*/,
140+ const char* /*setting_name*/,
141+ const char** /*hints*/,
142+ NMSecretAgentGetSecretsFlags /*flags*/,
143+ NetworkAgent* /*self*/)
144+{
145+ //Do nothing for now
146+}
plugins/Unity/Indicators/Network/networkagent.hnew file+65
@@ -0,0 +1,65 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#ifndef NETWORKAGENT_H
22+#define NETWORKAGENT_H
23+
24+#include "secret-agent.h"
25+
26+#include <QObject>
27+
28+class NetworkAgentToken;
29+
30+class NetworkAgent : public QObject
31+{
32+ Q_OBJECT
33+public:
34+ NetworkAgent(QObject *parent=0);
35+ ~NetworkAgent();
36+
37+ Q_INVOKABLE void authenticate(const QVariant &token, const QString &key);
38+ Q_INVOKABLE void cancel(const QVariant &token);
39+
40+Q_SIGNALS:
41+ void secretRequested(const QVariant &token);
42+ void secretRequestCancelled();
43+
44+private:
45+ UnitySettingsSecretAgent *m_agent;
46+
47+ static void onSecretRequested(UnitySettingsSecretAgent *agent,
48+ guint id,
49+ NMConnection *connection,
50+ const char *setting_name,
51+ const char **hints,
52+ NMSecretAgentGetSecretsFlags flags,
53+ NetworkAgent *self);
54+
55+ static void onSecretRequestCancelled(UnitySettingsSecretAgent *agent,
56+ guint id,
57+ NMConnection *connection,
58+ const char *setting_name,
59+ const char **hints,
60+ NMSecretAgentGetSecretsFlags flags,
61+ NetworkAgent *self);
62+
63+};
64+
65+#endif
plugins/Unity/Indicators/Network/plugin.cppnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2012 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+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+// Qt
20+#include <QtQml>
21+
22+// self
23+#include "plugin.h"
24+
25+// local
26+#include "networkagent.h"
27+
28+void IndicatorsNetworkPlugin::registerTypes(const char *uri)
29+{
30+ qmlRegisterType<NetworkAgent>(uri, 0, 1, "NetworkAgent");
31+}
plugins/Unity/Indicators/Network/plugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2012 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+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef INDICATORS_NETWORK_PLUGIN_H
20+#define INDICATORS_NETWORK_PLUGIN_H
21+
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class IndicatorsNetworkPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#endif // INDICATORS_NETWORK_PLUGIN_H
plugins/Unity/Indicators/Network/qml/AccessPoint.qmlnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Ubuntu.Components.ListItems 0.1 as ListItem
23+import Unity.Indicators 0.1 as Indicators
24+
25+Indicators.FramedMenuItem {
26+ id: accessPoint
27+
28+ readonly property bool checked: menu ? menu.isToggled : false
29+
30+ onCheckedChanged: {
31+ // Can't rely on binding. Checked is assigned on click.
32+ checkBoxActive.checked = checked;
33+ }
34+
35+ // FIXME - we need to get the strength from menu.ext.xCanonicalWifiApStrengthAction
36+ // but UnityMenuModel doesnt support fetching actions not attached to menu item.
37+ function getNetworkIcon(data) {
38+ var imageName = "nm-signal-100"
39+
40+ if (data.ext.xCanonicalWifiApIsAdhoc) {
41+ imageName = "nm-adhoc";
42+ }
43+ if (data.ext.xCanonicalWifiApIsSecure) {
44+ imageName += "-secure";
45+ }
46+
47+ return "image://gicon/" + imageName;
48+ }
49+
50+ icon: menu ? getNetworkIcon(menu) : "image://gicon/wifi-none"
51+ iconFrame: false
52+ control: CheckBox {
53+ id: checkBoxActive
54+ height: units.gu(4)
55+ width: units.gu(4)
56+ anchors.centerIn: parent
57+
58+ onClicked: {
59+ accessPoint.activate();
60+ }
61+ }
62+}
plugins/Unity/Indicators/Network/qml/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Network Unity/Indicators/Network)
plugins/Unity/Indicators/Network/qml/PasswordPage.qmlnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Ubuntu.Components.ListItems 0.1 as ListItem
23+import Unity.Indicators 0.1 as Indicators
24+
25+Page {
26+ id: pagePassword
27+
28+ property variant agent
29+ property variant token
30+
31+ anchors.fill: parent
32+ title: "Network Authentication"
33+
34+ Column {
35+ anchors {
36+ left: parent.left
37+ right: parent.right
38+ }
39+
40+ Indicators.SectionMenuItem {
41+ label: "Authentication"
42+ }
43+
44+ Indicators.FramedMenuItem {
45+ implicitHeight: password.height + units.gu(1)
46+
47+ PasswordTextField {
48+ id: password
49+ anchors {
50+ left: parent.left
51+ right: parent.right
52+ margins: units.gu(3)
53+ verticalCenter: parent.verticalCenter
54+ }
55+ }
56+ }
57+
58+ Indicators.FramedMenuItem {
59+ Row {
60+ anchors {
61+ right: parent.right
62+ verticalCenter: parent.verticalCenter
63+ margins: units.gu(3)
64+ }
65+
66+ spacing: units.gu(1)
67+
68+ Button {
69+ text: "Cancel"
70+ width: units.gu(10)
71+ onClicked: {
72+ agent.cancel(token);
73+ pageStack.pop();
74+ }
75+ }
76+
77+ Button {
78+ text: "OK"
79+ width: units.gu(10)
80+ onClicked: {
81+ agent.authenticate(token, password.text);
82+ pageStack.pop();
83+ }
84+ }
85+ }
86+ }
87+ }
88+}
plugins/Unity/Indicators/Network/qml/PasswordTextField.qmlnew file+68
@@ -0,0 +1,68 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+
23+Item {
24+ id: textMenu
25+
26+ property alias text: textField.text
27+
28+ height: contentColumn.height
29+
30+ Column {
31+ id: contentColumn
32+ spacing: units.gu(0.5)
33+ anchors {
34+ left: parent.left
35+ right: parent.right
36+ }
37+
38+ TextField {
39+ id: textField
40+
41+ anchors {
42+ left: parent.left
43+ right: parent.right
44+ }
45+
46+ placeholderText: "Password"
47+ echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
48+ }
49+
50+ Row {
51+ anchors {
52+ left: parent.left
53+ right: parent.right
54+ }
55+
56+ spacing: units.gu(1)
57+
58+ CheckBox {
59+ id: showPassword
60+ }
61+
62+ Label {
63+ text: "Show password"
64+ anchors.verticalCenter: showPassword.verticalCenter
65+ }
66+ }
67+ }
68+}
plugins/Unity/Indicators/Network/qml/WifiSection.qmlnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Unity.Indicators 0.1 as Indicators
23+
24+Indicators.SectionMenuItem {
25+ id: wifiSectionMenu
26+
27+ busy: menu ? menu.ext.xCanonicalBusyAction : false
28+}
plugins/Unity/Indicators/Network/qml/qmldirnew file+9
@@ -0,0 +1,9 @@
1+module Unity.Indicators.Network
2+plugin IndicatorsNetworkQml
3+typeinfo plugin.qmltypes
4+
5+NetworkPage 0.1 NetworkPage.qml
6+AccessPoint 0.1 AccessPoint.qml
7+PasswordPage 0.1 PasswordPage.qml
8+PasswordTextField 0.1 PasswordTextField.qml
9+WifiSection 0.1 WifiSection.qml
plugins/Unity/Indicators/Network/secret-agent.cnew file+382
@@ -0,0 +1,382 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+
22+#include <glib.h>
23+#include <glib-object.h>
24+#include <nm-secret-agent.h>
25+#include "secret-agent.h"
26+
27+#define UNITY_SETTINGS_TYPE_SECRET_AGENT (unity_settings_secret_agent_get_type ())
28+#define UNITY_SETTINGS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgent))
29+#define UNITY_SETTINGS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
30+#define UNITY_SETTINGS_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT))
31+#define UNITY_SETTINGS_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT))
32+#define UNITY_SETTINGS_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
33+#define UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentPrivate))
34+
35+#define AGENT_ID "com.canonical.settings.network.nm-agent"
36+
37+static gpointer unity_settings_secret_agent_parent_class = NULL;
38+
39+typedef struct _UnitySettingsSecretAgentPrivate UnitySettingsSecretAgentPrivate;
40+
41+struct _UnitySettingsSecretAgentPrivate {
42+ GQueue *requests;
43+};
44+
45+typedef struct _SecretRequest {
46+ gint id;
47+ NMSecretAgent *agent;
48+ NMConnection *connection;
49+ const char *connection_path;
50+ const char *setting_name;
51+ const char **hints;
52+ NMSecretAgentGetSecretsFlags flags;
53+ NMSecretAgentGetSecretsFunc callback;
54+ gpointer callback_data;
55+} SecretRequest;
56+
57+GType unity_settings_secret_agent_get_type (void) G_GNUC_CONST;
58+enum {
59+ UNITY_SETTINGS_SECRET_AGENT_DUMMY_PROPERTY
60+};
61+
62+enum {
63+ SECRET_REQUESTED,
64+ REQUEST_CANCELLED,
65+ LAST_SIGNAL
66+};
67+
68+static guint signals[LAST_SIGNAL] = { 0 };
69+
70+UnitySettingsSecretAgent* unity_settings_secret_agent_new (void);
71+UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type);
72+
73+int
74+secret_request_find (SecretRequest *req,
75+ guint *id)
76+{
77+ if (req->id > *id)
78+ return -1;
79+
80+ if (req->id < *id)
81+ return 1;
82+
83+ return 0;
84+}
85+
86+void
87+unity_settings_secret_agent_provide_secret (UnitySettingsSecretAgent *agent,
88+ guint request,
89+ GHashTable *secrets)
90+{
91+ GList *iter;
92+ SecretRequest *req;
93+ UnitySettingsSecretAgentPrivate *priv = agent->priv;
94+
95+ iter = g_queue_find_custom (priv->requests,
96+ &request,
97+ (GCompareFunc)secret_request_find);
98+
99+ if (iter == NULL || iter->data == NULL)
100+ {
101+ g_warning ("Secret request with id <%d> was not found", (int)request);
102+ return;
103+ }
104+
105+ req = iter->data;
106+
107+ req->callback (NM_SECRET_AGENT (agent),
108+ req->connection,
109+ secrets,
110+ NULL,
111+ req->callback_data);
112+
113+ g_queue_remove_all (priv->requests, req);
114+ g_free (req);
115+ return;
116+}
117+
118+void
119+free_request (SecretRequest *req)
120+{
121+ g_object_unref (req->connection);
122+ g_free (req);
123+}
124+
125+void
126+unity_settings_secret_agent_cancel_request (UnitySettingsSecretAgent *agent,
127+ guint request)
128+{
129+ GList *iter;
130+ SecretRequest *req;
131+ UnitySettingsSecretAgentPrivate *priv = agent->priv;
132+ GError *error;
133+
134+ iter = g_queue_find_custom (priv->requests,
135+ &request,
136+ (GCompareFunc)secret_request_find);
137+
138+ if (iter == NULL || iter->data == NULL)
139+ {
140+ g_warning ("Secret request with id <%d> was not found", (int)request);
141+ return;
142+ }
143+
144+ req = iter->data;
145+ error = g_error_new (NM_SECRET_AGENT_ERROR,
146+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
147+ "This secret request was canceled by the user.");
148+
149+ req->callback (NM_SECRET_AGENT (agent),
150+ req->connection,
151+ NULL,
152+ error,
153+ req->callback_data);
154+
155+ g_queue_remove_all (priv->requests, req);
156+ free_request (req);
157+ return;
158+}
159+
160+static void
161+delete_secrets (NMSecretAgent *agent,
162+ NMConnection *connection,
163+ const char *connection_path,
164+ NMSecretAgentDeleteSecretsFunc callback,
165+ gpointer callback_data)
166+{
167+ g_debug ("delete secrets");
168+}
169+
170+/* If it returns G_MAXUINT it's considered an error */
171+static guint
172+find_available_id (UnitySettingsSecretAgentPrivate *priv)
173+{
174+ guint i = 0;
175+ guint candidate = 0;
176+
177+ if (g_queue_get_length (priv->requests) == G_MAXUINT)
178+ return G_MAXUINT;
179+
180+ while (i < g_queue_get_length (priv->requests))
181+ {
182+ SecretRequest *req = (SecretRequest*)g_queue_peek_nth (priv->requests, i);
183+
184+ if (req->id == candidate)
185+ {
186+ candidate++;
187+ i = 0;
188+ }
189+ else
190+ {
191+ i++;
192+ }
193+ }
194+
195+ return i;
196+}
197+
198+static void
199+get_secrets (NMSecretAgent *agent,
200+ NMConnection *connection,
201+ const char *connection_path,
202+ const char *setting_name,
203+ const char **hints,
204+ NMSecretAgentGetSecretsFlags flags,
205+ NMSecretAgentGetSecretsFunc callback,
206+ gpointer callback_data)
207+{
208+ guint id;
209+ UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent);
210+ SecretRequest *req = NULL;
211+
212+ if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE)
213+ {
214+ GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
215+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
216+ "No password found for this connection.");
217+ callback (agent, connection, NULL, error, callback_data);
218+ g_error_free (error);
219+ return;
220+ }
221+
222+ id = find_available_id (priv);
223+ if (id == G_MAXUINT)
224+ {
225+ GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
226+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
227+ "Reached maximum number of requests.");
228+ callback (agent, connection, NULL, error, callback_data);
229+ g_error_free (error);
230+ return;
231+ }
232+
233+ /* Adding a request */
234+ req = (SecretRequest*) g_malloc0 (sizeof (SecretRequest));
235+ *req = ((SecretRequest)
236+ { id,
237+ agent,
238+ connection,
239+ connection_path,
240+ setting_name,
241+ hints,
242+ flags,
243+ callback,
244+ callback_data });
245+
246+ g_object_ref (connection);
247+
248+ g_queue_push_tail (priv->requests, req);
249+
250+ g_signal_emit_by_name (agent,
251+ UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
252+ id,
253+ connection,
254+ setting_name,
255+ hints,
256+ flags);
257+}
258+
259+static void
260+save_secrets (NMSecretAgent *agent,
261+ NMConnection *connection,
262+ const char *connection_path,
263+ NMSecretAgentSaveSecretsFunc callback,
264+ gpointer callback_data)
265+{
266+ g_debug ("save secrets");
267+}
268+
269+static void
270+cancel_get_secrets (NMSecretAgent *agent,
271+ const char *connection_path,
272+ const char *setting_name)
273+{
274+ g_debug ("cancel get secrets");
275+}
276+
277+UnitySettingsSecretAgent*
278+unity_settings_secret_agent_construct (GType object_type)
279+{
280+ UnitySettingsSecretAgent * self = NULL;
281+ self = (UnitySettingsSecretAgent*) g_object_new (object_type,
282+ NM_SECRET_AGENT_IDENTIFIER, AGENT_ID,
283+ NULL);
284+ return self;
285+}
286+
287+
288+UnitySettingsSecretAgent*
289+unity_settings_secret_agent_new (void)
290+{
291+ return unity_settings_secret_agent_construct (UNITY_SETTINGS_TYPE_SECRET_AGENT);
292+}
293+
294+static void
295+destroy_pending_request (gpointer data)
296+{
297+ SecretRequest* req = (SecretRequest*)data;
298+ /* Reporting the cancellation of all pending requests */
299+ g_signal_emit_by_name (req->agent,
300+ UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
301+ req->id);
302+
303+ free_request (req);
304+}
305+
306+static void
307+unity_settings_secret_agent_finalize (GObject *agent)
308+{
309+ UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent);
310+
311+ g_queue_free_full (priv->requests, destroy_pending_request);
312+}
313+
314+static void
315+unity_settings_secret_agent_class_init (UnitySettingsSecretAgentClass *klass)
316+{
317+ unity_settings_secret_agent_parent_class = g_type_class_peek_parent (klass);
318+ NMSecretAgentClass *parent_class = NM_SECRET_AGENT_CLASS (klass);
319+ parent_class->get_secrets = get_secrets;
320+ parent_class->save_secrets = save_secrets;
321+ parent_class->delete_secrets = delete_secrets;
322+ parent_class->cancel_get_secrets = cancel_get_secrets;
323+
324+ g_type_class_add_private (klass, sizeof(UnitySettingsSecretAgentPrivate));
325+ G_OBJECT_CLASS (klass)->finalize = unity_settings_secret_agent_finalize;
326+
327+
328+ signals[SECRET_REQUESTED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
329+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
330+ G_SIGNAL_RUN_FIRST,
331+ G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, secret_requested),
332+ NULL, NULL, NULL,
333+ G_TYPE_NONE, 5,
334+ G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT);
335+
336+ signals[REQUEST_CANCELLED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
337+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
338+ G_SIGNAL_RUN_FIRST,
339+ G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, request_cancelled),
340+ NULL, NULL, NULL,
341+ G_TYPE_NONE, 1,
342+ G_TYPE_UINT);
343+}
344+
345+
346+static void
347+unity_settings_secret_agent_instance_init (UnitySettingsSecretAgent *self)
348+{
349+ self->priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (self);
350+ self->priv->requests = g_queue_new ();
351+}
352+
353+GType
354+unity_settings_secret_agent_get_type (void)
355+{
356+ static volatile gsize unity_settings_secret_agent_type_id__volatile = 0;
357+ if (g_once_init_enter (&unity_settings_secret_agent_type_id__volatile))
358+ {
359+ static const GTypeInfo g_define_type_info =
360+ {
361+ sizeof (UnitySettingsSecretAgentClass),
362+ (GBaseInitFunc) NULL,
363+ (GBaseFinalizeFunc) NULL,
364+ (GClassInitFunc) unity_settings_secret_agent_class_init,
365+ (GClassFinalizeFunc) NULL,
366+ NULL,
367+ sizeof (UnitySettingsSecretAgent),
368+ 0,
369+ (GInstanceInitFunc) unity_settings_secret_agent_instance_init,
370+ NULL
371+ };
372+ GType unity_settings_secret_agent_type_id;
373+ unity_settings_secret_agent_type_id = g_type_register_static (NM_TYPE_SECRET_AGENT,
374+ "UnitySettingsSecretAgent",
375+ &g_define_type_info,
376+ 0);
377+ g_once_init_leave (&unity_settings_secret_agent_type_id__volatile,
378+ unity_settings_secret_agent_type_id);
379+ }
380+
381+ return unity_settings_secret_agent_type_id__volatile;
382+}
plugins/Unity/Indicators/Network/secret-agent.hnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 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+ * Authors:
17+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#ifndef __SECRET_AGENT_H__
22+#define __SECRET_AGENT_H__
23+
24+#include <glib.h>
25+#include <glib-object.h>
26+#include <nm-secret-agent.h>
27+
28+/*
29+ * This class is a basic implementation of the NetworkManager SecretAgent base class.
30+ *
31+ * The purpose of this class is to handle credential requests from the network,
32+ * for example, from a WiFi hotspot or a VPN network.
33+ *
34+ * It queues requests objects (SecretRequest) on a GQueue in the private struct
35+ * of the class. And notifies the consumer of the class through the "secret-request"
36+ * and the "request-cancelled" signals with the following callback prototypes:
37+ *
38+ * void (*secret_requested) (UnitySettingsSecretAgent *self,
39+ * guint id,
40+ * NMConnection *connection,
41+ * const char *setting_name,
42+ * const char **hints,
43+ * NMSecretAgentGetSecretsFlags flags,
44+ * gpointer user_data);
45+ *
46+ * void (*request_cancelled) (UnitySettingsSecretAgent *self,
47+ * guint id,
48+ * gpointer user_data);
49+ *
50+ */
51+
52+
53+G_BEGIN_DECLS
54+
55+
56+#define UNITY_SETTINGS_TYPE_SECRET_AGENT (unity_settings_secret_agent_get_type ())
57+#define UNITY_SETTINGS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgent))
58+#define UNITY_SETTINGS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
59+#define UNITY_SETTINGS_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT))
60+#define UNITY_SETTINGS_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT))
61+#define UNITY_SETTINGS_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
62+
63+#define UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED "secret-requested"
64+#define UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED "request-cancelled"
65+
66+typedef struct _UnitySettingsSecretAgent UnitySettingsSecretAgent;
67+typedef struct _UnitySettingsSecretAgentClass UnitySettingsSecretAgentClass;
68+typedef struct _UnitySettingsSecretAgentPrivate UnitySettingsSecretAgentPrivate;
69+
70+struct _UnitySettingsSecretAgent {
71+ NMSecretAgent parent_instance;
72+ UnitySettingsSecretAgentPrivate * priv;
73+};
74+
75+struct _UnitySettingsSecretAgentClass {
76+ NMSecretAgentClass parent_class;
77+
78+ void (*secret_requested) (UnitySettingsSecretAgent *self,
79+ guint id,
80+ NMConnection *connection,
81+ const char *setting_name,
82+ const char **hints,
83+ NMSecretAgentGetSecretsFlags flags);
84+
85+ void (*request_cancelled) (UnitySettingsSecretAgent *self,
86+ guint id);
87+};
88+
89+
90+GType unity_settings_secret_agent_get_type (void) G_GNUC_CONST;
91+UnitySettingsSecretAgent* unity_settings_secret_agent_new (void);
92+UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type);
93+
94+void unity_settings_secret_agent_provide_secret (UnitySettingsSecretAgent *agent,
95+ guint request,
96+ GHashTable *secrets);
97+void unity_settings_secret_agent_cancel_request (UnitySettingsSecretAgent *agent,
98+ guint request);
99+
100+G_END_DECLS
101+
102+#endif
plugins/Unity/Indicators/qml/MenuItemFactory.qml+21
@@ -19,6 +19,7 @@
1919
2020import QtQuick 2.0
2121import Unity.Indicators 0.1 as Indicators
22+import Unity.Indicators.Network 0.1 as ICNetwork
2223
2324Item {
2425 id: menuFactory
@@ -38,6 +39,9 @@ Item {
3839
3940 "com.canonical.unity.slider" : sliderMenu,
4041 "com.canonical.unity.switch" : switchMenu,
42+
43+ "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
44+ "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
4145 }
4246
4347 Component {
@@ -57,6 +61,23 @@ Item {
5761 Component { id: progressMenu; Indicators.ProgressMenuItem {} }
5862 Component { id: standardMenu; Indicators.StandardMenuItem {} }
5963 Component { id: switchMenu; Indicators.SwitchMenuItem {} }
64+ Component {
65+ id: wifiSection;
66+ ICNetwork.WifiSection {
67+ Component.onCompleted: {
68+ model.loadExtendedAttributes(modelIndex, {'x-canonical-busy-action': 'bool'});
69+ }
70+ }
71+ }
72+ Component {
73+ id: accessPoint;
74+ ICNetwork.AccessPoint {
75+ Component.onCompleted: {
76+ model.loadExtendedAttributes(modelIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
77+ 'x-canonical-wifi-ap-is-secure': 'bool'});
78+ }
79+ }
80+ }
6081
6182 function load(modelData) {
6283 if (modelData.type !== undefined) {
plugins/Unity/IndicatorsLegacy/Network/CMakeLists.txt+8−8
@@ -1,26 +1,26 @@
11# export_qmlplugin macro
22include(Plugins)
33
4−project(IndicatorsNetworkQml)
4+project(IndicatorsLegacyNetworkQml)
55
66pkg_check_modules(GLIB glib-2.0>=2.32)
77pkg_check_modules(LIBNM_GLIB libnm-glib>=0.9.6)
88pkg_check_modules(LIBNM_UTIL libnm-util>=0.9.6)
99
1010if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
11− set(INDICATORS_NETWORK_SRC
11+ set(INDICATORS_LEGACY_NETWORK_SRC
1212 networkagent.cpp
1313 plugin.cpp
1414 secret-agent.c
1515 )
1616
17− add_library(IndicatorsNetworkQml MODULE
18− ${INDICATORS_NETWORK_SRC}
17+ add_library(IndicatorsLegacyNetworkQml MODULE
18+ ${INDICATORS_LEGACY_NETWORK_SRC}
1919 )
2020
21− qt5_use_modules(IndicatorsNetworkQml Core Qml Widgets)
21+ qt5_use_modules(IndicatorsLegacyNetworkQml Core Qml Widgets)
2222
23− set_target_properties(IndicatorsNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
23+ set_target_properties(IndicatorsLegacyNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
2424
2525 include_directories(
2626 ${CMAKE_CURRENT_SOURCE_DIR}
@@ -29,14 +29,14 @@ if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
2929 ${LIBNM_UTIL_INCLUDE_DIRS}
3030 )
3131
32− target_link_libraries(IndicatorsNetworkQml
32+ target_link_libraries(IndicatorsLegacyNetworkQml
3333 ${GLIB_LIBRARIES}
3434 ${LIBNM_GLIB_LIBRARIES}
3535 ${LIBNM_UTIL_LIBRARIES}
3636 )
3737
3838 # export the qmltypes and plugin files
39− export_qmlplugin(Unity.IndicatorsLegacy.Network 0.1 Unity/IndicatorsLegacy/Network TARGETS IndicatorsNetworkQml)
39+ export_qmlplugin(Unity.IndicatorsLegacy.Network 0.1 Unity/IndicatorsLegacy/Network TARGETS IndicatorsLegacyNetworkQml)
4040
4141else()
4242 message(WARNING "Missing glib or libnm dependency for the network plugin, not building")
plugins/Unity/IndicatorsLegacy/Network/qml/qmldir+1−1
@@ -1,5 +1,5 @@
11module Unity.IndicatorsLegacy.Network
2−plugin IndicatorsNetworkQml
2+plugin IndicatorsLegacyNetworkQml
33typeinfo plugin.qmltypes
44
55NetworkPage 0.1 NetworkPage.qml
plugins/Unity/IndicatorsLegacy/flatmenuproxymodel.cpp+13
@@ -80,6 +80,19 @@ void FlatMenuProxyModel::setSourceModel(QAbstractItemModel *source)
8080 SIGNAL(modelReset()),
8181 SLOT(onModelReset()), Qt::QueuedConnection);
8282
83+ //Connection args
84+ connect(source,
85+ SIGNAL(busTypeChanged(DBusEnums::BusType)),
86+ SIGNAL(busTypeChanged()));
87+
88+ connect(source,
89+ SIGNAL(busNameChanged(const QString&)),
90+ SIGNAL(busNameChanged()));
91+
92+ connect(source,
93+ SIGNAL(objectPathChanged(const QString&)),
94+ SIGNAL(objectPathChanged()));
95+
8396 connect(source,
8497 SIGNAL(statusChanged(DBusEnums::ConnectionStatus)),
8598 SIGNAL(statusChanged()), Qt::QueuedConnection);
plugins/Unity/filters.cpp+4
@@ -23,6 +23,7 @@
2323
2424// Local
2525#include "filter.h"
26+#include "genericoptionsmodel.h"
2627
2728// Qt
2829#include <QDebug>
@@ -77,6 +78,8 @@ QVariant Filters::data(const QModelIndex& index, int role) const
7778 return filter->collapsed();
7879 case Filters::RoleFiltering:
7980 return filter->filtering();
81+ case Filters::RoleOptions:
82+ return QVariant::fromValue(filter->options());
8083 default:
8184 break;
8285 }
@@ -93,6 +96,7 @@ QHash<int, QByteArray> Filters::roleNames() const
9396 roles[Filters::RoleVisible] = "visible";
9497 roles[Filters::RoleCollapsed] = "collapsed";
9598 roles[Filters::RoleFiltering] = "filtering";
99+ roles[Filters::RoleOptions] = "options";
96100 return roles;
97101}
98102
plugins/Unity/filters.h+2−1
@@ -48,7 +48,8 @@ public:
4848 RoleRendererName,
4949 RoleVisible,
5050 RoleCollapsed,
51− RoleFiltering
51+ RoleFiltering,
52+ RoleOptions
5253 };
5354
5455 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
plugins/Unity/genericoptionsmodel.cpp+18
@@ -76,6 +76,24 @@ int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
7676 return m_options.size ();
7777}
7878
79+void GenericOptionsModel::setActive(QVector<AbstractFilterOption *>::size_type idx, bool value)
80+{
81+ if (idx < m_options.size())
82+ {
83+ m_options[idx]->setActive(value);
84+ }
85+}
86+
87+void GenericOptionsModel::setActive(const QString &id, bool value)
88+{
89+ Q_FOREACH(auto opt, m_options) {
90+ if (opt->id() == id) {
91+ opt->setActive(value);
92+ break;
93+ }
94+ }
95+}
96+
7997AbstractFilterOption* GenericOptionsModel::getRawOption(QVector<AbstractFilterOption *>::size_type idx) const
8098{
8199 if (idx < m_options.size())
plugins/Unity/genericoptionsmodel.h+3
@@ -49,6 +49,9 @@ public:
4949 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
5050 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
5151
52+ Q_INVOKABLE void setActive(QVector<AbstractFilterOption *>::size_type idx, bool value);
53+ Q_INVOKABLE void setActive(const QString &id, bool value);
54+
5255 AbstractFilterOption* getRawOption(QVector<AbstractFilterOption *>::size_type idx) const;
5356
5457public Q_SLOTS:
plugins/Utils/qlimitproxymodelqml.cpp+90−4
@@ -25,6 +25,8 @@ QLimitProxyModelQML::QLimitProxyModelQML(QObject *parent)
2525 , m_limit(-1)
2626 , m_sourceInserting(false)
2727 , m_sourceRemoving(false)
28+ , m_dataChangedBegin(-1)
29+ , m_dataChangedEnd(-1)
2830{
2931 connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
3032 connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
@@ -130,8 +132,45 @@ QLimitProxyModelQML::sourceRowsAboutToBeInserted(const QModelIndex &parent, int
130132 beginInsertRows(mapFromSource(parent), start, end);
131133 m_sourceInserting = true;
132134 } else if (start < m_limit) {
133− beginInsertRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
134− m_sourceInserting = true;
135+ const int nSourceAddedItems = end - start + 1;
136+ const int currentCount = QIdentityProxyModel::rowCount();
137+ if (currentCount + nSourceAddedItems <= m_limit) {
138+ // After Inserting items we will be under the limit
139+ // so just proceed with the insertion normally
140+ beginInsertRows(mapFromSource(parent), start, end);
141+ m_sourceInserting = true;
142+ } else if (currentCount >= m_limit) {
143+ // We are already over the limit so to our users we are not adding items, just
144+ // changing it's data, i.e we had something like
145+ // A B C D E
146+ // with a limit of 5
147+ // after inserting (let's say three 'F' at position 1) we will have
148+ // A F F F B
149+ // so we just need to signal a dataChanged from 1 to 4
150+ m_dataChangedBegin = start;
151+ m_dataChangedEnd = m_limit - 1;
152+ } else { // currentCount < m_limit && currentCount + nSourceAddedItems > m_limit
153+ // We have less items than the limit but after adding them we will be over
154+ // To our users this means we need to insert some items and change the
155+ // data of some others, i.e we had something like
156+ // A B C
157+ // with a limit of 5
158+ // after inserting (let's say three 'F' at position 1) we will have
159+ // A F F F B
160+ // so we need to signal an insetion from position 1 to 2, instead of from
161+ // position 1 to 3 and a after that a data changed from 3 to 4
162+ const int nItemsToInsert = m_limit - currentCount;
163+ beginInsertRows(mapFromSource(parent), start, start + nItemsToInsert - 1);
164+ m_sourceInserting = true;
165+ m_dataChangedBegin = start + nItemsToInsert;
166+ m_dataChangedEnd = m_limit - 1;
167+ if (m_dataChangedBegin > m_dataChangedEnd) {
168+ // Just in case we were empty and insert 6 items with a limit of 5
169+ // We don't want to signal a dataChanged from 5 to 4
170+ m_dataChangedBegin = -1;
171+ m_dataChangedEnd = -1;
172+ }
173+ }
135174 }
136175}
137176
@@ -142,8 +181,45 @@ QLimitProxyModelQML::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int s
142181 beginRemoveRows(mapFromSource(parent), start, end);
143182 m_sourceRemoving = true;
144183 } else if (start < m_limit) {
145− beginRemoveRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
146− m_sourceRemoving = true;
184+ const int nSourceRemovedItems = end - start + 1;
185+ const int currentCount = QIdentityProxyModel::rowCount();
186+ if (currentCount <= m_limit) {
187+ // We are already under the limit so
188+ // so just proceed with the removal normally
189+ beginRemoveRows(mapFromSource(parent), start, end);
190+ m_sourceRemoving = true;
191+ } else if (currentCount - nSourceRemovedItems >= m_limit) {
192+ // Even after removing items we will be at or over the limit
193+ // So to our users we are not removing anything, just changing the data
194+ // i.e. we had a internal model with
195+ // A B C D E F G H
196+ // and a limit of 5, our users just see
197+ // A B C D E
198+ // so if we remove 3 items starting at 1 we have to expose
199+ // A E F G H
200+ // that is, a dataChanged from 1 to 4
201+ m_dataChangedBegin = start;
202+ m_dataChangedEnd = m_limit - 1;
203+ } else { // currentCount > m_limit && currentCount - nSourceRemovedItems < m_limit
204+ // We have more items than the limit but after removing we will be below it
205+ // So to our users we both removing and changing the data
206+ // i.e. we had a internal model with
207+ // A B C D E F G
208+ // and a limit of 5, our users just see
209+ // A B C D E
210+ // so if we remove items from 1 to 3 we have to expose
211+ // A E F G
212+ // that is, a remove from 4 to 4 and a dataChanged from 1 to 3
213+ const int nItemsToRemove = m_limit - (currentCount - nSourceRemovedItems);
214+ beginRemoveRows(mapFromSource(parent), m_limit - nItemsToRemove, m_limit - 1);
215+ m_sourceRemoving = true;
216+ m_dataChangedBegin = start;
217+ m_dataChangedEnd = m_limit - nItemsToRemove - 1;
218+ if (m_dataChangedBegin > m_dataChangedEnd) {
219+ m_dataChangedBegin = -1;
220+ m_dataChangedEnd = -1;
221+ }
222+ }
147223 }
148224}
149225
@@ -154,6 +230,11 @@ QLimitProxyModelQML::sourceRowsInserted(const QModelIndex & /*parent*/, int /*st
154230 endInsertRows();
155231 m_sourceInserting = false;
156232 }
233+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
234+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
235+ m_dataChangedBegin = -1;
236+ m_dataChangedEnd = -1;
237+ }
157238}
158239
159240void
@@ -163,4 +244,9 @@ QLimitProxyModelQML::sourceRowsRemoved(const QModelIndex & /*parent*/, int /*sta
163244 endRemoveRows();
164245 m_sourceRemoving = false;
165246 }
247+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
248+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
249+ m_dataChangedBegin = -1;
250+ m_dataChangedEnd = -1;
251+ }
166252}
plugins/Utils/qlimitproxymodelqml.h+2
@@ -55,6 +55,8 @@ private:
5555 int m_limit;
5656 bool m_sourceInserting;
5757 bool m_sourceRemoving;
58+ int m_dataChangedBegin;
59+ int m_dataChangedEnd;
5860};
5961
6062#endif // QLIMITPROXYMODELQML_H
src/Panel/Indicators/servicefiles/CMakeLists.txt−1
@@ -1,6 +1,5 @@
11file(GLOB INDICATOR_SERVICE_FILES
22 ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.indicator.messages
3− ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.settings.network
43)
54
65# copy indicators files into build directory for shadow builds
src/Panel/Indicators/servicefiles/com.canonical.indicator.messages+1−1
@@ -1,5 +1,5 @@
11[Indicator Service]
2−Name=indicator-messaging
2+Name=indicator-messages
33ObjectPath=/com/canonical/indicator/messages
44Position=50
55
src/Panel/Indicators/servicefiles/com.canonical.settings.networkdeleted−10
@@ -1,10 +0,0 @@
1−[Indicator Service]
2−Name=chewie-network
3−ObjectPath=/com/canonical/settings/network
4−Position=69
5−
6−[phone]
7−ObjectPath=/com/canonical/settings/network/phone
8−
9−[desktop]
10−ObjectPath=/com/canonical/settings/network/desktop
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+2−2
@@ -31,8 +31,8 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
3131 m_pinned(false),
3232 m_running(false),
3333 m_recent(false),
34− m_progress(8),
35− m_count(8),
34+ m_progress(-1),
35+ m_count(0),
3636 m_quickList(new MockQuickListModel(this))
3737{
3838
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+31−1
@@ -23,22 +23,32 @@
2323MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(parent)
2424{
2525 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
26+ item->setProgress(0);
2627 m_list.append(item);
2728 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
29+ item->setProgress(10);
2830 m_list.append(item);
2931 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
32+ item->setProgress(50);
3033 m_list.append(item);
3134 item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
35+ item->setProgress(150);
3236 m_list.append(item);
3337 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
38+ item->setCount(1);
3439 m_list.append(item);
3540 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
41+ item->setCount(12);
3642 m_list.append(item);
3743 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
44+ item->setCount(123);
3845 m_list.append(item);
3946 item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
47+ item->setCount(1234567890);
4048 m_list.append(item);
4149 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
50+ item->setProgress(50);
51+ item->setCount(5);
4252 m_list.append(item);
4353 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
4454 m_list.append(item);
@@ -91,9 +101,29 @@ unity::shell::launcher::LauncherItemInterface *MockLauncherModel::get(int index)
91101
92102void MockLauncherModel::move(int oldIndex, int newIndex)
93103{
94− beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex);
104+ // Make sure its not moved outside the lists
105+ if (newIndex < 0) {
106+ newIndex = 0;
107+ }
108+ if (newIndex >= m_list.count()) {
109+ newIndex = m_list.count()-1;
110+ }
111+
112+ // Nothing to do?
113+ if (oldIndex == newIndex) {
114+ return;
115+ }
116+
117+ // QList's and QAbstractItemModel's move implementation differ when moving an item up the list :/
118+ // While QList needs the index in the resulting list, beginMoveRows expects it to be in the current list
119+ // adjust the model's index by +1 in case we're moving upwards
120+ int newModelIndex = newIndex > oldIndex ? newIndex+1 : newIndex;
121+
122+ beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newModelIndex);
95123 m_list.move(oldIndex, newIndex);
96124 endMoveRows();
125+
126+ pin(m_list.at(newIndex)->appId());
97127}
98128
99129void MockLauncherModel::pin(const QString &appId, int index)
tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8
@@ -58,10 +58,17 @@ public:
5858 m_roles = roles;
5959 }
6060
61+ void clear()
62+ {
63+ beginRemoveRows(QModelIndex(), 0, m_list.count() - 1);
64+ m_list.clear();
65+ endRemoveRows();
66+ }
67+
6168 bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
6269 beginInsertRows(parent, row, row+count-1);
6370 for (int i=0; i<count; i++) {
64− m_list.insert(i+row, "test"+i);
71+ m_list.insert(i+row, QString::number(i));
6572 }
6673 endInsertRows();
6774 return true;
@@ -88,6 +95,60 @@ private:
8895 QHash<int, QByteArray> m_roles;
8996};
9097
98+class MirrorModel : public QObject
99+{
100+ Q_OBJECT
101+
102+public:
103+ MirrorModel(QAbstractItemModel *model) : m_mirror(model)
104+ {
105+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
106+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
107+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
108+ }
109+
110+ void check()
111+ {
112+ QCOMPARE(m_list.count(), m_mirror->rowCount());
113+ for (int i = 0; i < m_list.count(); ++i) {
114+ QCOMPARE(m_list[i], m_mirror->data(m_mirror->index(i, 0)).toString());
115+ }
116+ }
117+
118+private Q_SLOTS:
119+ void rowsInserted(const QModelIndex &parent, int start, int end)
120+ {
121+ QVERIFY(!parent.isValid());
122+ for (int i = start; i <= end; ++i) {
123+ m_list.insert(i, m_mirror->data(m_mirror->index(i, 0)).toString());
124+ }
125+ }
126+
127+ void rowsRemoved(const QModelIndex &parent, int start, int end)
128+ {
129+ QVERIFY(!parent.isValid());
130+ for (int i = end; i >= start; --i) {
131+ m_list.removeAt(i);
132+ }
133+ }
134+
135+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
136+ {
137+ QVERIFY(topLeft.isValid());
138+ QVERIFY(bottomRight.isValid());
139+ QVERIFY(!topLeft.parent().isValid());
140+ QVERIFY(!bottomRight.parent().isValid());
141+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
142+ m_list[i] = m_mirror->data(m_mirror->index(i, 0)).toString();
143+ }
144+ }
145+
146+
147+private:
148+ QStringList m_list;
149+ QAbstractItemModel *m_mirror;
150+};
151+
91152class QLimitProxyModelTest : public QObject
92153{
93154 Q_OBJECT
@@ -401,15 +462,10 @@ private Q_SLOTS:
401462 QCOMPARE(spyOnCountChanged.count(), 0);
402463
403464 model.removeRows(2, 2);
404− QCOMPARE(spyOnRowsRemoved.count(), 1);
465+ QCOMPARE(spyOnRowsRemoved.count(), 0);
405466 QCOMPARE(spyOnRowsInserted.count(), 0);
406− QCOMPARE(spyOnCountChanged.count(), 1);
407− arguments = spyOnRowsRemoved.takeFirst();
408− QCOMPARE(arguments.at(1).toInt(), 2);
409− QCOMPARE(arguments.at(2).toInt(), 3);
467+ QCOMPARE(spyOnCountChanged.count(), 0);
410468 QCOMPARE(proxy.rowCount(), 7);
411− spyOnRowsInserted.clear();
412− spyOnCountChanged.clear();
413469
414470 model.removeRows(0, 7);
415471 QCOMPARE(spyOnRowsRemoved.count(), 1);
@@ -479,6 +535,75 @@ private Q_SLOTS:
479535 QCOMPARE(proxy.rowCount(), 5);
480536 QCOMPARE(spyOnCountChanged.count(), 1);
481537 }
538+
539+ void testMirrorModel() {
540+ QLimitProxyModelQML proxy;
541+ MockListModel model;
542+ MirrorModel mirror(&proxy);
543+
544+ proxy.setModel(&model);
545+ proxy.setLimit(5);
546+
547+ // Checks what happens when the model already has
548+ // more items than the limit and we add stuff to
549+ // the front
550+ model.insertRows(0, 7);
551+ mirror.check();
552+ model.insertRows(1, 3);
553+ mirror.check();
554+ model.clear();
555+ mirror.check();
556+
557+ // Checks what happens when the model does
558+ // not has more items than limit but adding
559+ // stuff to its front makes it go past the limit
560+ model.insertRows(0, 3);
561+ mirror.check();
562+ model.insertRows(1, 3);
563+ mirror.check();
564+ model.clear();
565+ mirror.check();
566+
567+ // Checks what happens when the model does
568+ // not has more items than limit and adding
569+ // stuff to its front makes it not go past the limit
570+ model.insertRows(0, 1);
571+ mirror.check();
572+ model.insertRows(1, 3);
573+ mirror.check();
574+ model.clear();
575+ mirror.check();
576+
577+ // Checks what happens when the model already has
578+ // more items than the limit and we remove stuff from
579+ // the front but it still has more than the limit
580+ model.insertRows(0, 10);
581+ mirror.check();
582+ model.removeRows(1, 3);
583+ mirror.check();
584+ model.clear();
585+ mirror.check();
586+
587+ // Checks what happens when the model already has
588+ // more items than the limit and we remove stuff from
589+ // the front but it has less than the limit
590+ model.insertRows(0, 6);
591+ mirror.check();
592+ model.removeRows(1, 3);
593+ mirror.check();
594+ model.clear();
595+ mirror.check();
596+
597+ // Checks what happens when the model has
598+ // less items than the limit and we remove stuff from
599+ // the front
600+ model.insertRows(0, 4);
601+ mirror.check();
602+ model.removeRows(1, 3);
603+ mirror.check();
604+ model.clear();
605+ mirror.check();
606+ }
482607};
483608
484609QTEST_GUILESS_MAIN(QLimitProxyModelTest)
tests/qmltests/Greeter/tst_Clock.qml+1−1
@@ -70,7 +70,7 @@ Rectangle {
7070 compare(clock.__timerRunning, true, "Timer should be running")
7171 wait(0) // spin event loop to trigger the timer
7272 verify(dateLabel.text !== dateString)
73− if (timeLabel.text == "11:13") wait(60000) // next test will fail at 11:13, wait 1 minute
73+ if (timeLabel.text.indexOf("11:13") != -1) wait(60000) // next test will fail at 11:13, wait 1 minute
7474 verify(timeLabel.text !== timeString)
7575 }
7676
tests/qmltests/Launcher/tst_Launcher.qml+16
@@ -182,6 +182,22 @@ Item {
182182 revealer.waitUntilLauncherDisappears();
183183 launcher.available = true;
184184 }
185+
186+ function test_countEmblems() {
187+ var launcherListView = findChild(launcher, "launcherListView");
188+ for (var i = 0; i < launcherListView.count; ++i) {
189+ var delegate = findChild(launcherListView, "launcherDelegate" + i)
190+ compare(findChild(delegate, "countEmblem").visible, LauncherModel.get(i).count > 0)
191+ }
192+ }
193+
194+ function test_progressOverlays() {
195+ var launcherListView = findChild(launcher, "launcherListView");
196+ for (var i = 0; i < launcherListView.count; ++i) {
197+ var delegate = findChild(launcherListView, "launcherDelegate" + i)
198+ compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
199+ }
200+ }
185201 }
186202
187203 UT.UnityTestCase {